format
This commit is contained in:
@@ -1,110 +1,110 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"><title>接口文档(apidoc生成)</title>
|
||||
<style type="text/css">
|
||||
body {text-align: center;margin:auto;}
|
||||
a{text-decoration: none;}
|
||||
.table {margin: auto;border-collapse: collapse;border-spacing: 0;display: block;width: 100%;overflow: auto;word-break: normal;word-break: keep-all;}
|
||||
.table td,.table th{padding: 0.2rem 0.8rem 0.2rem 0.8rem;border: 1px solid #aaa;}
|
||||
.table td {text-align: left;}
|
||||
.s {font-size: 0.8rem; vertical-align: middle;}
|
||||
.subtable {border-spacing: 0;border: 0;margin:0;}
|
||||
.subtable td{border: 0;padding: 0 0 0 10px;}
|
||||
.typetable {border-spacing: 0;border: 0;margin:0;}
|
||||
.typetable td{border: 0;padding: 2px 20px 2px 10px;}
|
||||
.typetable .l{border-bottom: 1px solid red;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<head>
|
||||
<meta charset="UTF-8"><title>接口文档(apidoc生成)</title>
|
||||
<style type="text/css">
|
||||
body {text-align: center;margin:auto;}
|
||||
a{text-decoration: none;}
|
||||
.table {margin: auto;border-collapse: collapse;border-spacing: 0;display: block;width: 100%;overflow: auto;word-break: normal;word-break: keep-all;}
|
||||
.table td,.table th{padding: 0.2rem 0.8rem 0.2rem 0.8rem;border: 1px solid #aaa;}
|
||||
.table td {text-align: left;}
|
||||
.s {font-size: 0.8rem; vertical-align: middle;}
|
||||
.subtable {border-spacing: 0;border: 0;margin:0;}
|
||||
.subtable td{border: 0;padding: 0 0 0 10px;}
|
||||
.typetable {border-spacing: 0;border: 0;margin:0;}
|
||||
.typetable td{border: 0;padding: 2px 20px 2px 10px;}
|
||||
.typetable .l{border-bottom: 1px solid red;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
var createhtml = function (jsoncontent) {
|
||||
var classmap = jsoncontent.types;
|
||||
var html = [];
|
||||
html.push('<div style="width:' + Math.floor(window.screen.width * 0.9) + 'px;margin:0 auto;text-align: center;">');
|
||||
html.push('<br/><br/><table class="table" align="center">');
|
||||
for (var i = 0; i < jsoncontent.servers.length; i++) {
|
||||
var servlets = jsoncontent.servers[i].servlets;
|
||||
if (servlets.length && (servlets[0].comment || "").indexOf("【") === 0) {
|
||||
servlets.sort(function (a, b) {
|
||||
return a.comment > b.comment ? -1 : (a.comment == b.comment ? 0 : 1);
|
||||
});
|
||||
}
|
||||
for (var j = 0; j < servlets.length; j++) {
|
||||
var servlet = servlets[j];
|
||||
if (html.length > 2) html.push(' <tr><th colspan="5" style="border-bottom:0;"> </th></tr>');
|
||||
html.push(' <tr><th colspan="5" style="border-top:' + ((html.length > 2) ? 0 : 1) + ';">' + (servlet.comment || '未知模块') + '</th></tr>');
|
||||
html.push(' <tr><th>请求URL</th><th>描 述</th><th>鉴 权</th><th>参 数 <span style="font-size:12px;">(粗体: 必填项; 红色: Header; 蓝色: Cookie)</span></th><th>输 出</th></tr>');
|
||||
for (var k = 0; k < servlet.mappings.length; k++) {
|
||||
var action = servlet.mappings[k];
|
||||
html.push(' <tr>');
|
||||
html.push('<td style="color:#ff00ff;">' + action.url + '</td>');
|
||||
html.push('<td>' + action.comment + '</td>');
|
||||
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 = [];
|
||||
paramshtml.push('<table class="subtable">');
|
||||
for (var p = 0; p < action.params.length; p++) {
|
||||
var param = action.params[p];
|
||||
var t = param.type.substring(param.type.lastIndexOf('.') + 1);
|
||||
if (classmap[param.type.replace('[]', '')]) {
|
||||
t = '<a href="#' + param.type.replace('[]', '') + '">' + t + '</a>';
|
||||
}
|
||||
if (param.name == '&') {
|
||||
paramshtml.push('<tr><td style="font-size:12px;">内置 </td><td> ' + t + '</td><td> 当前用户</td></tr>');
|
||||
} else {
|
||||
var w = param.required ? "font-weight:bold;" : "";
|
||||
var c = ' style="' + w + '"';
|
||||
if (param.style == "HEADER") c = ' style="color:red;' + 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('</table>');
|
||||
html.push('<td class="s" style="padding:0 5px;">' + paramshtml.join('') + '</td>');
|
||||
var rs = [];
|
||||
rs.push(action.result.replace(/</g, "<").replace(/>/g, ">").replace(/([a-zA-Z0-9_\$]+\.)+/g, ""));
|
||||
var results = action.results || [];
|
||||
for (var r = 0; r < results.length; r++) {
|
||||
rs.push('<a href="#' + results[r].replace('[]', '') + '">' + results[r].replace(/([a-zA-Z0-9_\$]+\.)+/g, "") + '</a>');
|
||||
}
|
||||
html.push('<td>' + rs.join("<br/>") + '</td>');
|
||||
html.push('</tr>');
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var type in classmap) {
|
||||
html.push(' <tr><th colspan="5" style="border-bottom:0;"> </th></tr>');
|
||||
html.push(' <tr id="' + type + '"><th colspan="5" style="border-top:0;">' + type + '</th></tr>');
|
||||
html.push(' <tr><td colspan="5"><table class="typetable">');
|
||||
for (var fieldname in classmap[type]) {
|
||||
var field = classmap[type][fieldname];
|
||||
var t = field.type.replace(/</g, "<").replace(/>/g, ">").replace(/\$/g, ".").replace(/([a-zA-Z0-9_\$]+\.)+/g, "");
|
||||
if (t == 'boolean' || t == 'short' || t == 'int' || t == 'long' || t == 'float' || t == 'double'
|
||||
|| t == 'boolean[]' || t == 'short[]' || t == 'int[]' || t == 'long[]' || t == 'float[]' || t == 'double[]') {
|
||||
t = '<font color=blue>' + t + '</font>';
|
||||
} else if (t == 'String' || t == 'String[]' || t == 'LongRange' || t.indexOf('Map<') === 0) {
|
||||
t = '<font color=red>' + t + '</font>';
|
||||
}
|
||||
var c = (field.comment || '');
|
||||
if (field.primary) {
|
||||
c = '【主键】 ' + c;
|
||||
} else if (!field.updatable) {
|
||||
c = '【只读】 ' + c;
|
||||
}
|
||||
html.push(' <tr class="l"><td>' + fieldname + '</td><td>' + t + '</td><td colspan="2">' + c + '</td></tr>');
|
||||
}
|
||||
html.push(' </table></td></tr>');
|
||||
}
|
||||
html.push('</table><br/><br/><br/>');
|
||||
html.push('</div>');
|
||||
return html.join('');
|
||||
};
|
||||
</script>
|
||||
<script>
|
||||
var createhtml = function (jsoncontent) {
|
||||
var classmap = jsoncontent.types;
|
||||
var html = [];
|
||||
html.push('<div style="width:' + Math.floor(window.screen.width * 0.9) + 'px;margin:0 auto;text-align: center;">');
|
||||
html.push('<br/><br/><table class="table" align="center">');
|
||||
for (var i = 0; i < jsoncontent.servers.length; i++) {
|
||||
var servlets = jsoncontent.servers[i].servlets;
|
||||
if (servlets.length && (servlets[0].comment || "").indexOf("【") === 0) {
|
||||
servlets.sort(function (a, b) {
|
||||
return a.comment > b.comment ? -1 : (a.comment == b.comment ? 0 : 1);
|
||||
});
|
||||
}
|
||||
for (var j = 0; j < servlets.length; j++) {
|
||||
var servlet = servlets[j];
|
||||
if (html.length > 2) html.push(' <tr><th colspan="5" style="border-bottom:0;"> </th></tr>');
|
||||
html.push(' <tr><th colspan="5" style="border-top:' + ((html.length > 2) ? 0 : 1) + ';">' + (servlet.comment || '未知模块') + '</th></tr>');
|
||||
html.push(' <tr><th>请求URL</th><th>描 述</th><th>鉴 权</th><th>参 数 <span style="font-size:12px;">(粗体: 必填项; 红色: Header; 蓝色: Cookie)</span></th><th>输 出</th></tr>');
|
||||
for (var k = 0; k < servlet.mappings.length; k++) {
|
||||
var action = servlet.mappings[k];
|
||||
html.push(' <tr>');
|
||||
html.push('<td style="color:#ff00ff;">' + action.url + '</td>');
|
||||
html.push('<td>' + action.comment + '</td>');
|
||||
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 = [];
|
||||
paramshtml.push('<table class="subtable">');
|
||||
for (var p = 0; p < action.params.length; p++) {
|
||||
var param = action.params[p];
|
||||
var t = param.type.substring(param.type.lastIndexOf('.') + 1);
|
||||
if (classmap[param.type.replace('[]', '')]) {
|
||||
t = '<a href="#' + param.type.replace('[]', '') + '">' + t + '</a>';
|
||||
}
|
||||
if (param.name == '&') {
|
||||
paramshtml.push('<tr><td style="font-size:12px;">内置 </td><td> ' + t + '</td><td> 当前用户</td></tr>');
|
||||
} else {
|
||||
var w = param.required ? "font-weight:bold;" : "";
|
||||
var c = ' style="' + w + '"';
|
||||
if (param.style == "HEADER") c = ' style="color:red;' + 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('</table>');
|
||||
html.push('<td class="s" style="padding:0 5px;">' + paramshtml.join('') + '</td>');
|
||||
var rs = [];
|
||||
rs.push(action.result.replace(/</g, "<").replace(/>/g, ">").replace(/([a-zA-Z0-9_\$]+\.)+/g, ""));
|
||||
var results = action.results || [];
|
||||
for (var r = 0; r < results.length; r++) {
|
||||
rs.push('<a href="#' + results[r].replace('[]', '') + '">' + results[r].replace(/([a-zA-Z0-9_\$]+\.)+/g, "") + '</a>');
|
||||
}
|
||||
html.push('<td>' + rs.join("<br/>") + '</td>');
|
||||
html.push('</tr>');
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var type in classmap) {
|
||||
html.push(' <tr><th colspan="5" style="border-bottom:0;"> </th></tr>');
|
||||
html.push(' <tr id="' + type + '"><th colspan="5" style="border-top:0;">' + type + '</th></tr>');
|
||||
html.push(' <tr><td colspan="5"><table class="typetable">');
|
||||
for (var fieldname in classmap[type]) {
|
||||
var field = classmap[type][fieldname];
|
||||
var t = field.type.replace(/</g, "<").replace(/>/g, ">").replace(/\$/g, ".").replace(/([a-zA-Z0-9_\$]+\.)+/g, "");
|
||||
if (t == 'boolean' || t == 'short' || t == 'int' || t == 'long' || t == 'float' || t == 'double'
|
||||
|| t == 'boolean[]' || t == 'short[]' || t == 'int[]' || t == 'long[]' || t == 'float[]' || t == 'double[]') {
|
||||
t = '<font color=blue>' + t + '</font>';
|
||||
} else if (t == 'String' || t == 'String[]' || t == 'LongRange' || t.indexOf('Map<') === 0) {
|
||||
t = '<font color=red>' + t + '</font>';
|
||||
}
|
||||
var c = (field.comment || '');
|
||||
if (field.primary) {
|
||||
c = '【主键】 ' + c;
|
||||
} else if (!field.updatable) {
|
||||
c = '【只读】 ' + c;
|
||||
}
|
||||
html.push(' <tr class="l"><td>' + fieldname + '</td><td>' + t + '</td><td colspan="2">' + c + '</td></tr>');
|
||||
}
|
||||
html.push(' </table></td></tr>');
|
||||
}
|
||||
html.push('</table><br/><br/><br/>');
|
||||
html.push('</div>');
|
||||
return html.join('');
|
||||
};
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var jsoncontent = '#{content}'; //这里必须要用单引号引起来
|
||||
document.write(createhtml(jsoncontent));
|
||||
</script>
|
||||
</body>
|
||||
<script>
|
||||
var jsoncontent = '#{content}'; //这里必须要用单引号引起来
|
||||
document.write(createhtml(jsoncontent));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -13,11 +13,11 @@ redkale.cluster.waits= = false
|
||||
redkale.cluster.protocols = SNCP
|
||||
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].servers.value = 127.0.0.1:9101
|
||||
|
||||
redkale.group[0].name =
|
||||
redkale.group[0].name =
|
||||
redkale.group[0].protocol = TCP
|
||||
redkale.group[0].node[0].addr = 127.0.0.1
|
||||
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].port = 6060
|
||||
redkale.server[0].root = root
|
||||
redkale.server[0].lib =
|
||||
redkale.server[0].lib =
|
||||
|
||||
#\u3010ssl\u8282\u70b9\u5728<server>\u4e2d\u552f\u4e00\u3011
|
||||
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
|
||||
|
||||
@@ -1,366 +1,366 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
文件说明:
|
||||
${APP_HOME} 指当前程序的根目录APP_HOME
|
||||
没注明唯一的节点可多个存在
|
||||
required: 被声明required的属性值不能为空
|
||||
|
||||
group
|
||||
/ / \ \
|
||||
/ / \ \
|
||||
/ / \ \
|
||||
node1 node2 node3 node4
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
serviceid1 serviceid2
|
||||
/ \ / \
|
||||
serviceid1_name1 serviceid1_name2 serviceid2_name1 serviceid2_name2
|
||||
<!--
|
||||
文件说明:
|
||||
${APP_HOME} 指当前程序的根目录APP_HOME
|
||||
没注明唯一的节点可多个存在
|
||||
required: 被声明required的属性值不能为空
|
||||
|
||||
group
|
||||
/ / \ \
|
||||
/ / \ \
|
||||
/ / \ \
|
||||
node1 node2 node3 node4
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
serviceid1 serviceid2
|
||||
/ \ / \
|
||||
serviceid1_name1 serviceid1_name2 serviceid2_name1 serviceid2_name2
|
||||
-->
|
||||
<!--
|
||||
nodeid: int 进程的节点ID,用于分布式环境,一个系统中节点ID必须全局唯一,使用cluster时框架会进行唯一性校验
|
||||
name: 进程的名称,用于监控识别,命名规则: 字母、数字、下划线、短横、点
|
||||
address: 本地局域网的IP地址, 默认值为默认网卡的ip,当不使用默认值需要指定值,如192.168.1.22
|
||||
port: required 程序的管理Server的端口,用于关闭或者与监管系统进行数据交互
|
||||
lib: 加上额外的lib路径,多个路径用分号;隔开; 默认为空。 例如: ${APP_HOME}/lib/a.jar;${APP_HOME}/lib2/b.jar;
|
||||
<!--
|
||||
nodeid: int 进程的节点ID,用于分布式环境,一个系统中节点ID必须全局唯一,使用cluster时框架会进行唯一性校验
|
||||
name: 进程的名称,用于监控识别,命名规则: 字母、数字、下划线、短横、点
|
||||
address: 本地局域网的IP地址, 默认值为默认网卡的ip,当不使用默认值需要指定值,如192.168.1.22
|
||||
port: required 程序的管理Server的端口,用于关闭或者与监管系统进行数据交互
|
||||
lib: 加上额外的lib路径,多个路径用分号;隔开; 默认为空。 例如: ${APP_HOME}/lib/a.jar;${APP_HOME}/lib2/b.jar;
|
||||
-->
|
||||
<application nodeid="1000" port="6560" lib="">
|
||||
|
||||
<!--
|
||||
【节点全局唯一】 @since 2.3.0
|
||||
全局Serivce执行的线程池, Application.workExecutor, 没配置该节点将自动创建一个。
|
||||
threads: 线程数,默认值: CPU核数*10, 核数=2的情况下默认值为20。值为0表示不启用workExecutor,都在IO线程中运行。
|
||||
clients: client回调函数运行的线程池大小, 默认值: CPU核数*4
|
||||
-->
|
||||
<executor threads="4"/>
|
||||
<application nodeid="1000" port="6560" lib="">
|
||||
|
||||
<!--
|
||||
【节点全局唯一】 @since 2.8.0
|
||||
全局Serivce的定时任务设置,没配置该节点将自动创建一个。
|
||||
enabled: 是否开启缓存功能。默认: true
|
||||
-->
|
||||
<schedule enabled="true"/>
|
||||
|
||||
<!--
|
||||
【节点全局唯一】 @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" />
|
||||
<!--
|
||||
【节点全局唯一】 @since 2.3.0
|
||||
全局Serivce执行的线程池, Application.workExecutor, 没配置该节点将自动创建一个。
|
||||
threads: 线程数,默认值: CPU核数*10, 核数=2的情况下默认值为20。值为0表示不启用workExecutor,都在IO线程中运行。
|
||||
clients: client回调函数运行的线程池大小, 默认值: CPU核数*4
|
||||
-->
|
||||
<executor threads="4"/>
|
||||
|
||||
<!--
|
||||
MQ管理接口配置
|
||||
不同MQ节点所配置的MQ集群不能重复。
|
||||
MQ跟着协议走,所以mq的属性值需要被赋值在rest节点上, 由于SncpServlet是自动生成的,故SNCP协议下,mq属性值被赋值在service/services节点上
|
||||
name: 服务的名称,用于监控识别,多个mq节点时只能有一个name为空的节点,mq.name不能重复,命名规则: 字母、数字、下划线
|
||||
type: 实现类名,必须是org.redkale.mq.MessageAgent的子类
|
||||
threads:线程数,为0表示使用workExecutor。默认: CPU核数, 核数=1的情况下默认值为2,JDK 21以上版本默认使用虚拟线程池
|
||||
rpcfirst:cluster和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>
|
||||
<!--
|
||||
【节点全局唯一】 @since 2.8.0
|
||||
全局Serivce的定时任务设置,没配置该节点将自动创建一个。
|
||||
enabled: 是否开启缓存功能。默认: true
|
||||
-->
|
||||
<schedule enabled="true"/>
|
||||
|
||||
<!--
|
||||
Application启动的监听事件,可配置多个节点
|
||||
value: 类名,必须是ApplicationListener的子类
|
||||
-->
|
||||
<listener value="org.redkalex.xxx.XXXApplicationListener"/>
|
||||
|
||||
<!--
|
||||
【节点全局唯一】
|
||||
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class
|
||||
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。
|
||||
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
|
||||
先加载子节点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="">
|
||||
<!--
|
||||
【节点全局唯一】 @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管理接口配置
|
||||
不同MQ节点所配置的MQ集群不能重复。
|
||||
MQ跟着协议走,所以mq的属性值需要被赋值在rest节点上, 由于SncpServlet是自动生成的,故SNCP协议下,mq属性值被赋值在service/services节点上
|
||||
name: 服务的名称,用于监控识别,多个mq节点时只能有一个name为空的节点,mq.name不能重复,命名规则: 字母、数字、下划线
|
||||
type: 实现类名,必须是org.redkale.mq.MessageAgent的子类
|
||||
threads:线程数,为0表示使用workExecutor。默认: CPU核数, 核数=1的情况下默认值为2,JDK 21以上版本默认使用虚拟线程池
|
||||
rpcfirst:cluster和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启动的监听事件,可配置多个节点
|
||||
value: 类名,必须是ApplicationListener的子类
|
||||
-->
|
||||
<listener value="org.redkalex.xxx.XXXApplicationListener"/>
|
||||
|
||||
<!--
|
||||
【节点全局唯一】
|
||||
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class
|
||||
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。
|
||||
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
|
||||
先加载子节点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>
|
||||
|
||||
@@ -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 = ${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
|
||||
java.util.logging.FileHandler.denyregx =
|
||||
java.util.logging.FileHandler.denyregx =
|
||||
java.util.logging.FileHandler.append = true
|
||||
|
||||
#java.util.logging.ConsoleHandler.level = FINE
|
||||
|
||||
@@ -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.user = root
|
||||
redkale.datasource.platf.write.password = 12345678
|
||||
redkale.datasource.platf.write.password = 12345678
|
||||
|
||||
@@ -30,10 +30,10 @@ import java.lang.annotation.*;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Priority {
|
||||
|
||||
/**
|
||||
* 优先级值
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int value();
|
||||
/**
|
||||
* 优先级值
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int value();
|
||||
}
|
||||
|
||||
@@ -17,67 +17,67 @@ import java.lang.annotation.*;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Resource {
|
||||
|
||||
// /**
|
||||
// * AuthenticationType
|
||||
// */
|
||||
// @Deprecated
|
||||
// public enum AuthenticationType {
|
||||
// /**
|
||||
// * @deprecated
|
||||
// */
|
||||
// CONTAINER,
|
||||
// /**
|
||||
// * @deprecated
|
||||
// */
|
||||
// APPLICATION
|
||||
// }
|
||||
//
|
||||
/**
|
||||
* 资源名称
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String name() default "";
|
||||
// /**
|
||||
// * AuthenticationType
|
||||
// */
|
||||
// @Deprecated
|
||||
// public enum AuthenticationType {
|
||||
// /**
|
||||
// * @deprecated
|
||||
// */
|
||||
// CONTAINER,
|
||||
// /**
|
||||
// * @deprecated
|
||||
// */
|
||||
// APPLICATION
|
||||
// }
|
||||
//
|
||||
/**
|
||||
* 资源名称
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String name() default "";
|
||||
|
||||
/**
|
||||
* 依赖注入的类型
|
||||
*
|
||||
* @return Class
|
||||
*/
|
||||
public Class<?> type() default Object.class;
|
||||
//
|
||||
// /**
|
||||
// *
|
||||
// * @return AuthenticationType
|
||||
// */
|
||||
// @Deprecated
|
||||
// public AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
|
||||
//
|
||||
// /**
|
||||
// *
|
||||
// * @return boolean
|
||||
// */
|
||||
// @Deprecated
|
||||
// public boolean shareable() default true;
|
||||
//
|
||||
// /**
|
||||
// *
|
||||
// * @return String
|
||||
// */
|
||||
// @Deprecated
|
||||
// public String description() default "";
|
||||
//
|
||||
// /**
|
||||
// *
|
||||
// * @return String
|
||||
// */
|
||||
// @Deprecated
|
||||
// public String mappedName() default "";
|
||||
//
|
||||
// /**
|
||||
// *
|
||||
// * @return String
|
||||
// */
|
||||
// @Deprecated
|
||||
// public String lookup() default "";
|
||||
/**
|
||||
* 依赖注入的类型
|
||||
*
|
||||
* @return Class
|
||||
*/
|
||||
public Class<?> type() default Object.class;
|
||||
//
|
||||
// /**
|
||||
// *
|
||||
// * @return AuthenticationType
|
||||
// */
|
||||
// @Deprecated
|
||||
// public AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
|
||||
//
|
||||
// /**
|
||||
// *
|
||||
// * @return boolean
|
||||
// */
|
||||
// @Deprecated
|
||||
// public boolean shareable() default true;
|
||||
//
|
||||
// /**
|
||||
// *
|
||||
// * @return String
|
||||
// */
|
||||
// @Deprecated
|
||||
// public String description() default "";
|
||||
//
|
||||
// /**
|
||||
// *
|
||||
// * @return String
|
||||
// */
|
||||
// @Deprecated
|
||||
// public String mappedName() default "";
|
||||
//
|
||||
// /**
|
||||
// *
|
||||
// * @return String
|
||||
// */
|
||||
// @Deprecated
|
||||
// public String lookup() default "";
|
||||
}
|
||||
|
||||
@@ -35,24 +35,24 @@ import java.lang.annotation.*;
|
||||
@Retention(RUNTIME)
|
||||
public @interface Cacheable {
|
||||
|
||||
/**
|
||||
* (Optional) Whether or not the entity should be cached.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
boolean value() default true;
|
||||
/**
|
||||
* (Optional) Whether or not the entity should be cached.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
boolean value() default true;
|
||||
|
||||
/**
|
||||
* (Optional) 定时自动更新缓存的周期秒数,为0表示不做定时更新, 大于0表示每经过interval秒后会自动从数据库中拉取数据更新Cache
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int interval() default 0;
|
||||
/**
|
||||
* (Optional) 定时自动更新缓存的周期秒数,为0表示不做定时更新, 大于0表示每经过interval秒后会自动从数据库中拉取数据更新Cache
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int interval() default 0;
|
||||
|
||||
/**
|
||||
* DataSource是否直接返回对象的真实引用, 而不是copy一份
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
boolean direct() default false;
|
||||
/**
|
||||
* DataSource是否直接返回对象的真实引用, 而不是copy一份
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
boolean direct() default false;
|
||||
}
|
||||
|
||||
@@ -56,92 +56,92 @@ import java.lang.annotation.*;
|
||||
@Retention(RUNTIME)
|
||||
public @interface Column {
|
||||
|
||||
/**
|
||||
* (Optional) The name of the column. Defaults to the property or field name.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String name() default "";
|
||||
/**
|
||||
* (Optional) The name of the column. Defaults to the property or field name.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* (Optional) The comment of the column.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String comment() default "";
|
||||
/**
|
||||
* (Optional) The comment of the column.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String comment() default "";
|
||||
|
||||
/**
|
||||
* (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
|
||||
* column. This constraint applies in addition to any constraint entailed by primary key mapping and to constraints
|
||||
* specified at the table level.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
boolean unique() default false;
|
||||
/**
|
||||
* (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
|
||||
* column. This constraint applies in addition to any constraint entailed by primary key mapping and to constraints
|
||||
* specified at the table level.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
boolean unique() default false;
|
||||
|
||||
/**
|
||||
* (Optional) Whether the database column is required.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
boolean nullable() default true;
|
||||
/**
|
||||
* (Optional) Whether the database column is required.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
boolean nullable() default true;
|
||||
|
||||
/**
|
||||
* for OpenAPI Specification 3
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String example() default "";
|
||||
/**
|
||||
* for OpenAPI Specification 3
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String example() default "";
|
||||
|
||||
/**
|
||||
* (Optional) Whether the column is included in SQL INSERT statements generated by the persistence provider.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
boolean insertable() default true;
|
||||
/**
|
||||
* (Optional) Whether the column is included in SQL INSERT statements generated by the persistence provider.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
boolean insertable() default true;
|
||||
|
||||
/**
|
||||
* (Optional) Whether the column is included in SQL UPDATE statements generated by the persistence provider.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
boolean updatable() default true;
|
||||
/**
|
||||
* (Optional) Whether the column is included in SQL UPDATE statements generated by the persistence provider.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
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
|
||||
* table.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
@Deprecated
|
||||
String table() default "";
|
||||
/**
|
||||
* (Optional) The name of the table that contains the column. If absent the column is assumed to be in the primary
|
||||
* table.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
@Deprecated
|
||||
String table() default "";
|
||||
|
||||
/**
|
||||
* (Optional) The column length. (Applies only if a string-valued column is used.) if type==String and length ==
|
||||
* 65535 then sqltype is TEXT <br>
|
||||
* if type==String and length <= 16777215 then sqltype is MEDIUMTEXT <br>
|
||||
* if type==String and length > 16777215 then sqltype is LONGTEXT <br>
|
||||
* if type==byte[] and length <= 65535 then sqltype is BLOB <br>
|
||||
* if type==byte[] and length <= 16777215 then sqltype is MEDIUMBLOB <br>
|
||||
* if type==byte[] and length > 16777215 then sqltype is LONGBLOB <br>
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int length() default 255;
|
||||
/**
|
||||
* (Optional) The column length. (Applies only if a string-valued column is used.) if type==String and length ==
|
||||
* 65535 then sqltype is TEXT <br>
|
||||
* if type==String and length <= 16777215 then sqltype is MEDIUMTEXT <br>
|
||||
* if type==String and length > 16777215 then sqltype is LONGTEXT <br>
|
||||
* if type==byte[] and length <= 65535 then sqltype is BLOB <br>
|
||||
* if type==byte[] and length <= 16777215 then sqltype is MEDIUMBLOB <br>
|
||||
* if type==byte[] and length > 16777215 then sqltype is LONGBLOB <br>
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int length() default 255;
|
||||
|
||||
/**
|
||||
* (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.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int precision() default 0;
|
||||
/**
|
||||
* (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.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int precision() default 0;
|
||||
|
||||
/**
|
||||
* (Optional) The scale for a decimal (exact numeric) column. (Applies only if a decimal column is used.)
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int scale() default 0;
|
||||
/**
|
||||
* (Optional) The scale for a decimal (exact numeric) column. (Applies only if a decimal column is used.)
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int scale() default 0;
|
||||
}
|
||||
|
||||
@@ -32,18 +32,18 @@ import java.lang.annotation.*;
|
||||
@Retention(RUNTIME)
|
||||
public @interface Entity {
|
||||
|
||||
/**
|
||||
* (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.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String name() default "";
|
||||
/**
|
||||
* (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.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* (Optional) The comment of the entity.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String comment() default "";
|
||||
/**
|
||||
* (Optional) The comment of the entity.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String comment() default "";
|
||||
}
|
||||
|
||||
@@ -41,24 +41,24 @@ import java.lang.annotation.*;
|
||||
@Retention(RUNTIME)
|
||||
public @interface Index {
|
||||
|
||||
/**
|
||||
* (Optional) The name of the index; defaults to a provider-generated name.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String name() default "";
|
||||
/**
|
||||
* (Optional) The name of the index; defaults to a provider-generated name.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* (Required) The names of the columns to be included in the index, in order.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String columnList();
|
||||
/**
|
||||
* (Required) The names of the columns to be included in the index, in order.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String columnList();
|
||||
|
||||
/**
|
||||
* (Optional) Whether the index is unique.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
boolean unique() default false;
|
||||
/**
|
||||
* (Optional) Whether the index is unique.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
boolean unique() default false;
|
||||
}
|
||||
|
||||
@@ -41,48 +41,48 @@ import java.lang.annotation.*;
|
||||
@Retention(RUNTIME)
|
||||
public @interface Table {
|
||||
|
||||
/**
|
||||
* (Optional) The name of the table.
|
||||
*
|
||||
* <p>Defaults to the entity name.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String name() default "";
|
||||
/**
|
||||
* (Optional) The name of the table.
|
||||
*
|
||||
* <p>Defaults to the entity name.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* (Optional) The catalog of the table.
|
||||
*
|
||||
* <p>Defaults to the default catalog.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String catalog() default "";
|
||||
/**
|
||||
* (Optional) The catalog of the table.
|
||||
*
|
||||
* <p>Defaults to the default catalog.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String catalog() default "";
|
||||
|
||||
/**
|
||||
* (Optional) Unique constraints that are to be placed on the table. These are only used if table generation is in
|
||||
* effect. These constraints apply in addition to any constraints specified by the <code>Column</code> and <code>
|
||||
* JoinColumn</code> annotations and constraints entailed by primary key mappings.
|
||||
*
|
||||
* <p>Defaults to no additional constraints.
|
||||
*
|
||||
* @return UniqueConstraint[]
|
||||
*/
|
||||
UniqueConstraint[] uniqueConstraints() default {};
|
||||
/**
|
||||
* (Optional) Unique constraints that are to be placed on the table. These are only used if table generation is in
|
||||
* effect. These constraints apply in addition to any constraints specified by the <code>Column</code> and <code>
|
||||
* JoinColumn</code> annotations and constraints entailed by primary key mappings.
|
||||
*
|
||||
* <p>Defaults to no additional constraints.
|
||||
*
|
||||
* @return UniqueConstraint[]
|
||||
*/
|
||||
UniqueConstraint[] uniqueConstraints() default {};
|
||||
|
||||
/**
|
||||
* (Optional) Indexes for the table. These are only used if table generation is in effect. Note that it is not
|
||||
* necessary to specify an index for a primary key, as the primary key index will be created automatically.
|
||||
*
|
||||
* @return indexes
|
||||
* @since Java Persistence 2.1
|
||||
*/
|
||||
Index[] indexes() default {};
|
||||
/**
|
||||
* (Optional) Indexes for the table. These are only used if table generation is in effect. Note that it is not
|
||||
* necessary to specify an index for a primary key, as the primary key index will be created automatically.
|
||||
*
|
||||
* @return indexes
|
||||
* @since Java Persistence 2.1
|
||||
*/
|
||||
Index[] indexes() default {};
|
||||
|
||||
/**
|
||||
* comment
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String comment() default "";
|
||||
/**
|
||||
* comment
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String comment() default "";
|
||||
}
|
||||
|
||||
@@ -40,18 +40,18 @@ import java.lang.annotation.*;
|
||||
@Retention(RUNTIME)
|
||||
public @interface UniqueConstraint {
|
||||
|
||||
/**
|
||||
* (Optional) Constraint name. A provider-chosen name will be chosen if a name is not specified.
|
||||
*
|
||||
* @return String
|
||||
* @since Java Persistence 2.0
|
||||
*/
|
||||
String name() default "";
|
||||
/**
|
||||
* (Optional) Constraint name. A provider-chosen name will be chosen if a name is not specified.
|
||||
*
|
||||
* @return String
|
||||
* @since Java Persistence 2.0
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* (Required) An array of the column names that make up the constraint.
|
||||
*
|
||||
* @return String[]
|
||||
*/
|
||||
String[] columnNames();
|
||||
/**
|
||||
* (Required) An array of the column names that make up the constraint.
|
||||
*
|
||||
* @return String[]
|
||||
*/
|
||||
String[] columnNames();
|
||||
}
|
||||
|
||||
@@ -4,51 +4,51 @@
|
||||
* @author zhangjx
|
||||
*/
|
||||
module org.redkale {
|
||||
requires java.base;
|
||||
requires java.logging;
|
||||
requires java.net.http;
|
||||
requires java.sql;
|
||||
requires jdk.unsupported; // sun.misc.Unsafe
|
||||
requires java.base;
|
||||
requires java.logging;
|
||||
requires java.net.http;
|
||||
requires java.sql;
|
||||
requires jdk.unsupported; // sun.misc.Unsafe
|
||||
|
||||
exports org.redkale.annotation;
|
||||
exports org.redkale.boot;
|
||||
exports org.redkale.boot.watch;
|
||||
exports org.redkale.cache;
|
||||
exports org.redkale.cache.spi;
|
||||
exports org.redkale.cluster;
|
||||
exports org.redkale.cluster.spi;
|
||||
exports org.redkale.convert;
|
||||
exports org.redkale.convert.bson;
|
||||
exports org.redkale.convert.ext;
|
||||
exports org.redkale.convert.json;
|
||||
exports org.redkale.convert.proto;
|
||||
exports org.redkale.convert.spi;
|
||||
exports org.redkale.inject;
|
||||
exports org.redkale.lock;
|
||||
exports org.redkale.lock.spi;
|
||||
exports org.redkale.mq;
|
||||
exports org.redkale.mq.spi;
|
||||
exports org.redkale.net;
|
||||
exports org.redkale.net.client;
|
||||
exports org.redkale.net.http;
|
||||
exports org.redkale.net.sncp;
|
||||
exports org.redkale.persistence;
|
||||
exports org.redkale.props.spi;
|
||||
exports org.redkale.schedule;
|
||||
exports org.redkale.schedule.spi;
|
||||
exports org.redkale.service;
|
||||
exports org.redkale.source;
|
||||
exports org.redkale.source.spi;
|
||||
exports org.redkale.util;
|
||||
exports org.redkale.watch;
|
||||
exports org.redkale.annotation;
|
||||
exports org.redkale.boot;
|
||||
exports org.redkale.boot.watch;
|
||||
exports org.redkale.cache;
|
||||
exports org.redkale.cache.spi;
|
||||
exports org.redkale.cluster;
|
||||
exports org.redkale.cluster.spi;
|
||||
exports org.redkale.convert;
|
||||
exports org.redkale.convert.bson;
|
||||
exports org.redkale.convert.ext;
|
||||
exports org.redkale.convert.json;
|
||||
exports org.redkale.convert.proto;
|
||||
exports org.redkale.convert.spi;
|
||||
exports org.redkale.inject;
|
||||
exports org.redkale.lock;
|
||||
exports org.redkale.lock.spi;
|
||||
exports org.redkale.mq;
|
||||
exports org.redkale.mq.spi;
|
||||
exports org.redkale.net;
|
||||
exports org.redkale.net.client;
|
||||
exports org.redkale.net.http;
|
||||
exports org.redkale.net.sncp;
|
||||
exports org.redkale.persistence;
|
||||
exports org.redkale.props.spi;
|
||||
exports org.redkale.schedule;
|
||||
exports org.redkale.schedule.spi;
|
||||
exports org.redkale.service;
|
||||
exports org.redkale.source;
|
||||
exports org.redkale.source.spi;
|
||||
exports org.redkale.util;
|
||||
exports org.redkale.watch;
|
||||
|
||||
uses org.redkale.props.spi.PropertiesAgentProvider;
|
||||
uses org.redkale.cache.spi.CacheManagerProvider;
|
||||
uses org.redkale.cluster.spi.ClusterAgentProvider;
|
||||
uses org.redkale.convert.spi.ConvertProvider;
|
||||
uses org.redkale.mq.spi.MessageAgentProvider;
|
||||
uses org.redkale.schedule.spi.ScheduleManagerProvider;
|
||||
uses org.redkale.source.spi.CacheSourceProvider;
|
||||
uses org.redkale.source.spi.DataSourceProvider;
|
||||
uses org.redkale.source.spi.DataNativeSqlParserProvider;
|
||||
uses org.redkale.props.spi.PropertiesAgentProvider;
|
||||
uses org.redkale.cache.spi.CacheManagerProvider;
|
||||
uses org.redkale.cluster.spi.ClusterAgentProvider;
|
||||
uses org.redkale.convert.spi.ConvertProvider;
|
||||
uses org.redkale.mq.spi.MessageAgentProvider;
|
||||
uses org.redkale.schedule.spi.ScheduleManagerProvider;
|
||||
uses org.redkale.source.spi.CacheSourceProvider;
|
||||
uses org.redkale.source.spi.DataSourceProvider;
|
||||
uses org.redkale.source.spi.DataNativeSqlParserProvider;
|
||||
}
|
||||
|
||||
@@ -22,5 +22,5 @@ import java.lang.annotation.*;
|
||||
@Retention(RUNTIME)
|
||||
public @interface AutoLoad {
|
||||
|
||||
boolean value() default true;
|
||||
boolean value() default true;
|
||||
}
|
||||
|
||||
@@ -21,5 +21,5 @@ import java.lang.annotation.*;
|
||||
@Retention(SOURCE)
|
||||
public @interface ClassDepends {
|
||||
|
||||
Class[] value() default {};
|
||||
Class[] value() default {};
|
||||
}
|
||||
|
||||
@@ -23,25 +23,25 @@ import java.lang.annotation.*;
|
||||
@Retention(RUNTIME)
|
||||
public @interface Command {
|
||||
|
||||
/**
|
||||
* 命令号,没有指定值则接收所有的命令
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String value() default "";
|
||||
/**
|
||||
* 命令号,没有指定值则接收所有的命令
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* 参数帮助说明,在value不为空命令redkale --help时显示
|
||||
*
|
||||
* @return String
|
||||
* @since 2.7.0
|
||||
*/
|
||||
String description() default "";
|
||||
/**
|
||||
* 参数帮助说明,在value不为空命令redkale --help时显示
|
||||
*
|
||||
* @return String
|
||||
* @since 2.7.0
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String comment() default "";
|
||||
/**
|
||||
* 描述
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String comment() default "";
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.lang.annotation.*;
|
||||
@Retention(RUNTIME)
|
||||
public @interface Comment {
|
||||
|
||||
String name() default "";
|
||||
String name() default "";
|
||||
|
||||
String value();
|
||||
String value();
|
||||
}
|
||||
|
||||
@@ -23,5 +23,5 @@ import java.lang.annotation.*;
|
||||
@ClassDepends
|
||||
public @interface ConstructorParameters {
|
||||
|
||||
String[] value();
|
||||
String[] value();
|
||||
}
|
||||
|
||||
@@ -37,15 +37,15 @@ import java.lang.annotation.*;
|
||||
@Repeatable(LogExcludeLevel.LogExcludeLevels.class)
|
||||
public @interface LogExcludeLevel {
|
||||
|
||||
String[] levels();
|
||||
String[] levels();
|
||||
|
||||
String[] keys();
|
||||
String[] keys();
|
||||
|
||||
@Documented
|
||||
@Target({TYPE})
|
||||
@Retention(RUNTIME)
|
||||
@interface LogExcludeLevels {
|
||||
@Documented
|
||||
@Target({TYPE})
|
||||
@Retention(RUNTIME)
|
||||
@interface LogExcludeLevels {
|
||||
|
||||
LogExcludeLevel[] value();
|
||||
}
|
||||
LogExcludeLevel[] value();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,5 +22,5 @@ import java.lang.annotation.*;
|
||||
@Retention(RUNTIME)
|
||||
public @interface LogLevel {
|
||||
|
||||
String value();
|
||||
String value();
|
||||
}
|
||||
|
||||
@@ -21,5 +21,5 @@ import java.lang.annotation.*;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NonBlocking { // 不可使用@Inherited,防止被继承, 见HttpServlet.preExecute/authenticate/execute
|
||||
|
||||
boolean value() default true;
|
||||
boolean value() default true;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.lang.annotation.Target;
|
||||
@Retention(RUNTIME)
|
||||
public @interface Param {
|
||||
|
||||
String value();
|
||||
String value();
|
||||
|
||||
String comment() default "";
|
||||
String comment() default "";
|
||||
}
|
||||
|
||||
@@ -30,16 +30,16 @@ import java.lang.annotation.Target;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
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
|
||||
*/
|
||||
int value();
|
||||
/**
|
||||
* 优先级值
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int value();
|
||||
}
|
||||
|
||||
@@ -19,42 +19,42 @@ import java.lang.annotation.*;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
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
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public boolean required() default true;
|
||||
/**
|
||||
* 是否必须存在
|
||||
*
|
||||
* @return boolean
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public boolean required() default true;
|
||||
|
||||
/**
|
||||
* 资源名称 <br>
|
||||
*
|
||||
* <blockquote>
|
||||
*
|
||||
* <pre>
|
||||
* name规则:
|
||||
* 1: "@"有特殊含义, 表示资源本身,"@"不能单独使用
|
||||
* 2: "#name"、"#type"有特殊含义
|
||||
* 3: 只能是字母、数字、(短横)-、(下划线)_、点(.)的组合
|
||||
* </pre>
|
||||
*
|
||||
* </blockquote>
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String name() default "";
|
||||
/**
|
||||
* 资源名称 <br>
|
||||
*
|
||||
* <blockquote>
|
||||
*
|
||||
* <pre>
|
||||
* name规则:
|
||||
* 1: "@"有特殊含义, 表示资源本身,"@"不能单独使用
|
||||
* 2: "#name"、"#type"有特殊含义
|
||||
* 3: 只能是字母、数字、(短横)-、(下划线)_、点(.)的组合
|
||||
* </pre>
|
||||
*
|
||||
* </blockquote>
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String name() default "";
|
||||
|
||||
/**
|
||||
* 依赖注入的类型
|
||||
*
|
||||
* @return Class
|
||||
*/
|
||||
public Class<?> type() default Object.class;
|
||||
/**
|
||||
* 依赖注入的类型
|
||||
*
|
||||
* @return Class
|
||||
*/
|
||||
public Class<?> type() default Object.class;
|
||||
}
|
||||
|
||||
@@ -55,12 +55,12 @@ import java.lang.annotation.*;
|
||||
@Retention(RUNTIME)
|
||||
public @interface ResourceChanged {
|
||||
|
||||
/**
|
||||
* 新旧值是否不同时才回调方法 <br>
|
||||
* true: 新值与旧值不同时才回调ResourceChanged方法 false: 只要执行了ResourceFactory.register 就回调ResourceChanged方法
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @return boolean
|
||||
*/
|
||||
boolean different() default true;
|
||||
/**
|
||||
* 新旧值是否不同时才回调方法 <br>
|
||||
* true: 新值与旧值不同时才回调ResourceChanged方法 false: 只要执行了ResourceFactory.register 就回调ResourceChanged方法
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @return boolean
|
||||
*/
|
||||
boolean different() default true;
|
||||
}
|
||||
|
||||
@@ -24,5 +24,5 @@ import java.lang.annotation.*;
|
||||
@Retention(RUNTIME)
|
||||
public @interface ResourceType {
|
||||
|
||||
Class value();
|
||||
Class value();
|
||||
}
|
||||
|
||||
@@ -68,103 +68,103 @@ package org.redkale.asm;
|
||||
*/
|
||||
public abstract class AnnotationVisitor {
|
||||
|
||||
/**
|
||||
* The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
protected final int api;
|
||||
/**
|
||||
* The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
/** The annotation visitor to which this visitor must delegate method calls. May be null. */
|
||||
protected AnnotationVisitor av;
|
||||
/** The annotation visitor to which this visitor must delegate method calls. May be null. */
|
||||
protected AnnotationVisitor av;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link AnnotationVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
public AnnotationVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@link AnnotationVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
public AnnotationVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link AnnotationVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
* @param av the annotation visitor to which this visitor must delegate method calls. May be null.
|
||||
*/
|
||||
public AnnotationVisitor(final int api, final AnnotationVisitor av) {
|
||||
this.api = api;
|
||||
this.av = av;
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@link AnnotationVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
* @param av the annotation visitor to which this visitor must delegate method calls. May be null.
|
||||
*/
|
||||
public AnnotationVisitor(final int api, final AnnotationVisitor av) {
|
||||
this.api = api;
|
||||
this.av = av;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a primitive value of the annotation.
|
||||
*
|
||||
* @param name the value name.
|
||||
* @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link Character},
|
||||
* {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double}, {@link String} or {@link Type}
|
||||
* of OBJECT or ARRAY sort. This value can also be an array of byte, boolean, short, char, int, long, float or
|
||||
* double values (this is equivalent to using {@link #visitArray visitArray} and visiting each array element in
|
||||
* turn, but is more convenient).
|
||||
*/
|
||||
public void visit(String name, Object value) {
|
||||
if (av != null) {
|
||||
av.visit(name, value);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visits a primitive value of the annotation.
|
||||
*
|
||||
* @param name the value name.
|
||||
* @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link Character},
|
||||
* {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double}, {@link String} or {@link Type}
|
||||
* of OBJECT or ARRAY sort. This value can also be an array of byte, boolean, short, char, int, long, float or
|
||||
* double values (this is equivalent to using {@link #visitArray visitArray} and visiting each array element in
|
||||
* turn, but is more convenient).
|
||||
*/
|
||||
public void visit(String name, Object value) {
|
||||
if (av != null) {
|
||||
av.visit(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an enumeration value of the annotation.
|
||||
*
|
||||
* @param name the value name.
|
||||
* @param desc the class descriptor of the enumeration class.
|
||||
* @param value the actual enumeration value.
|
||||
*/
|
||||
public void visitEnum(String name, String desc, String value) {
|
||||
if (av != null) {
|
||||
av.visitEnum(name, desc, value);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visits an enumeration value of the annotation.
|
||||
*
|
||||
* @param name the value name.
|
||||
* @param desc the class descriptor of the enumeration class.
|
||||
* @param value the actual enumeration value.
|
||||
*/
|
||||
public void visitEnum(String name, String desc, String value) {
|
||||
if (av != null) {
|
||||
av.visitEnum(name, desc, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a nested annotation value of the annotation.
|
||||
*
|
||||
* @param name the value name.
|
||||
* @param desc the class descriptor of the nested annotation class.
|
||||
* @return a visitor to visit the actual nested annotation value, or <tt>null</tt> if this visitor
|
||||
* is not interested in visiting this nested annotation. <i>The nested annotation value must be fully visited
|
||||
* before calling other methods on this annotation visitor</i>.
|
||||
*/
|
||||
public AnnotationVisitor visitAnnotation(String name, String desc) {
|
||||
if (av != null) {
|
||||
return av.visitAnnotation(name, desc);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Visits a nested annotation value of the annotation.
|
||||
*
|
||||
* @param name the value name.
|
||||
* @param desc the class descriptor of the nested annotation class.
|
||||
* @return a visitor to visit the actual nested annotation value, or <tt>null</tt> if this visitor
|
||||
* is not interested in visiting this nested annotation. <i>The nested annotation value must be fully visited
|
||||
* before calling other methods on this annotation visitor</i>.
|
||||
*/
|
||||
public AnnotationVisitor visitAnnotation(String name, String desc) {
|
||||
if (av != null) {
|
||||
return av.visitAnnotation(name, desc);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an array value of the annotation. Note that arrays of primitive types (such as byte, boolean, short, char,
|
||||
* int, long, float or double) can be passed as value to {@link #visit visit}. This is what {@link ClassReader}
|
||||
* does.
|
||||
*
|
||||
* @param name the value name.
|
||||
* @return a visitor to visit the actual array value elements, or <tt>null</tt> if this visitor is
|
||||
* not interested in visiting these values. The 'name' parameters passed to the methods of this visitor are
|
||||
* ignored. <i>All the array values must be visited before calling other methods on this annotation visitor</i>.
|
||||
*/
|
||||
public AnnotationVisitor visitArray(String name) {
|
||||
if (av != null) {
|
||||
return av.visitArray(name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Visits an array value of the annotation. Note that arrays of primitive types (such as byte, boolean, short, char,
|
||||
* int, long, float or double) can be passed as value to {@link #visit visit}. This is what {@link ClassReader}
|
||||
* does.
|
||||
*
|
||||
* @param name the value name.
|
||||
* @return a visitor to visit the actual array value elements, or <tt>null</tt> if this visitor is
|
||||
* not interested in visiting these values. The 'name' parameters passed to the methods of this visitor are
|
||||
* ignored. <i>All the array values must be visited before calling other methods on this annotation visitor</i>.
|
||||
*/
|
||||
public AnnotationVisitor visitArray(String name) {
|
||||
if (av != null) {
|
||||
return av.visitArray(name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Visits the end of the annotation. */
|
||||
public void visitEnd() {
|
||||
if (av != null) {
|
||||
av.visitEnd();
|
||||
}
|
||||
}
|
||||
/** Visits the end of the annotation. */
|
||||
public void visitEnd() {
|
||||
if (av != null) {
|
||||
av.visitEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,301 +66,301 @@ package org.redkale.asm;
|
||||
*/
|
||||
final class AnnotationWriter extends AnnotationVisitor {
|
||||
|
||||
/** The class writer to which this annotation must be added. */
|
||||
private final ClassWriter cw;
|
||||
/** The class writer to which this annotation must be added. */
|
||||
private final ClassWriter cw;
|
||||
|
||||
/** The number of values in this annotation. */
|
||||
private int size;
|
||||
/** The number of values in this annotation. */
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation writers
|
||||
* used for annotation default and annotation arrays use unnamed values.
|
||||
*/
|
||||
private final boolean named;
|
||||
/**
|
||||
* <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation writers
|
||||
* used for annotation default and annotation arrays use unnamed values.
|
||||
*/
|
||||
private final boolean named;
|
||||
|
||||
/**
|
||||
* The annotation values in bytecode form. This byte vector only contains the values themselves, i.e. the number of
|
||||
* values must be stored as a unsigned short just before these bytes.
|
||||
*/
|
||||
private final ByteVector bv;
|
||||
/**
|
||||
* The annotation values in bytecode form. This byte vector only contains the values themselves, i.e. the number of
|
||||
* values must be stored as a unsigned short just before these bytes.
|
||||
*/
|
||||
private final ByteVector bv;
|
||||
|
||||
/** The byte vector to be used to store the number of values of this annotation. See {@link #bv}. */
|
||||
private final ByteVector parent;
|
||||
/** The byte vector to be used to store the number of values of this annotation. See {@link #bv}. */
|
||||
private final ByteVector parent;
|
||||
|
||||
/** Where the number of values of this annotation must be stored in {@link #parent}. */
|
||||
private final int offset;
|
||||
/** Where the number of values of this annotation must be stored in {@link #parent}. */
|
||||
private final int offset;
|
||||
|
||||
/** Next annotation writer. This field is used to store annotation lists. */
|
||||
AnnotationWriter next;
|
||||
/** Next annotation writer. This field is used to store annotation lists. */
|
||||
AnnotationWriter next;
|
||||
|
||||
/** Previous annotation writer. This field is used to store annotation lists. */
|
||||
AnnotationWriter prev;
|
||||
/** Previous annotation writer. This field is used to store annotation lists. */
|
||||
AnnotationWriter prev;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// ------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs a new {@link AnnotationWriter}.
|
||||
*
|
||||
* @param cw the class writer to which this annotation must be added.
|
||||
* @param named <tt>true<tt> if values are named, <tt>false</tt> otherwise.
|
||||
* @param bv where the annotation values must be stored.
|
||||
* @param parent where the number of annotation values must be stored.
|
||||
* @param offset where in <tt>parent</tt> the number of annotation values must be stored.
|
||||
*/
|
||||
AnnotationWriter(
|
||||
final ClassWriter cw, final boolean named, final ByteVector bv, final ByteVector parent, final int offset) {
|
||||
super(Opcodes.ASM6);
|
||||
this.cw = cw;
|
||||
this.named = named;
|
||||
this.bv = bv;
|
||||
this.parent = parent;
|
||||
this.offset = offset;
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@link AnnotationWriter}.
|
||||
*
|
||||
* @param cw the class writer to which this annotation must be added.
|
||||
* @param named <tt>true<tt> if values are named, <tt>false</tt> otherwise.
|
||||
* @param bv where the annotation values must be stored.
|
||||
* @param parent where the number of annotation values must be stored.
|
||||
* @param offset where in <tt>parent</tt> the number of annotation values must be stored.
|
||||
*/
|
||||
AnnotationWriter(
|
||||
final ClassWriter cw, final boolean named, final ByteVector bv, final ByteVector parent, final int offset) {
|
||||
super(Opcodes.ASM6);
|
||||
this.cw = cw;
|
||||
this.named = named;
|
||||
this.bv = bv;
|
||||
this.parent = parent;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Implementation of the AnnotationVisitor abstract class
|
||||
// ------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
// Implementation of the AnnotationVisitor abstract class
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void visit(final String name, final Object value) {
|
||||
++size;
|
||||
if (named) {
|
||||
bv.putShort(cw.newUTF8(name));
|
||||
}
|
||||
if (value instanceof String) {
|
||||
bv.put12('s', cw.newUTF8((String) value));
|
||||
} else if (value instanceof Byte) {
|
||||
bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
|
||||
} else if (value instanceof Boolean) {
|
||||
int v = ((Boolean) value).booleanValue() ? 1 : 0;
|
||||
bv.put12('Z', cw.newInteger(v).index);
|
||||
} else if (value instanceof Character) {
|
||||
bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
|
||||
} else if (value instanceof Short) {
|
||||
bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
|
||||
} else if (value instanceof Type) {
|
||||
bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
|
||||
} else if (value instanceof byte[]) {
|
||||
byte[] v = (byte[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('B', cw.newInteger(v[i]).index);
|
||||
}
|
||||
} else if (value instanceof boolean[]) {
|
||||
boolean[] v = (boolean[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
|
||||
}
|
||||
} else if (value instanceof short[]) {
|
||||
short[] v = (short[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('S', cw.newInteger(v[i]).index);
|
||||
}
|
||||
} else if (value instanceof char[]) {
|
||||
char[] v = (char[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('C', cw.newInteger(v[i]).index);
|
||||
}
|
||||
} else if (value instanceof int[]) {
|
||||
int[] v = (int[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('I', cw.newInteger(v[i]).index);
|
||||
}
|
||||
} else if (value instanceof long[]) {
|
||||
long[] v = (long[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('J', cw.newLong(v[i]).index);
|
||||
}
|
||||
} else if (value instanceof float[]) {
|
||||
float[] v = (float[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('F', cw.newFloat(v[i]).index);
|
||||
}
|
||||
} else if (value instanceof double[]) {
|
||||
double[] v = (double[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('D', cw.newDouble(v[i]).index);
|
||||
}
|
||||
} else {
|
||||
Item i = cw.newConstItem(value);
|
||||
bv.put12(".s.IFJDCS".charAt(i.type), i.index);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void visit(final String name, final Object value) {
|
||||
++size;
|
||||
if (named) {
|
||||
bv.putShort(cw.newUTF8(name));
|
||||
}
|
||||
if (value instanceof String) {
|
||||
bv.put12('s', cw.newUTF8((String) value));
|
||||
} else if (value instanceof Byte) {
|
||||
bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
|
||||
} else if (value instanceof Boolean) {
|
||||
int v = ((Boolean) value).booleanValue() ? 1 : 0;
|
||||
bv.put12('Z', cw.newInteger(v).index);
|
||||
} else if (value instanceof Character) {
|
||||
bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
|
||||
} else if (value instanceof Short) {
|
||||
bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
|
||||
} else if (value instanceof Type) {
|
||||
bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
|
||||
} else if (value instanceof byte[]) {
|
||||
byte[] v = (byte[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('B', cw.newInteger(v[i]).index);
|
||||
}
|
||||
} else if (value instanceof boolean[]) {
|
||||
boolean[] v = (boolean[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
|
||||
}
|
||||
} else if (value instanceof short[]) {
|
||||
short[] v = (short[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('S', cw.newInteger(v[i]).index);
|
||||
}
|
||||
} else if (value instanceof char[]) {
|
||||
char[] v = (char[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('C', cw.newInteger(v[i]).index);
|
||||
}
|
||||
} else if (value instanceof int[]) {
|
||||
int[] v = (int[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('I', cw.newInteger(v[i]).index);
|
||||
}
|
||||
} else if (value instanceof long[]) {
|
||||
long[] v = (long[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('J', cw.newLong(v[i]).index);
|
||||
}
|
||||
} else if (value instanceof float[]) {
|
||||
float[] v = (float[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('F', cw.newFloat(v[i]).index);
|
||||
}
|
||||
} else if (value instanceof double[]) {
|
||||
double[] v = (double[]) value;
|
||||
bv.put12('[', v.length);
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
bv.put12('D', cw.newDouble(v[i]).index);
|
||||
}
|
||||
} else {
|
||||
Item i = cw.newConstItem(value);
|
||||
bv.put12(".s.IFJDCS".charAt(i.type), i.index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(final String name, final String desc, final String value) {
|
||||
++size;
|
||||
if (named) {
|
||||
bv.putShort(cw.newUTF8(name));
|
||||
}
|
||||
bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
|
||||
}
|
||||
@Override
|
||||
public void visitEnum(final String name, final String desc, final String value) {
|
||||
++size;
|
||||
if (named) {
|
||||
bv.putShort(cw.newUTF8(name));
|
||||
}
|
||||
bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String name, final String desc) {
|
||||
++size;
|
||||
if (named) {
|
||||
bv.putShort(cw.newUTF8(name));
|
||||
}
|
||||
// write tag and type, and reserve space for values count
|
||||
bv.put12('@', cw.newUTF8(desc)).putShort(0);
|
||||
return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
|
||||
}
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String name, final String desc) {
|
||||
++size;
|
||||
if (named) {
|
||||
bv.putShort(cw.newUTF8(name));
|
||||
}
|
||||
// write tag and type, and reserve space for values count
|
||||
bv.put12('@', cw.newUTF8(desc)).putShort(0);
|
||||
return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(final String name) {
|
||||
++size;
|
||||
if (named) {
|
||||
bv.putShort(cw.newUTF8(name));
|
||||
}
|
||||
// write tag, and reserve space for array size
|
||||
bv.put12('[', 0);
|
||||
return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
|
||||
}
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(final String name) {
|
||||
++size;
|
||||
if (named) {
|
||||
bv.putShort(cw.newUTF8(name));
|
||||
}
|
||||
// write tag, and reserve space for array size
|
||||
bv.put12('[', 0);
|
||||
return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (parent != null) {
|
||||
byte[] data = parent.data;
|
||||
data[offset] = (byte) (size >>> 8);
|
||||
data[offset + 1] = (byte) size;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (parent != null) {
|
||||
byte[] data = parent.data;
|
||||
data[offset] = (byte) (size >>> 8);
|
||||
data[offset + 1] = (byte) size;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
// ------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the size of this annotation writer list.
|
||||
*
|
||||
* @return the size of this annotation writer list.
|
||||
*/
|
||||
int getSize() {
|
||||
int size = 0;
|
||||
AnnotationWriter aw = this;
|
||||
while (aw != null) {
|
||||
size += aw.bv.length;
|
||||
aw = aw.next;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
/**
|
||||
* Returns the size of this annotation writer list.
|
||||
*
|
||||
* @return the size of this annotation writer list.
|
||||
*/
|
||||
int getSize() {
|
||||
int size = 0;
|
||||
AnnotationWriter aw = this;
|
||||
while (aw != null) {
|
||||
size += aw.bv.length;
|
||||
aw = aw.next;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the annotations of this annotation writer list into the given byte vector.
|
||||
*
|
||||
* @param out where the annotations must be put.
|
||||
*/
|
||||
void put(final ByteVector out) {
|
||||
int n = 0;
|
||||
int size = 2;
|
||||
AnnotationWriter aw = this;
|
||||
AnnotationWriter last = null;
|
||||
while (aw != null) {
|
||||
++n;
|
||||
size += aw.bv.length;
|
||||
aw.visitEnd(); // in case user forgot to call visitEnd
|
||||
aw.prev = last;
|
||||
last = aw;
|
||||
aw = aw.next;
|
||||
}
|
||||
out.putInt(size);
|
||||
out.putShort(n);
|
||||
aw = last;
|
||||
while (aw != null) {
|
||||
out.putByteArray(aw.bv.data, 0, aw.bv.length);
|
||||
aw = aw.prev;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Puts the annotations of this annotation writer list into the given byte vector.
|
||||
*
|
||||
* @param out where the annotations must be put.
|
||||
*/
|
||||
void put(final ByteVector out) {
|
||||
int n = 0;
|
||||
int size = 2;
|
||||
AnnotationWriter aw = this;
|
||||
AnnotationWriter last = null;
|
||||
while (aw != null) {
|
||||
++n;
|
||||
size += aw.bv.length;
|
||||
aw.visitEnd(); // in case user forgot to call visitEnd
|
||||
aw.prev = last;
|
||||
last = aw;
|
||||
aw = aw.next;
|
||||
}
|
||||
out.putInt(size);
|
||||
out.putShort(n);
|
||||
aw = last;
|
||||
while (aw != null) {
|
||||
out.putByteArray(aw.bv.data, 0, aw.bv.length);
|
||||
aw = aw.prev;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given annotation lists into the given byte vector.
|
||||
*
|
||||
* @param panns an array of annotation writer lists.
|
||||
* @param off index of the first annotation to be written.
|
||||
* @param out where the annotations must be put.
|
||||
*/
|
||||
static void put(final AnnotationWriter[] panns, final int off, final ByteVector out) {
|
||||
int size = 1 + 2 * (panns.length - off);
|
||||
for (int i = off; i < panns.length; ++i) {
|
||||
size += panns[i] == null ? 0 : panns[i].getSize();
|
||||
}
|
||||
out.putInt(size).putByte(panns.length - off);
|
||||
for (int i = off; i < panns.length; ++i) {
|
||||
AnnotationWriter aw = panns[i];
|
||||
AnnotationWriter last = null;
|
||||
int n = 0;
|
||||
while (aw != null) {
|
||||
++n;
|
||||
aw.visitEnd(); // in case user forgot to call visitEnd
|
||||
aw.prev = last;
|
||||
last = aw;
|
||||
aw = aw.next;
|
||||
}
|
||||
out.putShort(n);
|
||||
aw = last;
|
||||
while (aw != null) {
|
||||
out.putByteArray(aw.bv.data, 0, aw.bv.length);
|
||||
aw = aw.prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Puts the given annotation lists into the given byte vector.
|
||||
*
|
||||
* @param panns an array of annotation writer lists.
|
||||
* @param off index of the first annotation to be written.
|
||||
* @param out where the annotations must be put.
|
||||
*/
|
||||
static void put(final AnnotationWriter[] panns, final int off, final ByteVector out) {
|
||||
int size = 1 + 2 * (panns.length - off);
|
||||
for (int i = off; i < panns.length; ++i) {
|
||||
size += panns[i] == null ? 0 : panns[i].getSize();
|
||||
}
|
||||
out.putInt(size).putByte(panns.length - off);
|
||||
for (int i = off; i < panns.length; ++i) {
|
||||
AnnotationWriter aw = panns[i];
|
||||
AnnotationWriter last = null;
|
||||
int n = 0;
|
||||
while (aw != null) {
|
||||
++n;
|
||||
aw.visitEnd(); // in case user forgot to call visitEnd
|
||||
aw.prev = last;
|
||||
last = aw;
|
||||
aw = aw.next;
|
||||
}
|
||||
out.putShort(n);
|
||||
aw = last;
|
||||
while (aw != null) {
|
||||
out.putByteArray(aw.bv.data, 0, aw.bv.length);
|
||||
aw = aw.prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given type reference and type path into the given bytevector. LOCAL_VARIABLE and RESOURCE_VARIABLE
|
||||
* target types are not supported.
|
||||
*
|
||||
* @param typeRef a reference to the annotated type. See {@link TypeReference}.
|
||||
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
|
||||
* within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param out where the type reference and type path must be put.
|
||||
*/
|
||||
static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
|
||||
switch (typeRef >>> 24) {
|
||||
case 0x00: // CLASS_TYPE_PARAMETER
|
||||
case 0x01: // METHOD_TYPE_PARAMETER
|
||||
case 0x16: // METHOD_FORMAL_PARAMETER
|
||||
out.putShort(typeRef >>> 16);
|
||||
break;
|
||||
case 0x13: // FIELD
|
||||
case 0x14: // METHOD_RETURN
|
||||
case 0x15: // METHOD_RECEIVER
|
||||
out.putByte(typeRef >>> 24);
|
||||
break;
|
||||
case 0x47: // CAST
|
||||
case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
|
||||
case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||
case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
|
||||
out.putInt(typeRef);
|
||||
break;
|
||||
// case 0x10: // CLASS_EXTENDS
|
||||
// case 0x11: // CLASS_TYPE_PARAMETER_BOUND
|
||||
// case 0x12: // METHOD_TYPE_PARAMETER_BOUND
|
||||
// case 0x17: // THROWS
|
||||
// case 0x42: // EXCEPTION_PARAMETER
|
||||
// case 0x43: // INSTANCEOF
|
||||
// case 0x44: // NEW
|
||||
// case 0x45: // CONSTRUCTOR_REFERENCE
|
||||
// case 0x46: // METHOD_REFERENCE
|
||||
default:
|
||||
out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
|
||||
break;
|
||||
}
|
||||
if (typePath == null) {
|
||||
out.putByte(0);
|
||||
} else {
|
||||
int length = typePath.b[typePath.offset] * 2 + 1;
|
||||
out.putByteArray(typePath.b, typePath.offset, length);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Puts the given type reference and type path into the given bytevector. LOCAL_VARIABLE and RESOURCE_VARIABLE
|
||||
* target types are not supported.
|
||||
*
|
||||
* @param typeRef a reference to the annotated type. See {@link TypeReference}.
|
||||
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
|
||||
* within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param out where the type reference and type path must be put.
|
||||
*/
|
||||
static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
|
||||
switch (typeRef >>> 24) {
|
||||
case 0x00: // CLASS_TYPE_PARAMETER
|
||||
case 0x01: // METHOD_TYPE_PARAMETER
|
||||
case 0x16: // METHOD_FORMAL_PARAMETER
|
||||
out.putShort(typeRef >>> 16);
|
||||
break;
|
||||
case 0x13: // FIELD
|
||||
case 0x14: // METHOD_RETURN
|
||||
case 0x15: // METHOD_RECEIVER
|
||||
out.putByte(typeRef >>> 24);
|
||||
break;
|
||||
case 0x47: // CAST
|
||||
case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
|
||||
case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||
case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
|
||||
out.putInt(typeRef);
|
||||
break;
|
||||
// case 0x10: // CLASS_EXTENDS
|
||||
// case 0x11: // CLASS_TYPE_PARAMETER_BOUND
|
||||
// case 0x12: // METHOD_TYPE_PARAMETER_BOUND
|
||||
// case 0x17: // THROWS
|
||||
// case 0x42: // EXCEPTION_PARAMETER
|
||||
// case 0x43: // INSTANCEOF
|
||||
// case 0x44: // NEW
|
||||
// case 0x45: // CONSTRUCTOR_REFERENCE
|
||||
// case 0x46: // METHOD_REFERENCE
|
||||
default:
|
||||
out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
|
||||
break;
|
||||
}
|
||||
if (typePath == null) {
|
||||
out.putByte(0);
|
||||
} else {
|
||||
int length = typePath.b[typePath.offset] * 2 + 1;
|
||||
out.putByteArray(typePath.b, typePath.offset, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,124 +17,124 @@ import org.redkale.convert.json.JsonConvert;
|
||||
*/
|
||||
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) {
|
||||
this.access = access;
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
this.signature = signature;
|
||||
this.exceptions = exceptions;
|
||||
this.params = new ArrayList<>();
|
||||
}
|
||||
public AsmMethodBean(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
this.access = access;
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
this.signature = signature;
|
||||
this.exceptions = exceptions;
|
||||
this.params = new ArrayList<>();
|
||||
}
|
||||
|
||||
public static AsmMethodBean get(Map<String, AsmMethodBean> map, Method method) {
|
||||
return map == null ? null : map.get(method.getName() + ":" + Type.getMethodDescriptor(method));
|
||||
}
|
||||
public static AsmMethodBean get(Map<String, AsmMethodBean> map, Method method) {
|
||||
return map == null ? null : map.get(method.getName() + ":" + Type.getMethodDescriptor(method));
|
||||
}
|
||||
|
||||
void removeEmptyNames() {
|
||||
if (params != null) {
|
||||
List<AsmMethodParam> dels = null;
|
||||
for (AsmMethodParam p : params) {
|
||||
if (" ".equals(p.getName())) {
|
||||
if (dels == null) {
|
||||
dels = new ArrayList<>();
|
||||
}
|
||||
dels.add(p);
|
||||
}
|
||||
}
|
||||
if (dels != null) {
|
||||
for (AsmMethodParam p : dels) {
|
||||
params.remove(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void removeEmptyNames() {
|
||||
if (params != null) {
|
||||
List<AsmMethodParam> dels = null;
|
||||
for (AsmMethodParam p : params) {
|
||||
if (" ".equals(p.getName())) {
|
||||
if (dels == null) {
|
||||
dels = new ArrayList<>();
|
||||
}
|
||||
dels.add(p);
|
||||
}
|
||||
}
|
||||
if (dels != null) {
|
||||
for (AsmMethodParam p : dels) {
|
||||
params.remove(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> fieldNameList() {
|
||||
if (params == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<String> rs = new ArrayList<>(params.size());
|
||||
for (AsmMethodParam p : params) {
|
||||
rs.add(p.getName());
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
public List<String> fieldNameList() {
|
||||
if (params == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<String> rs = new ArrayList<>(params.size());
|
||||
for (AsmMethodParam p : params) {
|
||||
rs.add(p.getName());
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
|
||||
public String[] fieldNameArray() {
|
||||
if (params == null) {
|
||||
return null;
|
||||
}
|
||||
String[] rs = new String[params.size()];
|
||||
for (int i = 0; i < rs.length; i++) {
|
||||
rs[i] = params.get(i).getName();
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
public String[] fieldNameArray() {
|
||||
if (params == null) {
|
||||
return null;
|
||||
}
|
||||
String[] rs = new String[params.size()];
|
||||
for (int i = 0; i < rs.length; i++) {
|
||||
rs[i] = params.get(i).getName();
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
|
||||
public List<AsmMethodParam> getParams() {
|
||||
return params;
|
||||
}
|
||||
public List<AsmMethodParam> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setParams(List<AsmMethodParam> params) {
|
||||
this.params = params;
|
||||
}
|
||||
public void setParams(List<AsmMethodParam> params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public int getAccess() {
|
||||
return access;
|
||||
}
|
||||
public int getAccess() {
|
||||
return access;
|
||||
}
|
||||
|
||||
public void setAccess(int access) {
|
||||
this.access = access;
|
||||
}
|
||||
public void setAccess(int access) {
|
||||
this.access = access;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(String signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
public void setSignature(String signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public String[] getExceptions() {
|
||||
return exceptions;
|
||||
}
|
||||
public String[] getExceptions() {
|
||||
return exceptions;
|
||||
}
|
||||
|
||||
public void setExceptions(String[] exceptions) {
|
||||
this.exceptions = exceptions;
|
||||
}
|
||||
public void setExceptions(String[] exceptions) {
|
||||
this.exceptions = exceptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,370 +40,370 @@ import org.redkale.util.Utility;
|
||||
*/
|
||||
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) {
|
||||
this.remote = remote;
|
||||
this.serviceType = serviceType;
|
||||
}
|
||||
protected AsmMethodBoost(boolean remote, Class serviceType) {
|
||||
this.remote = remote;
|
||||
this.serviceType = serviceType;
|
||||
}
|
||||
|
||||
public static AsmMethodBoost create(boolean remote, Collection<AsmMethodBoost> list) {
|
||||
return new AsmMethodBoosts(remote, list);
|
||||
}
|
||||
public static AsmMethodBoost create(boolean remote, Collection<AsmMethodBoost> list) {
|
||||
return new AsmMethodBoosts(remote, list);
|
||||
}
|
||||
|
||||
public static AsmMethodBoost create(boolean remote, AsmMethodBoost... items) {
|
||||
return new AsmMethodBoosts(remote, items);
|
||||
}
|
||||
public static AsmMethodBoost create(boolean remote, AsmMethodBoost... items) {
|
||||
return new AsmMethodBoosts(remote, items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回一个类所有方法的字节信息, key为: method.getName+':'+Type.getMethodDescriptor(method)
|
||||
*
|
||||
* @param clazz Class
|
||||
* @return Map
|
||||
*/
|
||||
public static Map<String, AsmMethodBean> getMethodBeans(Class clazz) {
|
||||
Map<String, AsmMethodBean> rs = MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), clazz);
|
||||
// 返回的List中参数列表可能会比方法参数量多,因为方法内的临时变量也会存入list中, 所以需要list的元素集合比方法的参数多
|
||||
rs.values().forEach(AsmMethodBean::removeEmptyNames);
|
||||
return rs;
|
||||
}
|
||||
/**
|
||||
* 返回一个类所有方法的字节信息, key为: method.getName+':'+Type.getMethodDescriptor(method)
|
||||
*
|
||||
* @param clazz Class
|
||||
* @return Map
|
||||
*/
|
||||
public static Map<String, AsmMethodBean> getMethodBeans(Class clazz) {
|
||||
Map<String, AsmMethodBean> rs = MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), clazz);
|
||||
// 返回的List中参数列表可能会比方法参数量多,因为方法内的临时变量也会存入list中, 所以需要list的元素集合比方法的参数多
|
||||
rs.values().forEach(AsmMethodBean::removeEmptyNames);
|
||||
return rs;
|
||||
}
|
||||
|
||||
public static String getMethodBeanKey(Method method) {
|
||||
return method.getName() + ":" + Type.getMethodDescriptor(method);
|
||||
}
|
||||
public static String getMethodBeanKey(Method method) {
|
||||
return method.getName() + ":" + Type.getMethodDescriptor(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取需屏蔽的方法上的注解
|
||||
*
|
||||
* @param method 方法
|
||||
* @return 需要屏蔽的注解
|
||||
*/
|
||||
public abstract List<Class<? extends Annotation>> filterMethodAnnotations(Method method);
|
||||
/**
|
||||
* 获取需屏蔽的方法上的注解
|
||||
*
|
||||
* @param method 方法
|
||||
* @return 需要屏蔽的注解
|
||||
*/
|
||||
public abstract List<Class<? extends Annotation>> filterMethodAnnotations(Method method);
|
||||
|
||||
/**
|
||||
* 对方法进行动态加强处理
|
||||
*
|
||||
* @param classLoader ClassLoader
|
||||
* @param cw 动态字节码Writer
|
||||
* @param newDynName 动态新类名
|
||||
* @param fieldPrefix 动态字段的前缀
|
||||
* @param filterAnns 需要过滤的注解
|
||||
* @param method 操作的方法
|
||||
* @param newMethodName 新的方法名, 可能为null
|
||||
* @return 下一个新的方法名,不做任何处理应返回参数newMethodName
|
||||
*/
|
||||
public abstract String doMethod(
|
||||
ClassLoader classLoader,
|
||||
ClassWriter cw,
|
||||
String newDynName,
|
||||
String fieldPrefix,
|
||||
List<Class<? extends Annotation>> filterAnns,
|
||||
Method method,
|
||||
@Nullable String newMethodName);
|
||||
/**
|
||||
* 对方法进行动态加强处理
|
||||
*
|
||||
* @param classLoader ClassLoader
|
||||
* @param cw 动态字节码Writer
|
||||
* @param newDynName 动态新类名
|
||||
* @param fieldPrefix 动态字段的前缀
|
||||
* @param filterAnns 需要过滤的注解
|
||||
* @param method 操作的方法
|
||||
* @param newMethodName 新的方法名, 可能为null
|
||||
* @return 下一个新的方法名,不做任何处理应返回参数newMethodName
|
||||
*/
|
||||
public abstract String doMethod(
|
||||
ClassLoader classLoader,
|
||||
ClassWriter cw,
|
||||
String newDynName,
|
||||
String fieldPrefix,
|
||||
List<Class<? extends Annotation>> filterAnns,
|
||||
Method method,
|
||||
@Nullable String newMethodName);
|
||||
|
||||
/**
|
||||
* 处理所有动态方法后调用
|
||||
*
|
||||
* @param classLoader ClassLoader
|
||||
* @param cw 动态字节码Writer
|
||||
* @param newDynName 动态新类名
|
||||
* @param fieldPrefix 动态字段的前缀
|
||||
*/
|
||||
public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) {}
|
||||
/**
|
||||
* 处理所有动态方法后调用
|
||||
*
|
||||
* @param classLoader ClassLoader
|
||||
* @param cw 动态字节码Writer
|
||||
* @param newDynName 动态新类名
|
||||
* @param fieldPrefix 动态字段的前缀
|
||||
*/
|
||||
public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) {}
|
||||
|
||||
/**
|
||||
* 实例对象进行操作,通常用于给动态的字段赋值
|
||||
*
|
||||
* @param resourceFactory ResourceFactory
|
||||
* @param service 实例对象
|
||||
*/
|
||||
public abstract void doInstance(ResourceFactory resourceFactory, T service);
|
||||
/**
|
||||
* 实例对象进行操作,通常用于给动态的字段赋值
|
||||
*
|
||||
* @param resourceFactory ResourceFactory
|
||||
* @param service 实例对象
|
||||
*/
|
||||
public abstract void doInstance(ResourceFactory resourceFactory, T service);
|
||||
|
||||
protected AsmMethodBean getMethodBean(Method method) {
|
||||
Map<String, AsmMethodBean> methodBeans = AsmMethodBoost.getMethodBeans(serviceType);
|
||||
return AsmMethodBean.get(methodBeans, method);
|
||||
}
|
||||
protected AsmMethodBean getMethodBean(Method method) {
|
||||
Map<String, AsmMethodBean> methodBeans = AsmMethodBoost.getMethodBeans(serviceType);
|
||||
return AsmMethodBean.get(methodBeans, method);
|
||||
}
|
||||
|
||||
protected MethodVisitor createMethodVisitor(
|
||||
ClassWriter cw, Method method, String newMethodName, AsmMethodBean methodBean) {
|
||||
return new MethodDebugVisitor(cw.visitMethod(
|
||||
getAcc(method, newMethodName),
|
||||
getNowMethodName(method, newMethodName),
|
||||
Type.getMethodDescriptor(method),
|
||||
getMethodSignature(method, methodBean),
|
||||
getMethodExceptions(method, methodBean)));
|
||||
}
|
||||
protected MethodVisitor createMethodVisitor(
|
||||
ClassWriter cw, Method method, String newMethodName, AsmMethodBean methodBean) {
|
||||
return new MethodDebugVisitor(cw.visitMethod(
|
||||
getAcc(method, newMethodName),
|
||||
getNowMethodName(method, newMethodName),
|
||||
Type.getMethodDescriptor(method),
|
||||
getMethodSignature(method, methodBean),
|
||||
getMethodExceptions(method, methodBean)));
|
||||
}
|
||||
|
||||
protected int getAcc(Method method, String newMethodName) {
|
||||
if (newMethodName != null) {
|
||||
return ACC_PRIVATE;
|
||||
}
|
||||
return Modifier.isProtected(method.getModifiers()) ? ACC_PROTECTED : ACC_PUBLIC;
|
||||
}
|
||||
protected int getAcc(Method method, String newMethodName) {
|
||||
if (newMethodName != null) {
|
||||
return ACC_PRIVATE;
|
||||
}
|
||||
return Modifier.isProtected(method.getModifiers()) ? ACC_PROTECTED : ACC_PUBLIC;
|
||||
}
|
||||
|
||||
protected String getNowMethodName(Method method, String newMethodName) {
|
||||
return newMethodName == null ? method.getName() : newMethodName;
|
||||
}
|
||||
protected String getNowMethodName(Method method, String newMethodName) {
|
||||
return newMethodName == null ? method.getName() : newMethodName;
|
||||
}
|
||||
|
||||
protected String getMethodSignature(Method method, AsmMethodBean methodBean) {
|
||||
return methodBean != null ? methodBean.getSignature() : null;
|
||||
}
|
||||
protected String getMethodSignature(Method method, AsmMethodBean methodBean) {
|
||||
return methodBean != null ? methodBean.getSignature() : null;
|
||||
}
|
||||
|
||||
protected String[] getMethodExceptions(Method method, AsmMethodBean methodBean) {
|
||||
if (methodBean == null) {
|
||||
String[] exceptions = null;
|
||||
Class<?>[] expTypes = method.getExceptionTypes();
|
||||
if (expTypes.length > 0) {
|
||||
exceptions = new String[expTypes.length];
|
||||
for (int i = 0; i < expTypes.length; i++) {
|
||||
exceptions[i] = expTypes[i].getName().replace('.', '/');
|
||||
}
|
||||
}
|
||||
return exceptions;
|
||||
} else {
|
||||
return methodBean.getExceptions();
|
||||
}
|
||||
}
|
||||
protected String[] getMethodExceptions(Method method, AsmMethodBean methodBean) {
|
||||
if (methodBean == null) {
|
||||
String[] exceptions = null;
|
||||
Class<?>[] expTypes = method.getExceptionTypes();
|
||||
if (expTypes.length > 0) {
|
||||
exceptions = new String[expTypes.length];
|
||||
for (int i = 0; i < expTypes.length; i++) {
|
||||
exceptions[i] = expTypes[i].getName().replace('.', '/');
|
||||
}
|
||||
}
|
||||
return exceptions;
|
||||
} else {
|
||||
return methodBean.getExceptions();
|
||||
}
|
||||
}
|
||||
|
||||
protected void visitRawAnnotation(
|
||||
Method method, String newMethodName, MethodVisitor mv, Class selfAnnType, List filterAnns) {
|
||||
if (newMethodName == null) {
|
||||
// 给方法加上原有的Annotation
|
||||
final Annotation[] anns = method.getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
if (ann.annotationType() != selfAnnType
|
||||
&& (filterAnns == null || !filterAnns.contains(ann.annotationType()))) {
|
||||
Asms.visitAnnotation(mv.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
|
||||
}
|
||||
}
|
||||
// 给参数加上原有的Annotation
|
||||
final Annotation[][] annss = method.getParameterAnnotations();
|
||||
for (int k = 0; k < annss.length; k++) {
|
||||
for (Annotation ann : annss[k]) {
|
||||
Asms.visitAnnotation(
|
||||
mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
protected void visitRawAnnotation(
|
||||
Method method, String newMethodName, MethodVisitor mv, Class selfAnnType, List filterAnns) {
|
||||
if (newMethodName == null) {
|
||||
// 给方法加上原有的Annotation
|
||||
final Annotation[] anns = method.getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
if (ann.annotationType() != selfAnnType
|
||||
&& (filterAnns == null || !filterAnns.contains(ann.annotationType()))) {
|
||||
Asms.visitAnnotation(mv.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
|
||||
}
|
||||
}
|
||||
// 给参数加上原有的Annotation
|
||||
final Annotation[][] annss = method.getParameterAnnotations();
|
||||
for (int k = 0; k < annss.length; k++) {
|
||||
for (Annotation ann : annss[k]) {
|
||||
Asms.visitAnnotation(
|
||||
mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected List<Integer> visitVarInsnParamTypes(MethodVisitor mv, Method method, int insn) {
|
||||
// 传参数
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
List<Integer> insns = new ArrayList<>();
|
||||
for (Class pt : paramTypes) {
|
||||
insn++;
|
||||
if (pt.isPrimitive()) {
|
||||
if (pt == long.class) {
|
||||
mv.visitVarInsn(LLOAD, insn++);
|
||||
} else if (pt == float.class) {
|
||||
mv.visitVarInsn(FLOAD, insn++);
|
||||
} else if (pt == double.class) {
|
||||
mv.visitVarInsn(DLOAD, insn++);
|
||||
} else {
|
||||
mv.visitVarInsn(ILOAD, insn);
|
||||
}
|
||||
} else {
|
||||
mv.visitVarInsn(ALOAD, insn);
|
||||
}
|
||||
insns.add(insn);
|
||||
}
|
||||
return insns;
|
||||
}
|
||||
protected List<Integer> visitVarInsnParamTypes(MethodVisitor mv, Method method, int insn) {
|
||||
// 传参数
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
List<Integer> insns = new ArrayList<>();
|
||||
for (Class pt : paramTypes) {
|
||||
insn++;
|
||||
if (pt.isPrimitive()) {
|
||||
if (pt == long.class) {
|
||||
mv.visitVarInsn(LLOAD, insn++);
|
||||
} else if (pt == float.class) {
|
||||
mv.visitVarInsn(FLOAD, insn++);
|
||||
} else if (pt == double.class) {
|
||||
mv.visitVarInsn(DLOAD, insn++);
|
||||
} else {
|
||||
mv.visitVarInsn(ILOAD, insn);
|
||||
}
|
||||
} else {
|
||||
mv.visitVarInsn(ALOAD, insn);
|
||||
}
|
||||
insns.add(insn);
|
||||
}
|
||||
return insns;
|
||||
}
|
||||
|
||||
protected void visitParamTypesLocalVariable(
|
||||
MethodVisitor mv, Method method, Label l0, Label l2, List<Integer> insns, AsmMethodBean methodBean) {
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
if (methodBean != null && paramTypes.length > 0) {
|
||||
mv.visitLabel(l2);
|
||||
List<AsmMethodParam> params = methodBean.getParams();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
AsmMethodParam param = params.get(i);
|
||||
mv.visitLocalVariable(
|
||||
param.getName(),
|
||||
param.description(paramTypes[i]),
|
||||
param.signature(paramTypes[i]),
|
||||
l0,
|
||||
l2,
|
||||
insns.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
protected void visitParamTypesLocalVariable(
|
||||
MethodVisitor mv, Method method, Label l0, Label l2, List<Integer> insns, AsmMethodBean methodBean) {
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
if (methodBean != null && paramTypes.length > 0) {
|
||||
mv.visitLabel(l2);
|
||||
List<AsmMethodParam> params = methodBean.getParams();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
AsmMethodParam param = params.get(i);
|
||||
mv.visitLocalVariable(
|
||||
param.getName(),
|
||||
param.description(paramTypes[i]),
|
||||
param.signature(paramTypes[i]),
|
||||
l0,
|
||||
l2,
|
||||
insns.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void visitInsnReturn(
|
||||
MethodVisitor mv, Method method, Label l0, List<Integer> insns, AsmMethodBean methodBean) {
|
||||
if (method.getGenericReturnType() == void.class) {
|
||||
mv.visitInsn(RETURN);
|
||||
} else {
|
||||
Class returnclz = method.getReturnType();
|
||||
if (returnclz.isPrimitive()) {
|
||||
if (returnclz == long.class) {
|
||||
mv.visitInsn(LRETURN);
|
||||
} else if (returnclz == float.class) {
|
||||
mv.visitInsn(FRETURN);
|
||||
} else if (returnclz == double.class) {
|
||||
mv.visitInsn(DRETURN);
|
||||
} else {
|
||||
mv.visitInsn(IRETURN);
|
||||
}
|
||||
} else {
|
||||
mv.visitInsn(ARETURN);
|
||||
}
|
||||
}
|
||||
visitParamTypesLocalVariable(mv, method, l0, new Label(), insns, methodBean);
|
||||
}
|
||||
protected void visitInsnReturn(
|
||||
MethodVisitor mv, Method method, Label l0, List<Integer> insns, AsmMethodBean methodBean) {
|
||||
if (method.getGenericReturnType() == void.class) {
|
||||
mv.visitInsn(RETURN);
|
||||
} else {
|
||||
Class returnclz = method.getReturnType();
|
||||
if (returnclz.isPrimitive()) {
|
||||
if (returnclz == long.class) {
|
||||
mv.visitInsn(LRETURN);
|
||||
} else if (returnclz == float.class) {
|
||||
mv.visitInsn(FRETURN);
|
||||
} else if (returnclz == double.class) {
|
||||
mv.visitInsn(DRETURN);
|
||||
} else {
|
||||
mv.visitInsn(IRETURN);
|
||||
}
|
||||
} else {
|
||||
mv.visitInsn(ARETURN);
|
||||
}
|
||||
}
|
||||
visitParamTypesLocalVariable(mv, method, l0, new Label(), insns, methodBean);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生产动态字节码的方法扩展器, 可以进行方法加强动作
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @since 2.8.0
|
||||
*/
|
||||
static class AsmMethodBoosts<T> extends AsmMethodBoost<T> {
|
||||
/**
|
||||
* 生产动态字节码的方法扩展器, 可以进行方法加强动作
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @since 2.8.0
|
||||
*/
|
||||
static class AsmMethodBoosts<T> extends AsmMethodBoost<T> {
|
||||
|
||||
private final AsmMethodBoost[] items;
|
||||
private final AsmMethodBoost[] items;
|
||||
|
||||
public AsmMethodBoosts(boolean remote, Collection<AsmMethodBoost> list) {
|
||||
super(remote, null);
|
||||
this.items = list.toArray(new AsmMethodBoost[list.size()]);
|
||||
}
|
||||
public AsmMethodBoosts(boolean remote, Collection<AsmMethodBoost> list) {
|
||||
super(remote, null);
|
||||
this.items = list.toArray(new AsmMethodBoost[list.size()]);
|
||||
}
|
||||
|
||||
public AsmMethodBoosts(boolean remote, AsmMethodBoost... items) {
|
||||
super(remote, null);
|
||||
this.items = items;
|
||||
}
|
||||
public AsmMethodBoosts(boolean remote, AsmMethodBoost... items) {
|
||||
super(remote, null);
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Annotation>> filterMethodAnnotations(Method method) {
|
||||
List<Class<? extends Annotation>> list = null;
|
||||
for (AsmMethodBoost item : items) {
|
||||
if (item != null) {
|
||||
List<Class<? extends Annotation>> sub = item.filterMethodAnnotations(method);
|
||||
if (sub != null) {
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
list.addAll(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@Override
|
||||
public List<Class<? extends Annotation>> filterMethodAnnotations(Method method) {
|
||||
List<Class<? extends Annotation>> list = null;
|
||||
for (AsmMethodBoost item : items) {
|
||||
if (item != null) {
|
||||
List<Class<? extends Annotation>> sub = item.filterMethodAnnotations(method);
|
||||
if (sub != null) {
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
list.addAll(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String doMethod(
|
||||
ClassLoader classLoader,
|
||||
ClassWriter cw,
|
||||
String newDynName,
|
||||
String fieldPrefix,
|
||||
List<Class<? extends Annotation>> filterAnns,
|
||||
Method method,
|
||||
String newMethodName) {
|
||||
String newName = newMethodName;
|
||||
for (AsmMethodBoost item : items) {
|
||||
if (item != null) {
|
||||
newName = item.doMethod(classLoader, cw, newDynName, fieldPrefix, filterAnns, method, newName);
|
||||
}
|
||||
}
|
||||
return newName;
|
||||
}
|
||||
@Override
|
||||
public String doMethod(
|
||||
ClassLoader classLoader,
|
||||
ClassWriter cw,
|
||||
String newDynName,
|
||||
String fieldPrefix,
|
||||
List<Class<? extends Annotation>> filterAnns,
|
||||
Method method,
|
||||
String newMethodName) {
|
||||
String newName = newMethodName;
|
||||
for (AsmMethodBoost item : items) {
|
||||
if (item != null) {
|
||||
newName = item.doMethod(classLoader, cw, newDynName, fieldPrefix, filterAnns, method, newName);
|
||||
}
|
||||
}
|
||||
return newName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) {
|
||||
for (AsmMethodBoost item : items) {
|
||||
if (item != null) {
|
||||
item.doAfterMethods(classLoader, cw, newDynName, fieldPrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) {
|
||||
for (AsmMethodBoost item : items) {
|
||||
if (item != null) {
|
||||
item.doAfterMethods(classLoader, cw, newDynName, fieldPrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doInstance(ResourceFactory resourceFactory, T service) {
|
||||
for (AsmMethodBoost item : items) {
|
||||
if (item != null) {
|
||||
item.doInstance(resourceFactory, service);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void doInstance(ResourceFactory resourceFactory, T service) {
|
||||
for (AsmMethodBoost item : items) {
|
||||
if (item != null) {
|
||||
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) {
|
||||
super(api);
|
||||
this.serviceType = serviceType;
|
||||
this.methodBeanMap = methodBeanMap;
|
||||
}
|
||||
public MethodParamClassVisitor(int api, Class serviceType, final Map<String, AsmMethodBean> methodBeanMap) {
|
||||
super(api);
|
||||
this.serviceType = serviceType;
|
||||
this.methodBeanMap = methodBeanMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(
|
||||
int methodAccess,
|
||||
String methodName,
|
||||
String methodDesc,
|
||||
String methodSignature,
|
||||
String[] methodExceptions) {
|
||||
super.visitMethod(api, methodName, methodDesc, methodSignature, methodExceptions);
|
||||
if (java.lang.reflect.Modifier.isStatic(methodAccess)) {
|
||||
return null;
|
||||
}
|
||||
String key = methodName + ":" + methodDesc;
|
||||
if (methodBeanMap.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
AsmMethodBean bean =
|
||||
new AsmMethodBean(methodAccess, methodName, methodDesc, methodSignature, methodExceptions);
|
||||
List<AsmMethodParam> paramList = bean.getParams();
|
||||
methodBeanMap.put(key, bean);
|
||||
return new MethodVisitor(Opcodes.ASM6) {
|
||||
@Override
|
||||
public void visitParameter(String paramName, int paramAccess) {
|
||||
paramList.add(new AsmMethodParam(paramName));
|
||||
}
|
||||
@Override
|
||||
public MethodVisitor visitMethod(
|
||||
int methodAccess,
|
||||
String methodName,
|
||||
String methodDesc,
|
||||
String methodSignature,
|
||||
String[] methodExceptions) {
|
||||
super.visitMethod(api, methodName, methodDesc, methodSignature, methodExceptions);
|
||||
if (java.lang.reflect.Modifier.isStatic(methodAccess)) {
|
||||
return null;
|
||||
}
|
||||
String key = methodName + ":" + methodDesc;
|
||||
if (methodBeanMap.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
AsmMethodBean bean =
|
||||
new AsmMethodBean(methodAccess, methodName, methodDesc, methodSignature, methodExceptions);
|
||||
List<AsmMethodParam> paramList = bean.getParams();
|
||||
methodBeanMap.put(key, bean);
|
||||
return new MethodVisitor(Opcodes.ASM6) {
|
||||
@Override
|
||||
public void visitParameter(String paramName, int paramAccess) {
|
||||
paramList.add(new AsmMethodParam(paramName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(
|
||||
String varName, String varDesc, String varSignature, Label start, Label end, int varIndex) {
|
||||
if (varIndex < 1) {
|
||||
return;
|
||||
}
|
||||
int size = paramList.size();
|
||||
// index并不会按顺序执行
|
||||
if (varIndex > size) {
|
||||
for (int i = size; i < varIndex; i++) {
|
||||
paramList.add(new AsmMethodParam(" ", varDesc, varSignature));
|
||||
}
|
||||
paramList.set(varIndex - 1, new AsmMethodParam(varName, varDesc, varSignature));
|
||||
}
|
||||
paramList.set(varIndex - 1, new AsmMethodParam(varName, varDesc, varSignature));
|
||||
}
|
||||
};
|
||||
}
|
||||
@Override
|
||||
public void visitLocalVariable(
|
||||
String varName, String varDesc, String varSignature, Label start, Label end, int varIndex) {
|
||||
if (varIndex < 1) {
|
||||
return;
|
||||
}
|
||||
int size = paramList.size();
|
||||
// index并不会按顺序执行
|
||||
if (varIndex > size) {
|
||||
for (int i = size; i < varIndex; i++) {
|
||||
paramList.add(new AsmMethodParam(" ", varDesc, varSignature));
|
||||
}
|
||||
paramList.set(varIndex - 1, new AsmMethodParam(varName, varDesc, varSignature));
|
||||
}
|
||||
paramList.set(varIndex - 1, new AsmMethodParam(varName, varDesc, varSignature));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 返回的List中参数列表可能会比方法参数量多,因为方法内的临时变量也会存入list中, 所以需要list的元素集合比方法的参数多
|
||||
static Map<String, AsmMethodBean> getMethodParamNames(Map<String, AsmMethodBean> map, Class clazz) {
|
||||
String n = clazz.getName();
|
||||
InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class");
|
||||
if (in == null) {
|
||||
return map;
|
||||
}
|
||||
try {
|
||||
new ClassReader(Utility.readBytesThenClose(in))
|
||||
.accept(new MethodParamClassVisitor(Opcodes.ASM6, clazz, map), 0);
|
||||
} catch (Exception e) { // 无需理会
|
||||
}
|
||||
Class superClass = clazz.getSuperclass();
|
||||
if (superClass == null || superClass == Object.class) { // 接口的getSuperclass为null
|
||||
return map;
|
||||
}
|
||||
return getMethodParamNames(map, superClass);
|
||||
}
|
||||
}
|
||||
// 返回的List中参数列表可能会比方法参数量多,因为方法内的临时变量也会存入list中, 所以需要list的元素集合比方法的参数多
|
||||
static Map<String, AsmMethodBean> getMethodParamNames(Map<String, AsmMethodBean> map, Class clazz) {
|
||||
String n = clazz.getName();
|
||||
InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class");
|
||||
if (in == null) {
|
||||
return map;
|
||||
}
|
||||
try {
|
||||
new ClassReader(Utility.readBytesThenClose(in))
|
||||
.accept(new MethodParamClassVisitor(Opcodes.ASM6, clazz, map), 0);
|
||||
} catch (Exception e) { // 无需理会
|
||||
}
|
||||
Class superClass = clazz.getSuperclass();
|
||||
if (superClass == null || superClass == Object.class) { // 接口的getSuperclass为null
|
||||
return map;
|
||||
}
|
||||
return getMethodParamNames(map, superClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,58 +15,58 @@ import org.redkale.util.TypeToken;
|
||||
*/
|
||||
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) {
|
||||
this.name = name;
|
||||
}
|
||||
public AsmMethodParam(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public AsmMethodParam(String name, String description, String signature) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.signature = signature;
|
||||
}
|
||||
public AsmMethodParam(String name, String description, String signature) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public String description(java.lang.reflect.Type type) {
|
||||
return description == null ? Type.getDescriptor(TypeToken.typeToClass(type)) : description;
|
||||
}
|
||||
public String description(java.lang.reflect.Type type) {
|
||||
return description == null ? Type.getDescriptor(TypeToken.typeToClass(type)) : description;
|
||||
}
|
||||
|
||||
public String signature(java.lang.reflect.Type type) {
|
||||
return signature;
|
||||
}
|
||||
public String signature(java.lang.reflect.Type type) {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(String signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
public void setSignature(String signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,173 +25,173 @@ import org.redkale.util.RedkaleException;
|
||||
*/
|
||||
public final class Asms {
|
||||
|
||||
private Asms() {}
|
||||
private Asms() {}
|
||||
|
||||
public static Handle createLambdaMetaHandle() {
|
||||
return new Handle(
|
||||
Opcodes.H_INVOKESTATIC,
|
||||
"java/lang/invoke/LambdaMetafactory",
|
||||
"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;",
|
||||
false);
|
||||
}
|
||||
public static Handle createLambdaMetaHandle() {
|
||||
return new Handle(
|
||||
Opcodes.H_INVOKESTATIC,
|
||||
"java/lang/invoke/LambdaMetafactory",
|
||||
"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;",
|
||||
false);
|
||||
}
|
||||
|
||||
public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) {
|
||||
try {
|
||||
for (Method anm : ann.annotationType().getMethods()) {
|
||||
final String mname = anm.getName();
|
||||
if ("equals".equals(mname)
|
||||
|| "hashCode".equals(mname)
|
||||
|| "toString".equals(mname)
|
||||
|| "annotationType".equals(mname)) {
|
||||
continue;
|
||||
}
|
||||
final Object r = anm.invoke(ann);
|
||||
if (r instanceof String[]) {
|
||||
AnnotationVisitor av1 = av.visitArray(mname);
|
||||
for (String item : (String[]) r) {
|
||||
av1.visit(null, item);
|
||||
}
|
||||
av1.visitEnd();
|
||||
} else if (r instanceof Class[]) {
|
||||
AnnotationVisitor av1 = av.visitArray(mname);
|
||||
for (Class item : (Class[]) r) {
|
||||
av1.visit(null, Type.getType(item));
|
||||
}
|
||||
av1.visitEnd();
|
||||
} else if (r instanceof Enum[]) {
|
||||
AnnotationVisitor av1 = av.visitArray(mname);
|
||||
for (Enum item : (Enum[]) r) {
|
||||
av1.visitEnum(null, Type.getDescriptor(item.getClass()), ((Enum) item).name());
|
||||
}
|
||||
av1.visitEnd();
|
||||
} else if (r instanceof Annotation[]) {
|
||||
AnnotationVisitor av1 = av.visitArray(mname);
|
||||
for (Annotation item : (Annotation[]) r) {
|
||||
visitAnnotation(
|
||||
av1.visitAnnotation(null, Type.getDescriptor(((Annotation) item).annotationType())),
|
||||
item);
|
||||
}
|
||||
av1.visitEnd();
|
||||
} else if (r instanceof Class) {
|
||||
av.visit(mname, Type.getType((Class) r));
|
||||
} else if (r instanceof Enum) {
|
||||
av.visitEnum(mname, Type.getDescriptor(r.getClass()), ((Enum) r).name());
|
||||
} else if (r instanceof Annotation) {
|
||||
visitAnnotation(
|
||||
av.visitAnnotation(null, Type.getDescriptor(((Annotation) r).annotationType())),
|
||||
(Annotation) r);
|
||||
} else {
|
||||
av.visit(mname, r);
|
||||
}
|
||||
}
|
||||
av.visitEnd();
|
||||
} catch (Exception e) {
|
||||
throw new RedkaleException(e);
|
||||
}
|
||||
}
|
||||
public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) {
|
||||
try {
|
||||
for (Method anm : ann.annotationType().getMethods()) {
|
||||
final String mname = anm.getName();
|
||||
if ("equals".equals(mname)
|
||||
|| "hashCode".equals(mname)
|
||||
|| "toString".equals(mname)
|
||||
|| "annotationType".equals(mname)) {
|
||||
continue;
|
||||
}
|
||||
final Object r = anm.invoke(ann);
|
||||
if (r instanceof String[]) {
|
||||
AnnotationVisitor av1 = av.visitArray(mname);
|
||||
for (String item : (String[]) r) {
|
||||
av1.visit(null, item);
|
||||
}
|
||||
av1.visitEnd();
|
||||
} else if (r instanceof Class[]) {
|
||||
AnnotationVisitor av1 = av.visitArray(mname);
|
||||
for (Class item : (Class[]) r) {
|
||||
av1.visit(null, Type.getType(item));
|
||||
}
|
||||
av1.visitEnd();
|
||||
} else if (r instanceof Enum[]) {
|
||||
AnnotationVisitor av1 = av.visitArray(mname);
|
||||
for (Enum item : (Enum[]) r) {
|
||||
av1.visitEnum(null, Type.getDescriptor(item.getClass()), ((Enum) item).name());
|
||||
}
|
||||
av1.visitEnd();
|
||||
} else if (r instanceof Annotation[]) {
|
||||
AnnotationVisitor av1 = av.visitArray(mname);
|
||||
for (Annotation item : (Annotation[]) r) {
|
||||
visitAnnotation(
|
||||
av1.visitAnnotation(null, Type.getDescriptor(((Annotation) item).annotationType())),
|
||||
item);
|
||||
}
|
||||
av1.visitEnd();
|
||||
} else if (r instanceof Class) {
|
||||
av.visit(mname, Type.getType((Class) r));
|
||||
} else if (r instanceof Enum) {
|
||||
av.visitEnum(mname, Type.getDescriptor(r.getClass()), ((Enum) r).name());
|
||||
} else if (r instanceof Annotation) {
|
||||
visitAnnotation(
|
||||
av.visitAnnotation(null, Type.getDescriptor(((Annotation) r).annotationType())),
|
||||
(Annotation) r);
|
||||
} else {
|
||||
av.visit(mname, r);
|
||||
}
|
||||
}
|
||||
av.visitEnd();
|
||||
} catch (Exception e) {
|
||||
throw new RedkaleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void visitInsn(MethodVisitor mv, int num) {
|
||||
if (num < 6) {
|
||||
mv.visitInsn(ICONST_0 + num);
|
||||
} else if (num <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, num);
|
||||
} else if (num <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, num);
|
||||
} else {
|
||||
mv.visitLdcInsn(num);
|
||||
}
|
||||
}
|
||||
public static void visitInsn(MethodVisitor mv, int num) {
|
||||
if (num < 6) {
|
||||
mv.visitInsn(ICONST_0 + num);
|
||||
} else if (num <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(BIPUSH, num);
|
||||
} else if (num <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(SIPUSH, num);
|
||||
} else {
|
||||
mv.visitLdcInsn(num);
|
||||
}
|
||||
}
|
||||
|
||||
public static void visitFieldInsn(MethodVisitor mv, Class clazz) {
|
||||
if (clazz == boolean.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
|
||||
} else if (clazz == byte.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;");
|
||||
} else if (clazz == char.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;");
|
||||
} else if (clazz == short.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;");
|
||||
} else if (clazz == int.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
|
||||
} else if (clazz == float.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;");
|
||||
} else if (clazz == long.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;");
|
||||
} else if (clazz == double.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;");
|
||||
} else {
|
||||
mv.visitLdcInsn(Type.getType(Type.getDescriptor(clazz)));
|
||||
}
|
||||
}
|
||||
public static void visitFieldInsn(MethodVisitor mv, Class clazz) {
|
||||
if (clazz == boolean.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
|
||||
} else if (clazz == byte.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;");
|
||||
} else if (clazz == char.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;");
|
||||
} else if (clazz == short.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;");
|
||||
} else if (clazz == int.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
|
||||
} else if (clazz == float.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;");
|
||||
} else if (clazz == long.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;");
|
||||
} else if (clazz == double.class) {
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;");
|
||||
} else {
|
||||
mv.visitLdcInsn(Type.getType(Type.getDescriptor(clazz)));
|
||||
}
|
||||
}
|
||||
|
||||
public static void visitPrimitiveValueOf(MethodVisitor mv, Class clazz) {
|
||||
if (clazz == boolean.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
|
||||
} else if (clazz == byte.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
|
||||
} else if (clazz == short.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
|
||||
} else if (clazz == char.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
|
||||
} else if (clazz == int.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
|
||||
} else if (clazz == float.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
|
||||
} else if (clazz == long.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
|
||||
} else if (clazz == double.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
|
||||
}
|
||||
}
|
||||
public static void visitPrimitiveValueOf(MethodVisitor mv, Class clazz) {
|
||||
if (clazz == boolean.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
|
||||
} else if (clazz == byte.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
|
||||
} else if (clazz == short.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
|
||||
} else if (clazz == char.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
|
||||
} else if (clazz == int.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
|
||||
} else if (clazz == float.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
|
||||
} else if (clazz == long.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
|
||||
} else if (clazz == double.class) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void visitCheckCast(MethodVisitor mv, Class clazz) {
|
||||
if (clazz == boolean.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
|
||||
} else if (clazz == byte.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
|
||||
} else if (clazz == short.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
|
||||
} else if (clazz == char.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
|
||||
} else if (clazz == int.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
|
||||
} else if (clazz == float.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
|
||||
} else if (clazz == long.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
|
||||
} else if (clazz == double.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
|
||||
} else {
|
||||
mv.visitTypeInsn(CHECKCAST, clazz.getName().replace('.', '/'));
|
||||
}
|
||||
}
|
||||
public static void visitCheckCast(MethodVisitor mv, Class clazz) {
|
||||
if (clazz == boolean.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
|
||||
} else if (clazz == byte.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
|
||||
} else if (clazz == short.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
|
||||
} else if (clazz == char.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
|
||||
} else if (clazz == int.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
|
||||
} else if (clazz == float.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
|
||||
} else if (clazz == long.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
|
||||
} else if (clazz == double.class) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
|
||||
} else {
|
||||
mv.visitTypeInsn(CHECKCAST, clazz.getName().replace('.', '/'));
|
||||
}
|
||||
}
|
||||
|
||||
public static void visitPrimitiveVirtual(MethodVisitor mv, Class clazz) {
|
||||
if (clazz == boolean.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
|
||||
} else if (clazz == byte.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
|
||||
} else if (clazz == short.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
|
||||
} else if (clazz == char.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
|
||||
} else if (clazz == int.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
|
||||
} else if (clazz == float.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
|
||||
} else if (clazz == long.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
|
||||
} else if (clazz == double.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
|
||||
}
|
||||
}
|
||||
public static void visitPrimitiveVirtual(MethodVisitor mv, Class clazz) {
|
||||
if (clazz == boolean.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
|
||||
} else if (clazz == byte.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
|
||||
} else if (clazz == short.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
|
||||
} else if (clazz == char.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
|
||||
} else if (clazz == int.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
|
||||
} else if (clazz == float.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
|
||||
} else if (clazz == long.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
|
||||
} else if (clazz == double.class) {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,245 +68,245 @@ import java.util.Arrays;
|
||||
*/
|
||||
public class Attribute {
|
||||
|
||||
/** The type of this attribute. */
|
||||
public final String type;
|
||||
/** The type of this attribute. */
|
||||
public final String type;
|
||||
|
||||
/** The raw value of this attribute, used only for unknown attributes. */
|
||||
byte[] value;
|
||||
/** The raw value of this attribute, used only for unknown attributes. */
|
||||
byte[] value;
|
||||
|
||||
/** The next attribute in this attribute list. May be <tt>null</tt>. */
|
||||
Attribute next;
|
||||
/** The next attribute in this attribute list. May be <tt>null</tt>. */
|
||||
Attribute next;
|
||||
|
||||
/**
|
||||
* Constructs a new empty attribute.
|
||||
*
|
||||
* @param type the type of the attribute.
|
||||
*/
|
||||
protected Attribute(final String type) {
|
||||
this.type = type;
|
||||
}
|
||||
/**
|
||||
* Constructs a new empty attribute.
|
||||
*
|
||||
* @param type the type of the attribute.
|
||||
*/
|
||||
protected Attribute(final String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if this type of attribute is unknown. The default implementation of this
|
||||
* method always returns <tt>true</tt>.
|
||||
*
|
||||
* @return <tt>true</tt> if this type of attribute is unknown.
|
||||
*/
|
||||
public boolean isUnknown() {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Returns <tt>true</tt> if this type of attribute is unknown. The default implementation of this
|
||||
* method always returns <tt>true</tt>.
|
||||
*
|
||||
* @return <tt>true</tt> if this type of attribute is unknown.
|
||||
*/
|
||||
public boolean isUnknown() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if this type of attribute is a code attribute.
|
||||
*
|
||||
* @return <tt>true</tt> if this type of attribute is a code attribute.
|
||||
*/
|
||||
public boolean isCodeAttribute() {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns <tt>true</tt> if this type of attribute is a code attribute.
|
||||
*
|
||||
* @return <tt>true</tt> if this type of attribute is a code attribute.
|
||||
*/
|
||||
public boolean isCodeAttribute() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the labels corresponding to this attribute.
|
||||
*
|
||||
* @return the labels corresponding to this attribute, or <tt>null</tt> if this attribute is not a
|
||||
* code attribute that contains labels.
|
||||
*/
|
||||
protected Label[] getLabels() {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Returns the labels corresponding to this attribute.
|
||||
*
|
||||
* @return the labels corresponding to this attribute, or <tt>null</tt> if this attribute is not a
|
||||
* code attribute that contains labels.
|
||||
*/
|
||||
protected Label[] getLabels() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a {@link #type type} attribute. This method must return a <i>new</i> {@link Attribute} object, of type
|
||||
* {@link #type type}, corresponding to the <tt>len</tt> bytes starting at the given offset, in the
|
||||
* given class reader.
|
||||
*
|
||||
* @param cr the class that contains the attribute to be read.
|
||||
* @param off index of the first byte of the attribute's content in {@link ClassReader#b cr.b}. The 6 attribute
|
||||
* header bytes, containing the type and the length of the attribute, are not taken into account here.
|
||||
* @param len the length of the attribute's content.
|
||||
* @param buf buffer to be used to call {@link ClassReader#readUTF8 readUTF8},
|
||||
* {@link ClassReader#readClass(int,char[]) readClass} or {@link ClassReader#readConst readConst}.
|
||||
* @param codeOff index of the first byte of code's attribute content in {@link ClassReader#b cr.b}, or -1 if the
|
||||
* attribute to be read is not a code attribute. The 6 attribute header bytes, containing the type and the
|
||||
* length of the attribute, are not taken into account here.
|
||||
* @param labels the labels of the method's code, or <tt>null</tt> if the attribute to be read is
|
||||
* not a code attribute.
|
||||
* @return a <i>new</i> {@link Attribute} object corresponding to the given bytes.
|
||||
*/
|
||||
protected Attribute read(
|
||||
final ClassReader cr,
|
||||
final int off,
|
||||
final int len,
|
||||
final char[] buf,
|
||||
final int codeOff,
|
||||
final Label[] labels) {
|
||||
Attribute attr = new Attribute(type);
|
||||
attr.value = new byte[len];
|
||||
System.arraycopy(cr.b, off, attr.value, 0, len);
|
||||
return attr;
|
||||
}
|
||||
/**
|
||||
* Reads a {@link #type type} attribute. This method must return a <i>new</i> {@link Attribute} object, of type
|
||||
* {@link #type type}, corresponding to the <tt>len</tt> bytes starting at the given offset, in the
|
||||
* given class reader.
|
||||
*
|
||||
* @param cr the class that contains the attribute to be read.
|
||||
* @param off index of the first byte of the attribute's content in {@link ClassReader#b cr.b}. The 6 attribute
|
||||
* header bytes, containing the type and the length of the attribute, are not taken into account here.
|
||||
* @param len the length of the attribute's content.
|
||||
* @param buf buffer to be used to call {@link ClassReader#readUTF8 readUTF8},
|
||||
* {@link ClassReader#readClass(int,char[]) readClass} or {@link ClassReader#readConst readConst}.
|
||||
* @param codeOff index of the first byte of code's attribute content in {@link ClassReader#b cr.b}, or -1 if the
|
||||
* attribute to be read is not a code attribute. The 6 attribute header bytes, containing the type and the
|
||||
* length of the attribute, are not taken into account here.
|
||||
* @param labels the labels of the method's code, or <tt>null</tt> if the attribute to be read is
|
||||
* not a code attribute.
|
||||
* @return a <i>new</i> {@link Attribute} object corresponding to the given bytes.
|
||||
*/
|
||||
protected Attribute read(
|
||||
final ClassReader cr,
|
||||
final int off,
|
||||
final int len,
|
||||
final char[] buf,
|
||||
final int codeOff,
|
||||
final Label[] labels) {
|
||||
Attribute attr = new Attribute(type);
|
||||
attr.value = new byte[len];
|
||||
System.arraycopy(cr.b, off, attr.value, 0, len);
|
||||
return attr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the byte array form of this attribute.
|
||||
*
|
||||
* @param cw the class to which this attribute must be added. This parameter can be used to add to the constant pool
|
||||
* of this class the items that corresponds to this attribute.
|
||||
* @param code the bytecode of the method corresponding to this code attribute, or <tt>null</tt> if
|
||||
* this attribute is not a code attributes.
|
||||
* @param len the length of the bytecode of the method corresponding to this code attribute, or
|
||||
* <tt>null</tt> if this attribute is not a code attribute.
|
||||
* @param maxStack the maximum stack size of the method corresponding to this code attribute, or -1 if this
|
||||
* attribute is not a code attribute.
|
||||
* @param maxLocals the maximum number of local variables of the method corresponding to this code attribute, or -1
|
||||
* if this attribute is not a code attribute.
|
||||
* @return the byte array form of this attribute.
|
||||
*/
|
||||
protected ByteVector write(
|
||||
final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) {
|
||||
ByteVector v = new ByteVector();
|
||||
v.data = value;
|
||||
v.length = value.length;
|
||||
return v;
|
||||
}
|
||||
/**
|
||||
* Returns the byte array form of this attribute.
|
||||
*
|
||||
* @param cw the class to which this attribute must be added. This parameter can be used to add to the constant pool
|
||||
* of this class the items that corresponds to this attribute.
|
||||
* @param code the bytecode of the method corresponding to this code attribute, or <tt>null</tt> if
|
||||
* this attribute is not a code attributes.
|
||||
* @param len the length of the bytecode of the method corresponding to this code attribute, or
|
||||
* <tt>null</tt> if this attribute is not a code attribute.
|
||||
* @param maxStack the maximum stack size of the method corresponding to this code attribute, or -1 if this
|
||||
* attribute is not a code attribute.
|
||||
* @param maxLocals the maximum number of local variables of the method corresponding to this code attribute, or -1
|
||||
* if this attribute is not a code attribute.
|
||||
* @return the byte array form of this attribute.
|
||||
*/
|
||||
protected ByteVector write(
|
||||
final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) {
|
||||
ByteVector v = new ByteVector();
|
||||
v.data = value;
|
||||
v.length = value.length;
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the attribute list that begins with this attribute.
|
||||
*
|
||||
* @return the length of the attribute list that begins with this attribute.
|
||||
*/
|
||||
final int getCount() {
|
||||
int count = 0;
|
||||
Attribute attr = this;
|
||||
while (attr != null) {
|
||||
count += 1;
|
||||
attr = attr.next;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
/**
|
||||
* Returns the length of the attribute list that begins with this attribute.
|
||||
*
|
||||
* @return the length of the attribute list that begins with this attribute.
|
||||
*/
|
||||
final int getCount() {
|
||||
int count = 0;
|
||||
Attribute attr = this;
|
||||
while (attr != null) {
|
||||
count += 1;
|
||||
attr = attr.next;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of all the attributes in this attribute list.
|
||||
*
|
||||
* @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write}
|
||||
* method.
|
||||
* @param code the bytecode of the method corresponding to these code attributes, or <tt>null</tt>
|
||||
* if these attributes are not code attributes.
|
||||
* @param len the length of the bytecode of the method corresponding to these code attributes, or
|
||||
* <tt>null</tt> if these attributes are not code attributes.
|
||||
* @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these
|
||||
* attributes are not code attributes.
|
||||
* @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or
|
||||
* -1 if these attributes are not code attributes.
|
||||
* @return the size of all the attributes in this attribute list. This size includes the size of the attribute
|
||||
* headers.
|
||||
*/
|
||||
final int getSize(final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) {
|
||||
Attribute attr = this;
|
||||
int size = 0;
|
||||
while (attr != null) {
|
||||
cw.newUTF8(attr.type);
|
||||
size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
|
||||
attr = attr.next;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
/**
|
||||
* Returns the size of all the attributes in this attribute list.
|
||||
*
|
||||
* @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write}
|
||||
* method.
|
||||
* @param code the bytecode of the method corresponding to these code attributes, or <tt>null</tt>
|
||||
* if these attributes are not code attributes.
|
||||
* @param len the length of the bytecode of the method corresponding to these code attributes, or
|
||||
* <tt>null</tt> if these attributes are not code attributes.
|
||||
* @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these
|
||||
* attributes are not code attributes.
|
||||
* @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or
|
||||
* -1 if these attributes are not code attributes.
|
||||
* @return the size of all the attributes in this attribute list. This size includes the size of the attribute
|
||||
* headers.
|
||||
*/
|
||||
final int getSize(final ClassWriter cw, final byte[] code, final int len, final int maxStack, final int maxLocals) {
|
||||
Attribute attr = this;
|
||||
int size = 0;
|
||||
while (attr != null) {
|
||||
cw.newUTF8(attr.type);
|
||||
size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
|
||||
attr = attr.next;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes all the attributes of this attribute list in the given byte vector.
|
||||
*
|
||||
* @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write}
|
||||
* method.
|
||||
* @param code the bytecode of the method corresponding to these code attributes, or <tt>null</tt>
|
||||
* if these attributes are not code attributes.
|
||||
* @param len the length of the bytecode of the method corresponding to these code attributes, or
|
||||
* <tt>null</tt> if these attributes are not code attributes.
|
||||
* @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these
|
||||
* attributes are not code attributes.
|
||||
* @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or
|
||||
* -1 if these attributes are not code attributes.
|
||||
* @param out where the attributes must be written.
|
||||
*/
|
||||
final void put(
|
||||
final ClassWriter cw,
|
||||
final byte[] code,
|
||||
final int len,
|
||||
final int maxStack,
|
||||
final int maxLocals,
|
||||
final ByteVector out) {
|
||||
Attribute attr = this;
|
||||
while (attr != null) {
|
||||
ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
|
||||
out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
|
||||
out.putByteArray(b.data, 0, b.length);
|
||||
attr = attr.next;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Writes all the attributes of this attribute list in the given byte vector.
|
||||
*
|
||||
* @param cw the class writer to be used to convert the attributes into byte arrays, with the {@link #write write}
|
||||
* method.
|
||||
* @param code the bytecode of the method corresponding to these code attributes, or <tt>null</tt>
|
||||
* if these attributes are not code attributes.
|
||||
* @param len the length of the bytecode of the method corresponding to these code attributes, or
|
||||
* <tt>null</tt> if these attributes are not code attributes.
|
||||
* @param maxStack the maximum stack size of the method corresponding to these code attributes, or -1 if these
|
||||
* attributes are not code attributes.
|
||||
* @param maxLocals the maximum number of local variables of the method corresponding to these code attributes, or
|
||||
* -1 if these attributes are not code attributes.
|
||||
* @param out where the attributes must be written.
|
||||
*/
|
||||
final void put(
|
||||
final ClassWriter cw,
|
||||
final byte[] code,
|
||||
final int len,
|
||||
final int maxStack,
|
||||
final int maxLocals,
|
||||
final ByteVector out) {
|
||||
Attribute attr = this;
|
||||
while (attr != null) {
|
||||
ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
|
||||
out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
|
||||
out.putByteArray(b.data, 0, b.length);
|
||||
attr = attr.next;
|
||||
}
|
||||
}
|
||||
|
||||
// The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely
|
||||
// removed.
|
||||
// see also changes in ClassReader.accept.
|
||||
/** */
|
||||
public static class NestMembers extends Attribute {
|
||||
/** */
|
||||
public NestMembers() {
|
||||
super("NestMembers");
|
||||
}
|
||||
// The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely
|
||||
// removed.
|
||||
// see also changes in ClassReader.accept.
|
||||
/** */
|
||||
public static class NestMembers extends Attribute {
|
||||
/** */
|
||||
public NestMembers() {
|
||||
super("NestMembers");
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
String[] classes;
|
||||
byte[] bytes;
|
||||
String[] classes;
|
||||
|
||||
@Override
|
||||
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
|
||||
int offset = off;
|
||||
NestMembers a = new NestMembers();
|
||||
int size = cr.readShort(off);
|
||||
a.classes = new String[size];
|
||||
off += 2;
|
||||
for (int i = 0; i < size; i++) {
|
||||
a.classes[i] = cr.readClass(off, buf);
|
||||
off += 2;
|
||||
}
|
||||
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
|
||||
return a;
|
||||
}
|
||||
@Override
|
||||
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
|
||||
int offset = off;
|
||||
NestMembers a = new NestMembers();
|
||||
int size = cr.readShort(off);
|
||||
a.classes = new String[size];
|
||||
off += 2;
|
||||
for (int i = 0; i < size; i++) {
|
||||
a.classes[i] = cr.readClass(off, buf);
|
||||
off += 2;
|
||||
}
|
||||
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
|
||||
ByteVector v = new ByteVector(bytes.length);
|
||||
v.putShort(classes.length);
|
||||
for (String s : classes) {
|
||||
v.putShort(cw.newClass(s));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
|
||||
ByteVector v = new ByteVector(bytes.length);
|
||||
v.putShort(classes.length);
|
||||
for (String s : classes) {
|
||||
v.putShort(cw.newClass(s));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
/** */
|
||||
public static class NestHost extends Attribute {
|
||||
/** */
|
||||
public static class NestHost extends Attribute {
|
||||
|
||||
byte[] bytes;
|
||||
String clazz;
|
||||
/** */
|
||||
public NestHost() {
|
||||
super("NestHost");
|
||||
}
|
||||
byte[] bytes;
|
||||
String clazz;
|
||||
/** */
|
||||
public NestHost() {
|
||||
super("NestHost");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
|
||||
int offset = off;
|
||||
NestHost a = new NestHost();
|
||||
a.clazz = cr.readClass(off, buf);
|
||||
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
|
||||
return a;
|
||||
}
|
||||
@Override
|
||||
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
|
||||
int offset = off;
|
||||
NestHost a = new NestHost();
|
||||
a.clazz = cr.readClass(off, buf);
|
||||
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
|
||||
ByteVector v = new ByteVector(bytes.length);
|
||||
v.putShort(cw.newClass(clazz));
|
||||
return v;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
|
||||
ByteVector v = new ByteVector(bytes.length);
|
||||
v.putShort(cw.newClass(clazz));
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
static final Attribute[] DEFAULT_ATTRIBUTE_PROTOS = new Attribute[] {new NestMembers(), new NestHost()};
|
||||
static final Attribute[] DEFAULT_ATTRIBUTE_PROTOS = new Attribute[] {new NestMembers(), new NestHost()};
|
||||
}
|
||||
|
||||
@@ -66,266 +66,266 @@ package org.redkale.asm;
|
||||
*/
|
||||
public class ByteVector {
|
||||
|
||||
/** The content of this vector. */
|
||||
byte[] data;
|
||||
/** The content of this vector. */
|
||||
byte[] data;
|
||||
|
||||
/** Actual number of bytes in this vector. */
|
||||
int length;
|
||||
/** Actual number of bytes in this vector. */
|
||||
int length;
|
||||
|
||||
/** Constructs a new {@link ByteVector ByteVector} with a default initial size. */
|
||||
public ByteVector() {
|
||||
data = new byte[64];
|
||||
}
|
||||
/** Constructs a new {@link ByteVector ByteVector} with a default initial size. */
|
||||
public ByteVector() {
|
||||
data = new byte[64];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ByteVector ByteVector} with the given initial size.
|
||||
*
|
||||
* @param initialSize the initial size of the byte vector to be constructed.
|
||||
*/
|
||||
public ByteVector(final int initialSize) {
|
||||
data = new byte[initialSize];
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@link ByteVector ByteVector} with the given initial size.
|
||||
*
|
||||
* @param initialSize the initial size of the byte vector to be constructed.
|
||||
*/
|
||||
public ByteVector(final int initialSize) {
|
||||
data = new byte[initialSize];
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param b a byte.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putByte(final int b) {
|
||||
int length = this.length;
|
||||
if (length + 1 > data.length) {
|
||||
enlarge(1);
|
||||
}
|
||||
data[length++] = (byte) b;
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param b a byte.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putByte(final int b) {
|
||||
int length = this.length;
|
||||
if (length + 1 > data.length) {
|
||||
enlarge(1);
|
||||
}
|
||||
data[length++] = (byte) b;
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param b1 a byte.
|
||||
* @param b2 another byte.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
ByteVector put11(final int b1, final int b2) {
|
||||
int length = this.length;
|
||||
if (length + 2 > data.length) {
|
||||
enlarge(2);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
data[length++] = (byte) b1;
|
||||
data[length++] = (byte) b2;
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param b1 a byte.
|
||||
* @param b2 another byte.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
ByteVector put11(final int b1, final int b2) {
|
||||
int length = this.length;
|
||||
if (length + 2 > data.length) {
|
||||
enlarge(2);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
data[length++] = (byte) b1;
|
||||
data[length++] = (byte) b2;
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a short into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param s a short.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putShort(final int s) {
|
||||
int length = this.length;
|
||||
if (length + 2 > data.length) {
|
||||
enlarge(2);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
data[length++] = (byte) (s >>> 8);
|
||||
data[length++] = (byte) s;
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Puts a short into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param s a short.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putShort(final int s) {
|
||||
int length = this.length;
|
||||
if (length + 2 > data.length) {
|
||||
enlarge(2);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
data[length++] = (byte) (s >>> 8);
|
||||
data[length++] = (byte) s;
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param b a byte.
|
||||
* @param s a short.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
ByteVector put12(final int b, final int s) {
|
||||
int length = this.length;
|
||||
if (length + 3 > data.length) {
|
||||
enlarge(3);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
data[length++] = (byte) b;
|
||||
data[length++] = (byte) (s >>> 8);
|
||||
data[length++] = (byte) s;
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param b a byte.
|
||||
* @param s a short.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
ByteVector put12(final int b, final int s) {
|
||||
int length = this.length;
|
||||
if (length + 3 > data.length) {
|
||||
enlarge(3);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
data[length++] = (byte) b;
|
||||
data[length++] = (byte) (s >>> 8);
|
||||
data[length++] = (byte) s;
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts an int into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param i an int.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putInt(final int i) {
|
||||
int length = this.length;
|
||||
if (length + 4 > data.length) {
|
||||
enlarge(4);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
data[length++] = (byte) (i >>> 24);
|
||||
data[length++] = (byte) (i >>> 16);
|
||||
data[length++] = (byte) (i >>> 8);
|
||||
data[length++] = (byte) i;
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Puts an int into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param i an int.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putInt(final int i) {
|
||||
int length = this.length;
|
||||
if (length + 4 > data.length) {
|
||||
enlarge(4);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
data[length++] = (byte) (i >>> 24);
|
||||
data[length++] = (byte) (i >>> 16);
|
||||
data[length++] = (byte) (i >>> 8);
|
||||
data[length++] = (byte) i;
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a long into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param l a long.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putLong(final long l) {
|
||||
int length = this.length;
|
||||
if (length + 8 > data.length) {
|
||||
enlarge(8);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
int i = (int) (l >>> 32);
|
||||
data[length++] = (byte) (i >>> 24);
|
||||
data[length++] = (byte) (i >>> 16);
|
||||
data[length++] = (byte) (i >>> 8);
|
||||
data[length++] = (byte) i;
|
||||
i = (int) l;
|
||||
data[length++] = (byte) (i >>> 24);
|
||||
data[length++] = (byte) (i >>> 16);
|
||||
data[length++] = (byte) (i >>> 8);
|
||||
data[length++] = (byte) i;
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Puts a long into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param l a long.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putLong(final long l) {
|
||||
int length = this.length;
|
||||
if (length + 8 > data.length) {
|
||||
enlarge(8);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
int i = (int) (l >>> 32);
|
||||
data[length++] = (byte) (i >>> 24);
|
||||
data[length++] = (byte) (i >>> 16);
|
||||
data[length++] = (byte) (i >>> 8);
|
||||
data[length++] = (byte) i;
|
||||
i = (int) l;
|
||||
data[length++] = (byte) (i >>> 24);
|
||||
data[length++] = (byte) (i >>> 16);
|
||||
data[length++] = (byte) (i >>> 8);
|
||||
data[length++] = (byte) i;
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param s a String whose UTF8 encoded length must be less than 65536.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putUTF8(final String s) {
|
||||
int charLength = s.length();
|
||||
if (charLength > 65535) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
int len = length;
|
||||
if (len + 2 + charLength > data.length) {
|
||||
enlarge(2 + charLength);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
// optimistic algorithm: instead of computing the byte length and then
|
||||
// serializing the string (which requires two loops), we assume the byte
|
||||
// length is equal to char length (which is the most frequent case), and
|
||||
// we start serializing the string right away. During the serialization,
|
||||
// if we find that this assumption is wrong, we continue with the
|
||||
// general method.
|
||||
data[len++] = (byte) (charLength >>> 8);
|
||||
data[len++] = (byte) charLength;
|
||||
for (int i = 0; i < charLength; ++i) {
|
||||
char c = s.charAt(i);
|
||||
if (c >= '\001' && c <= '\177') {
|
||||
data[len++] = (byte) c;
|
||||
} else {
|
||||
length = len;
|
||||
return encodeUTF8(s, i, 65535);
|
||||
}
|
||||
}
|
||||
length = len;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param s a String whose UTF8 encoded length must be less than 65536.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putUTF8(final String s) {
|
||||
int charLength = s.length();
|
||||
if (charLength > 65535) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
int len = length;
|
||||
if (len + 2 + charLength > data.length) {
|
||||
enlarge(2 + charLength);
|
||||
}
|
||||
byte[] data = this.data;
|
||||
// optimistic algorithm: instead of computing the byte length and then
|
||||
// serializing the string (which requires two loops), we assume the byte
|
||||
// length is equal to char length (which is the most frequent case), and
|
||||
// we start serializing the string right away. During the serialization,
|
||||
// if we find that this assumption is wrong, we continue with the
|
||||
// general method.
|
||||
data[len++] = (byte) (charLength >>> 8);
|
||||
data[len++] = (byte) charLength;
|
||||
for (int i = 0; i < charLength; ++i) {
|
||||
char c = s.charAt(i);
|
||||
if (c >= '\001' && c <= '\177') {
|
||||
data[len++] = (byte) c;
|
||||
} else {
|
||||
length = len;
|
||||
return encodeUTF8(s, i, 65535);
|
||||
}
|
||||
}
|
||||
length = len;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary. The string
|
||||
* length is encoded in two bytes before the encoded characters, if there is space for that (i.e. if this.length - i
|
||||
* - 2 >= 0).
|
||||
*
|
||||
* @param s the String to encode.
|
||||
* @param i the index of the first character to encode. The previous characters are supposed to have already been
|
||||
* encoded, using only one byte per character.
|
||||
* @param maxByteLength the maximum byte length of the encoded string, including the already encoded characters.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
|
||||
int charLength = s.length();
|
||||
int byteLength = i;
|
||||
char c;
|
||||
for (int j = i; j < charLength; ++j) {
|
||||
c = s.charAt(j);
|
||||
if (c >= '\001' && c <= '\177') {
|
||||
byteLength++;
|
||||
} else if (c > '\u07FF') {
|
||||
byteLength += 3;
|
||||
} else {
|
||||
byteLength += 2;
|
||||
}
|
||||
}
|
||||
if (byteLength > maxByteLength) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
int start = length - i - 2;
|
||||
if (start >= 0) {
|
||||
data[start] = (byte) (byteLength >>> 8);
|
||||
data[start + 1] = (byte) byteLength;
|
||||
}
|
||||
if (length + byteLength - i > data.length) {
|
||||
enlarge(byteLength - i);
|
||||
}
|
||||
int len = length;
|
||||
for (int j = i; j < charLength; ++j) {
|
||||
c = s.charAt(j);
|
||||
if (c >= '\001' && c <= '\177') {
|
||||
data[len++] = (byte) c;
|
||||
} else if (c > '\u07FF') {
|
||||
data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
|
||||
data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
|
||||
data[len++] = (byte) (0x80 | c & 0x3F);
|
||||
} else {
|
||||
data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
|
||||
data[len++] = (byte) (0x80 | c & 0x3F);
|
||||
}
|
||||
}
|
||||
length = len;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if necessary. The string
|
||||
* length is encoded in two bytes before the encoded characters, if there is space for that (i.e. if this.length - i
|
||||
* - 2 >= 0).
|
||||
*
|
||||
* @param s the String to encode.
|
||||
* @param i the index of the first character to encode. The previous characters are supposed to have already been
|
||||
* encoded, using only one byte per character.
|
||||
* @param maxByteLength the maximum byte length of the encoded string, including the already encoded characters.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
|
||||
int charLength = s.length();
|
||||
int byteLength = i;
|
||||
char c;
|
||||
for (int j = i; j < charLength; ++j) {
|
||||
c = s.charAt(j);
|
||||
if (c >= '\001' && c <= '\177') {
|
||||
byteLength++;
|
||||
} else if (c > '\u07FF') {
|
||||
byteLength += 3;
|
||||
} else {
|
||||
byteLength += 2;
|
||||
}
|
||||
}
|
||||
if (byteLength > maxByteLength) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
int start = length - i - 2;
|
||||
if (start >= 0) {
|
||||
data[start] = (byte) (byteLength >>> 8);
|
||||
data[start + 1] = (byte) byteLength;
|
||||
}
|
||||
if (length + byteLength - i > data.length) {
|
||||
enlarge(byteLength - i);
|
||||
}
|
||||
int len = length;
|
||||
for (int j = i; j < charLength; ++j) {
|
||||
c = s.charAt(j);
|
||||
if (c >= '\001' && c <= '\177') {
|
||||
data[len++] = (byte) c;
|
||||
} else if (c > '\u07FF') {
|
||||
data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
|
||||
data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
|
||||
data[len++] = (byte) (0x80 | c & 0x3F);
|
||||
} else {
|
||||
data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
|
||||
data[len++] = (byte) (0x80 | c & 0x3F);
|
||||
}
|
||||
}
|
||||
length = len;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param b an array of bytes. May be <tt>null</tt> to put <tt>len</tt> null bytes
|
||||
* into this byte vector.
|
||||
* @param off index of the fist byte of b that must be copied.
|
||||
* @param len number of bytes of b that must be copied.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putByteArray(final byte[] b, final int off, final int len) {
|
||||
if (length + len > data.length) {
|
||||
enlarge(len);
|
||||
}
|
||||
if (b != null) {
|
||||
System.arraycopy(b, off, data, length, len);
|
||||
}
|
||||
length += len;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if necessary.
|
||||
*
|
||||
* @param b an array of bytes. May be <tt>null</tt> to put <tt>len</tt> null bytes
|
||||
* into this byte vector.
|
||||
* @param off index of the fist byte of b that must be copied.
|
||||
* @param len number of bytes of b that must be copied.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
public ByteVector putByteArray(final byte[] b, final int off, final int len) {
|
||||
if (length + len > data.length) {
|
||||
enlarge(len);
|
||||
}
|
||||
if (b != null) {
|
||||
System.arraycopy(b, off, data, length, len);
|
||||
}
|
||||
length += len;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enlarge this byte vector so that it can receive n more bytes.
|
||||
*
|
||||
* @param size number of additional bytes that this byte vector should be able to receive.
|
||||
*/
|
||||
private void enlarge(final int size) {
|
||||
int length1 = 2 * data.length;
|
||||
int length2 = length + size;
|
||||
byte[] newData = new byte[length1 > length2 ? length1 : length2];
|
||||
System.arraycopy(data, 0, newData, 0, length);
|
||||
data = newData;
|
||||
}
|
||||
/**
|
||||
* Enlarge this byte vector so that it can receive n more bytes.
|
||||
*
|
||||
* @param size number of additional bytes that this byte vector should be able to receive.
|
||||
*/
|
||||
private void enlarge(final int size) {
|
||||
int length1 = 2 * data.length;
|
||||
int length2 = length + size;
|
||||
byte[] newData = new byte[length1 > length2 ? length1 : length2];
|
||||
System.arraycopy(data, 0, newData, 0, length);
|
||||
data = newData;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -70,223 +70,223 @@ package org.redkale.asm;
|
||||
*/
|
||||
public abstract class ClassVisitor {
|
||||
|
||||
/**
|
||||
* The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
protected final int api;
|
||||
/**
|
||||
* The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
/** The class visitor to which this visitor must delegate method calls. May be null. */
|
||||
protected ClassVisitor cv;
|
||||
/** The class visitor to which this visitor must delegate method calls. May be null. */
|
||||
protected ClassVisitor cv;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ClassVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
public ClassVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@link ClassVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
public ClassVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ClassVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
* @param cv the class visitor to which this visitor must delegate method calls. May be null.
|
||||
*/
|
||||
public ClassVisitor(final int api, final ClassVisitor cv) {
|
||||
this.api = api;
|
||||
this.cv = cv;
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@link ClassVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
* @param cv the class visitor to which this visitor must delegate method calls. May be null.
|
||||
*/
|
||||
public ClassVisitor(final int api, final ClassVisitor cv) {
|
||||
this.api = api;
|
||||
this.cv = cv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the header of the class.
|
||||
*
|
||||
* @param version the class version.
|
||||
* @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if the class is
|
||||
* deprecated.
|
||||
* @param name the internal name of the class (see {@link Type#getInternalName() getInternalName}).
|
||||
* @param signature the signature of this class. May be <tt>null</tt> if the class is not a generic
|
||||
* one, and does not extend or implement generic classes or interfaces.
|
||||
* @param superName the internal of name of the super class (see {@link Type#getInternalName() getInternalName}).
|
||||
* For interfaces, the super class is {@link Object}. May be <tt>null</tt>, but only for the
|
||||
* {@link Object} class.
|
||||
* @param interfaces the internal names of the class's interfaces (see {@link Type#getInternalName()
|
||||
* getInternalName}). May be <tt>null</tt>.
|
||||
*/
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
if (cv != null) {
|
||||
cv.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visits the header of the class.
|
||||
*
|
||||
* @param version the class version.
|
||||
* @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if the class is
|
||||
* deprecated.
|
||||
* @param name the internal name of the class (see {@link Type#getInternalName() getInternalName}).
|
||||
* @param signature the signature of this class. May be <tt>null</tt> if the class is not a generic
|
||||
* one, and does not extend or implement generic classes or interfaces.
|
||||
* @param superName the internal of name of the super class (see {@link Type#getInternalName() getInternalName}).
|
||||
* For interfaces, the super class is {@link Object}. May be <tt>null</tt>, but only for the
|
||||
* {@link Object} class.
|
||||
* @param interfaces the internal names of the class's interfaces (see {@link Type#getInternalName()
|
||||
* getInternalName}). May be <tt>null</tt>.
|
||||
*/
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
if (cv != null) {
|
||||
cv.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the source of the class.
|
||||
*
|
||||
* @param source the name of the source file from which the class was compiled. May be
|
||||
* <tt>null</tt>.
|
||||
* @param debug additional debug information to compute the correspondance between source and compiled elements of
|
||||
* the class. May be <tt>null</tt>.
|
||||
*/
|
||||
public void visitSource(String source, String debug) {
|
||||
if (cv != null) {
|
||||
cv.visitSource(source, debug);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visits the source of the class.
|
||||
*
|
||||
* @param source the name of the source file from which the class was compiled. May be
|
||||
* <tt>null</tt>.
|
||||
* @param debug additional debug information to compute the correspondance between source and compiled elements of
|
||||
* the class. May be <tt>null</tt>.
|
||||
*/
|
||||
public void visitSource(String source, String debug) {
|
||||
if (cv != null) {
|
||||
cv.visitSource(source, debug);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit the module corresponding to the class.
|
||||
*
|
||||
* @param name module name
|
||||
* @param access module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
|
||||
* @param version module version or null.
|
||||
* @return a visitor to visit the module values, or <tt>null</tt> if this visitor is not interested
|
||||
* in visiting this module.
|
||||
*/
|
||||
public ModuleVisitor visitModule(String name, int access, String version) {
|
||||
if (api < Opcodes.ASM6) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
if (cv != null) {
|
||||
return cv.visitModule(name, access, version);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Visit the module corresponding to the class.
|
||||
*
|
||||
* @param name module name
|
||||
* @param access module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
|
||||
* @param version module version or null.
|
||||
* @return a visitor to visit the module values, or <tt>null</tt> if this visitor is not interested
|
||||
* in visiting this module.
|
||||
*/
|
||||
public ModuleVisitor visitModule(String name, int access, String version) {
|
||||
if (api < Opcodes.ASM6) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
if (cv != null) {
|
||||
return cv.visitModule(name, access, version);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the enclosing class of the class. This method must be called only if the class has an enclosing class.
|
||||
*
|
||||
* @param owner internal name of the enclosing class of the class.
|
||||
* @param name the name of the method that contains the class, or <tt>null</tt> if the class is not
|
||||
* enclosed in a method of its enclosing class.
|
||||
* @param desc the descriptor of the method that contains the class, or <tt>null</tt> if the class
|
||||
* is not enclosed in a method of its enclosing class.
|
||||
*/
|
||||
public void visitOuterClass(String owner, String name, String desc) {
|
||||
if (cv != null) {
|
||||
cv.visitOuterClass(owner, name, desc);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visits the enclosing class of the class. This method must be called only if the class has an enclosing class.
|
||||
*
|
||||
* @param owner internal name of the enclosing class of the class.
|
||||
* @param name the name of the method that contains the class, or <tt>null</tt> if the class is not
|
||||
* enclosed in a method of its enclosing class.
|
||||
* @param desc the descriptor of the method that contains the class, or <tt>null</tt> if the class
|
||||
* is not enclosed in a method of its enclosing class.
|
||||
*/
|
||||
public void visitOuterClass(String owner, String name, String desc) {
|
||||
if (cv != null) {
|
||||
cv.visitOuterClass(owner, name, desc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation of the class.
|
||||
*
|
||||
* @param desc the class descriptor of the annotation class.
|
||||
* @param visible <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
|
||||
* interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
if (cv != null) {
|
||||
return cv.visitAnnotation(desc, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Visits an annotation of the class.
|
||||
*
|
||||
* @param desc the class descriptor of the annotation class.
|
||||
* @param visible <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
|
||||
* interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
if (cv != null) {
|
||||
return cv.visitAnnotation(desc, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation on a type in the class signature.
|
||||
*
|
||||
* @param typeRef a reference to the annotated type. The sort of this type reference must be
|
||||
* {@link TypeReference#CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
|
||||
* {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
|
||||
* {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See {@link TypeReference}.
|
||||
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
|
||||
* within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param desc the class descriptor of the annotation class.
|
||||
* @param visible <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
|
||||
* interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
|
||||
if (cv != null) {
|
||||
return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Visits an annotation on a type in the class signature.
|
||||
*
|
||||
* @param typeRef a reference to the annotated type. The sort of this type reference must be
|
||||
* {@link TypeReference#CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
|
||||
* {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
|
||||
* {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See {@link TypeReference}.
|
||||
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
|
||||
* within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param desc the class descriptor of the annotation class.
|
||||
* @param visible <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
|
||||
* interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
|
||||
if (cv != null) {
|
||||
return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a non standard attribute of the class.
|
||||
*
|
||||
* @param attr an attribute.
|
||||
*/
|
||||
public void visitAttribute(Attribute attr) {
|
||||
if (cv != null) {
|
||||
cv.visitAttribute(attr);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visits a non standard attribute of the class.
|
||||
*
|
||||
* @param attr an attribute.
|
||||
*/
|
||||
public void visitAttribute(Attribute attr) {
|
||||
if (cv != null) {
|
||||
cv.visitAttribute(attr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits information about an inner class. This inner class is not necessarily a member of the class being visited.
|
||||
*
|
||||
* @param name the internal name of an inner class (see {@link Type#getInternalName() getInternalName}).
|
||||
* @param outerName the internal name of the class to which the inner class belongs (see
|
||||
* {@link Type#getInternalName() getInternalName}). May be <tt>null</tt> for not member classes.
|
||||
* @param innerName the (simple) name of the inner class inside its enclosing class. May be
|
||||
* <tt>null</tt> for anonymous inner classes.
|
||||
* @param access the access flags of the inner class as originally declared in the enclosing class.
|
||||
*/
|
||||
public void visitInnerClass(String name, String outerName, String innerName, int access) {
|
||||
if (cv != null) {
|
||||
cv.visitInnerClass(name, outerName, innerName, access);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visits information about an inner class. This inner class is not necessarily a member of the class being visited.
|
||||
*
|
||||
* @param name the internal name of an inner class (see {@link Type#getInternalName() getInternalName}).
|
||||
* @param outerName the internal name of the class to which the inner class belongs (see
|
||||
* {@link Type#getInternalName() getInternalName}). May be <tt>null</tt> for not member classes.
|
||||
* @param innerName the (simple) name of the inner class inside its enclosing class. May be
|
||||
* <tt>null</tt> for anonymous inner classes.
|
||||
* @param access the access flags of the inner class as originally declared in the enclosing class.
|
||||
*/
|
||||
public void visitInnerClass(String name, String outerName, String innerName, int access) {
|
||||
if (cv != null) {
|
||||
cv.visitInnerClass(name, outerName, innerName, access);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a field of the class.
|
||||
*
|
||||
* @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if the field is
|
||||
* synthetic and/or deprecated.
|
||||
* @param name the field's name.
|
||||
* @param desc the field's descriptor (see {@link Type Type}).
|
||||
* @param signature the field's signature. May be <tt>null</tt> if the field's type does not use
|
||||
* generic types.
|
||||
* @param value the field's initial value. This parameter, which may be <tt>null</tt> if the field
|
||||
* does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}
|
||||
* or a {@link String} (for <tt>int</tt>, <tt>float</tt>,
|
||||
* <tt>long</tt> or <tt>String</tt> fields respectively). <i>This parameter is
|
||||
* only used for static fields</i>. Its value is ignored for non static fields, which must be initialized
|
||||
* through bytecode instructions in constructors or methods.
|
||||
* @return a visitor to visit field annotations and attributes, or <tt>null</tt> if this class
|
||||
* visitor is not interested in visiting these annotations and attributes.
|
||||
*/
|
||||
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
|
||||
if (cv != null) {
|
||||
return cv.visitField(access, name, desc, signature, value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Visits a field of the class.
|
||||
*
|
||||
* @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if the field is
|
||||
* synthetic and/or deprecated.
|
||||
* @param name the field's name.
|
||||
* @param desc the field's descriptor (see {@link Type Type}).
|
||||
* @param signature the field's signature. May be <tt>null</tt> if the field's type does not use
|
||||
* generic types.
|
||||
* @param value the field's initial value. This parameter, which may be <tt>null</tt> if the field
|
||||
* does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}
|
||||
* or a {@link String} (for <tt>int</tt>, <tt>float</tt>,
|
||||
* <tt>long</tt> or <tt>String</tt> fields respectively). <i>This parameter is
|
||||
* only used for static fields</i>. Its value is ignored for non static fields, which must be initialized
|
||||
* through bytecode instructions in constructors or methods.
|
||||
* @return a visitor to visit field annotations and attributes, or <tt>null</tt> if this class
|
||||
* visitor is not interested in visiting these annotations and attributes.
|
||||
*/
|
||||
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
|
||||
if (cv != null) {
|
||||
return cv.visitField(access, name, desc, signature, value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a method of the class. This method <i>must</i> return a new {@link MethodVisitor} instance (or
|
||||
* <tt>null</tt>) each time it is called, i.e., it should not return a previously returned visitor.
|
||||
*
|
||||
* @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if the method is
|
||||
* synthetic and/or deprecated.
|
||||
* @param name the method's name.
|
||||
* @param desc the method's descriptor (see {@link Type Type}).
|
||||
* @param signature the method's signature. May be <tt>null</tt> if the method parameters, return
|
||||
* type and exceptions do not use generic types.
|
||||
* @param exceptions the internal names of the method's exception classes (see {@link Type#getInternalName()
|
||||
* getInternalName}). May be <tt>null</tt>.
|
||||
* @return an object to visit the byte code of the method, or <tt>null</tt> if this class visitor is
|
||||
* not interested in visiting the code of this method.
|
||||
*/
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
if (cv != null) {
|
||||
return cv.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Visits a method of the class. This method <i>must</i> return a new {@link MethodVisitor} instance (or
|
||||
* <tt>null</tt>) each time it is called, i.e., it should not return a previously returned visitor.
|
||||
*
|
||||
* @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if the method is
|
||||
* synthetic and/or deprecated.
|
||||
* @param name the method's name.
|
||||
* @param desc the method's descriptor (see {@link Type Type}).
|
||||
* @param signature the method's signature. May be <tt>null</tt> if the method parameters, return
|
||||
* type and exceptions do not use generic types.
|
||||
* @param exceptions the internal names of the method's exception classes (see {@link Type#getInternalName()
|
||||
* getInternalName}). May be <tt>null</tt>.
|
||||
* @return an object to visit the byte code of the method, or <tt>null</tt> if this class visitor is
|
||||
* not interested in visiting the code of this method.
|
||||
*/
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
if (cv != null) {
|
||||
return cv.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the end of the class. This method, which is the last one to be called, is used to inform the visitor that
|
||||
* all the fields and methods of the class have been visited.
|
||||
*/
|
||||
public void visitEnd() {
|
||||
if (cv != null) {
|
||||
cv.visitEnd();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visits the end of the class. This method, which is the last one to be called, is used to inform the visitor that
|
||||
* all the fields and methods of the class have been visited.
|
||||
*/
|
||||
public void visitEnd() {
|
||||
if (cv != null) {
|
||||
cv.visitEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -66,78 +66,78 @@ package org.redkale.asm;
|
||||
*/
|
||||
class Context {
|
||||
|
||||
/** Prototypes of the attributes that must be parsed for this class. */
|
||||
Attribute[] attrs;
|
||||
/** Prototypes of the attributes that must be parsed for this class. */
|
||||
Attribute[] attrs;
|
||||
|
||||
/** The {@link ClassReader} option flags for the parsing of this class. */
|
||||
int flags;
|
||||
/** The {@link ClassReader} option flags for the parsing of this class. */
|
||||
int flags;
|
||||
|
||||
/** The buffer used to read strings. */
|
||||
char[] buffer;
|
||||
/** The buffer used to read strings. */
|
||||
char[] buffer;
|
||||
|
||||
/** The start index of each bootstrap method. */
|
||||
int[] bootstrapMethods;
|
||||
/** The start index of each bootstrap method. */
|
||||
int[] bootstrapMethods;
|
||||
|
||||
/** The access flags of the method currently being parsed. */
|
||||
int access;
|
||||
/** The access flags of the method currently being parsed. */
|
||||
int access;
|
||||
|
||||
/** The name of the method currently being parsed. */
|
||||
String name;
|
||||
/** The name of the method currently being parsed. */
|
||||
String name;
|
||||
|
||||
/** The descriptor of the method currently being parsed. */
|
||||
String desc;
|
||||
/** The descriptor of the method currently being parsed. */
|
||||
String desc;
|
||||
|
||||
/**
|
||||
* The label objects, indexed by bytecode offset, of the method currently being parsed (only bytecode offsets for
|
||||
* which a label is needed have a non null associated Label object).
|
||||
*/
|
||||
Label[] labels;
|
||||
/**
|
||||
* The label objects, indexed by bytecode offset, of the method currently being parsed (only bytecode offsets for
|
||||
* which a label is needed have a non null associated Label object).
|
||||
*/
|
||||
Label[] labels;
|
||||
|
||||
/** The target of the type annotation currently being parsed. */
|
||||
int typeRef;
|
||||
/** The target of the type annotation currently being parsed. */
|
||||
int typeRef;
|
||||
|
||||
/** The path of the type annotation currently being parsed. */
|
||||
TypePath typePath;
|
||||
/** The path of the type annotation currently being parsed. */
|
||||
TypePath typePath;
|
||||
|
||||
/** The offset of the latest stack map frame that has been parsed. */
|
||||
int offset;
|
||||
/** The offset of the latest stack map frame that has been parsed. */
|
||||
int offset;
|
||||
|
||||
/**
|
||||
* The labels corresponding to the start of the local variable ranges in the local variable type annotation
|
||||
* currently being parsed.
|
||||
*/
|
||||
Label[] start;
|
||||
/**
|
||||
* The labels corresponding to the start of the local variable ranges in the local variable type annotation
|
||||
* currently being parsed.
|
||||
*/
|
||||
Label[] start;
|
||||
|
||||
/**
|
||||
* The labels corresponding to the end of the local variable ranges in the local variable type annotation currently
|
||||
* being parsed.
|
||||
*/
|
||||
Label[] end;
|
||||
/**
|
||||
* The labels corresponding to the end of the local variable ranges in the local variable type annotation currently
|
||||
* being parsed.
|
||||
*/
|
||||
Label[] end;
|
||||
|
||||
/**
|
||||
* The local variable indices for each local variable range in the local variable type annotation currently being
|
||||
* parsed.
|
||||
*/
|
||||
int[] index;
|
||||
/**
|
||||
* The local variable indices for each local variable range in the local variable type annotation currently being
|
||||
* parsed.
|
||||
*/
|
||||
int[] index;
|
||||
|
||||
/** The encoding of the latest stack map frame that has been parsed. */
|
||||
int mode;
|
||||
/** The encoding of the latest stack map frame that has been parsed. */
|
||||
int mode;
|
||||
|
||||
/** The number of locals in the latest stack map frame that has been parsed. */
|
||||
int localCount;
|
||||
/** The number of locals in the latest stack map frame that has been parsed. */
|
||||
int localCount;
|
||||
|
||||
/**
|
||||
* The number locals in the latest stack map frame that has been parsed, minus the number of locals in the previous
|
||||
* frame.
|
||||
*/
|
||||
int localDiff;
|
||||
/**
|
||||
* The number locals in the latest stack map frame that has been parsed, minus the number of locals in the previous
|
||||
* frame.
|
||||
*/
|
||||
int localDiff;
|
||||
|
||||
/** The local values of the latest stack map frame that has been parsed. */
|
||||
Object[] local;
|
||||
/** The local values of the latest stack map frame that has been parsed. */
|
||||
Object[] local;
|
||||
|
||||
/** The stack size of the latest stack map frame that has been parsed. */
|
||||
int stackCount;
|
||||
/** The stack size of the latest stack map frame that has been parsed. */
|
||||
int stackCount;
|
||||
|
||||
/** The stack values of the latest stack map frame that has been parsed. */
|
||||
Object[] stack;
|
||||
/** The stack values of the latest stack map frame that has been parsed. */
|
||||
Object[] stack;
|
||||
}
|
||||
|
||||
@@ -67,17 +67,17 @@ package org.redkale.asm;
|
||||
*/
|
||||
class CurrentFrame extends Frame {
|
||||
|
||||
/**
|
||||
* Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the instruction just
|
||||
* after the given one. It is assumed that the value of this object when this method is called is the stack map
|
||||
* frame status just before the given instruction is executed.
|
||||
*/
|
||||
@Override
|
||||
void execute(int opcode, int arg, ClassWriter cw, Item item) {
|
||||
super.execute(opcode, arg, cw, item);
|
||||
Frame successor = new Frame();
|
||||
merge(cw, successor, 0);
|
||||
set(successor);
|
||||
owner.inputStackTop = 0;
|
||||
}
|
||||
/**
|
||||
* Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the instruction just
|
||||
* after the given one. It is assumed that the value of this object when this method is called is the stack map
|
||||
* frame status just before the given instruction is executed.
|
||||
*/
|
||||
@Override
|
||||
void execute(int opcode, int arg, ClassWriter cw, Item item) {
|
||||
super.execute(opcode, arg, cw, item);
|
||||
Frame successor = new Frame();
|
||||
merge(cw, successor, 0);
|
||||
set(successor);
|
||||
owner.inputStackTop = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,30 +65,30 @@ package org.redkale.asm;
|
||||
*/
|
||||
class Edge {
|
||||
|
||||
/** Denotes a normal control flow graph edge. */
|
||||
static final int NORMAL = 0;
|
||||
/** Denotes a normal control flow graph edge. */
|
||||
static final int NORMAL = 0;
|
||||
|
||||
/**
|
||||
* Denotes a control flow graph edge corresponding to an exception handler. More precisely any {@link Edge} whose
|
||||
* {@link #info} is strictly positive corresponds to an exception handler. The actual value of {@link #info} is the
|
||||
* index, in the {@link ClassWriter} type table, of the exception that is catched.
|
||||
*/
|
||||
static final int EXCEPTION = 0x7FFFFFFF;
|
||||
/**
|
||||
* Denotes a control flow graph edge corresponding to an exception handler. More precisely any {@link Edge} whose
|
||||
* {@link #info} is strictly positive corresponds to an exception handler. The actual value of {@link #info} is the
|
||||
* index, in the {@link ClassWriter} type table, of the exception that is catched.
|
||||
*/
|
||||
static final int EXCEPTION = 0x7FFFFFFF;
|
||||
|
||||
/**
|
||||
* Information about this control flow graph edge. If {@link ClassWriter#COMPUTE_MAXS} is used this field is the
|
||||
* (relative) stack size in the basic block from which this edge originates. This size is equal to the stack size at
|
||||
* the "jump" instruction to which this edge corresponds, relatively to the stack size at the beginning of the
|
||||
* originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used, this field is the kind of this control
|
||||
* flow graph edge (i.e. NORMAL or EXCEPTION).
|
||||
*/
|
||||
int info;
|
||||
/**
|
||||
* Information about this control flow graph edge. If {@link ClassWriter#COMPUTE_MAXS} is used this field is the
|
||||
* (relative) stack size in the basic block from which this edge originates. This size is equal to the stack size at
|
||||
* the "jump" instruction to which this edge corresponds, relatively to the stack size at the beginning of the
|
||||
* originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used, this field is the kind of this control
|
||||
* flow graph edge (i.e. NORMAL or EXCEPTION).
|
||||
*/
|
||||
int info;
|
||||
|
||||
/** The successor block of the basic block from which this edge originates. */
|
||||
Label successor;
|
||||
/** The successor block of the basic block from which this edge originates. */
|
||||
Label successor;
|
||||
|
||||
/**
|
||||
* The next edge in the list of successors of the originating basic block. See {@link Label#successors successors}.
|
||||
*/
|
||||
Edge next;
|
||||
/**
|
||||
* The next edge in the list of successors of the originating basic block. See {@link Label#successors successors}.
|
||||
*/
|
||||
Edge next;
|
||||
}
|
||||
|
||||
@@ -67,89 +67,89 @@ package org.redkale.asm;
|
||||
*/
|
||||
public abstract class FieldVisitor {
|
||||
|
||||
/**
|
||||
* The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
protected final int api;
|
||||
/**
|
||||
* The ASM API version implemented by this visitor. The value of this field must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
/** The field visitor to which this visitor must delegate method calls. May be null. */
|
||||
protected FieldVisitor fv;
|
||||
/** The field visitor to which this visitor must delegate method calls. May be null. */
|
||||
protected FieldVisitor fv;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link FieldVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
public FieldVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@link FieldVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
*/
|
||||
public FieldVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link FieldVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
* @param fv the field visitor to which this visitor must delegate method calls. May be null.
|
||||
*/
|
||||
public FieldVisitor(final int api, final FieldVisitor fv) {
|
||||
this.api = api;
|
||||
this.fv = fv;
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@link FieldVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
* @param fv the field visitor to which this visitor must delegate method calls. May be null.
|
||||
*/
|
||||
public FieldVisitor(final int api, final FieldVisitor fv) {
|
||||
this.api = api;
|
||||
this.fv = fv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation of the field.
|
||||
*
|
||||
* @param desc the class descriptor of the annotation class.
|
||||
* @param visible <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
|
||||
* interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
if (fv != null) {
|
||||
return fv.visitAnnotation(desc, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Visits an annotation of the field.
|
||||
*
|
||||
* @param desc the class descriptor of the annotation class.
|
||||
* @param visible <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
|
||||
* interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
if (fv != null) {
|
||||
return fv.visitAnnotation(desc, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation on the type of the field.
|
||||
*
|
||||
* @param typeRef a reference to the annotated type. The sort of this type reference must be
|
||||
* {@link TypeReference#FIELD FIELD}. See {@link TypeReference}.
|
||||
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
|
||||
* within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param desc the class descriptor of the annotation class.
|
||||
* @param visible <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
|
||||
* interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
|
||||
if (fv != null) {
|
||||
return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Visits an annotation on the type of the field.
|
||||
*
|
||||
* @param typeRef a reference to the annotated type. The sort of this type reference must be
|
||||
* {@link TypeReference#FIELD FIELD}. See {@link TypeReference}.
|
||||
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or static inner type
|
||||
* within 'typeRef'. May be <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param desc the class descriptor of the annotation class.
|
||||
* @param visible <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
|
||||
* interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
|
||||
if (fv != null) {
|
||||
return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a non standard attribute of the field.
|
||||
*
|
||||
* @param attr an attribute.
|
||||
*/
|
||||
public void visitAttribute(Attribute attr) {
|
||||
if (fv != null) {
|
||||
fv.visitAttribute(attr);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visits a non standard attribute of the field.
|
||||
*
|
||||
* @param attr an attribute.
|
||||
*/
|
||||
public void visitAttribute(Attribute attr) {
|
||||
if (fv != null) {
|
||||
fv.visitAttribute(attr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the end of the field. This method, which is the last one to be called, is used to inform the visitor that
|
||||
* all the annotations and attributes of the field have been visited.
|
||||
*/
|
||||
public void visitEnd() {
|
||||
if (fv != null) {
|
||||
fv.visitEnd();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visits the end of the field. This method, which is the last one to be called, is used to inform the visitor that
|
||||
* all the annotations and attributes of the field have been visited.
|
||||
*/
|
||||
public void visitEnd() {
|
||||
if (fv != null) {
|
||||
fv.visitEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,256 +65,256 @@ package org.redkale.asm;
|
||||
*/
|
||||
final class FieldWriter extends FieldVisitor {
|
||||
|
||||
/** The class writer to which this field must be added. */
|
||||
private final ClassWriter cw;
|
||||
/** The class writer to which this field must be added. */
|
||||
private final ClassWriter cw;
|
||||
|
||||
/** Access flags of this field. */
|
||||
private final int access;
|
||||
/** Access flags of this field. */
|
||||
private final int access;
|
||||
|
||||
/** The index of the constant pool item that contains the name of this method. */
|
||||
private final int name;
|
||||
/** The index of the constant pool item that contains the name of this method. */
|
||||
private final int name;
|
||||
|
||||
/** The index of the constant pool item that contains the descriptor of this field. */
|
||||
private final int desc;
|
||||
/** The index of the constant pool item that contains the descriptor of this field. */
|
||||
private final int desc;
|
||||
|
||||
/** The index of the constant pool item that contains the signature of this field. */
|
||||
private int signature;
|
||||
/** The index of the constant pool item that contains the signature of this field. */
|
||||
private int signature;
|
||||
|
||||
/** The index of the constant pool item that contains the constant value of this field. */
|
||||
private int value;
|
||||
/** The index of the constant pool item that contains the constant value of this field. */
|
||||
private int value;
|
||||
|
||||
/** The runtime visible annotations of this field. May be <tt>null</tt>. */
|
||||
private AnnotationWriter anns;
|
||||
/** The runtime visible annotations of this field. May be <tt>null</tt>. */
|
||||
private AnnotationWriter anns;
|
||||
|
||||
/** The runtime invisible annotations of this field. May be <tt>null</tt>. */
|
||||
private AnnotationWriter ianns;
|
||||
/** The runtime invisible annotations of this field. May be <tt>null</tt>. */
|
||||
private AnnotationWriter ianns;
|
||||
|
||||
/** The runtime visible type annotations of this field. May be <tt>null</tt>. */
|
||||
private AnnotationWriter tanns;
|
||||
/** The runtime visible type annotations of this field. May be <tt>null</tt>. */
|
||||
private AnnotationWriter tanns;
|
||||
|
||||
/** The runtime invisible type annotations of this field. May be <tt>null</tt>. */
|
||||
private AnnotationWriter itanns;
|
||||
/** The runtime invisible type annotations of this field. May be <tt>null</tt>. */
|
||||
private AnnotationWriter itanns;
|
||||
|
||||
/** The non standard attributes of this field. May be <tt>null</tt>. */
|
||||
private Attribute attrs;
|
||||
/** The non standard attributes of this field. May be <tt>null</tt>. */
|
||||
private Attribute attrs;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// ------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs a new {@link FieldWriter}.
|
||||
*
|
||||
* @param cw the class writer to which this field must be added.
|
||||
* @param access the field's access flags (see {@link Opcodes}).
|
||||
* @param name the field's name.
|
||||
* @param desc the field's descriptor (see {@link Type}).
|
||||
* @param signature the field's signature. May be <tt>null</tt>.
|
||||
* @param value the field's constant value. May be <tt>null</tt>.
|
||||
*/
|
||||
FieldWriter(
|
||||
final ClassWriter cw,
|
||||
final int access,
|
||||
final String name,
|
||||
final String desc,
|
||||
final String signature,
|
||||
final Object value) {
|
||||
super(Opcodes.ASM6);
|
||||
if (cw.firstField == null) {
|
||||
cw.firstField = this;
|
||||
} else {
|
||||
cw.lastField.fv = this;
|
||||
}
|
||||
cw.lastField = this;
|
||||
this.cw = cw;
|
||||
this.access = access;
|
||||
this.name = cw.newUTF8(name);
|
||||
this.desc = cw.newUTF8(desc);
|
||||
if (signature != null) {
|
||||
this.signature = cw.newUTF8(signature);
|
||||
}
|
||||
if (value != null) {
|
||||
this.value = cw.newConstItem(value).index;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@link FieldWriter}.
|
||||
*
|
||||
* @param cw the class writer to which this field must be added.
|
||||
* @param access the field's access flags (see {@link Opcodes}).
|
||||
* @param name the field's name.
|
||||
* @param desc the field's descriptor (see {@link Type}).
|
||||
* @param signature the field's signature. May be <tt>null</tt>.
|
||||
* @param value the field's constant value. May be <tt>null</tt>.
|
||||
*/
|
||||
FieldWriter(
|
||||
final ClassWriter cw,
|
||||
final int access,
|
||||
final String name,
|
||||
final String desc,
|
||||
final String signature,
|
||||
final Object value) {
|
||||
super(Opcodes.ASM6);
|
||||
if (cw.firstField == null) {
|
||||
cw.firstField = this;
|
||||
} else {
|
||||
cw.lastField.fv = this;
|
||||
}
|
||||
cw.lastField = this;
|
||||
this.cw = cw;
|
||||
this.access = access;
|
||||
this.name = cw.newUTF8(name);
|
||||
this.desc = cw.newUTF8(desc);
|
||||
if (signature != null) {
|
||||
this.signature = cw.newUTF8(signature);
|
||||
}
|
||||
if (value != null) {
|
||||
this.value = cw.newConstItem(value).index;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Implementation of the FieldVisitor abstract class
|
||||
// ------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
// Implementation of the FieldVisitor abstract class
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
|
||||
ByteVector bv = new ByteVector();
|
||||
// write type, and reserve space for values count
|
||||
bv.putShort(cw.newUTF8(desc)).putShort(0);
|
||||
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
|
||||
if (visible) {
|
||||
aw.next = anns;
|
||||
anns = aw;
|
||||
} else {
|
||||
aw.next = ianns;
|
||||
ianns = aw;
|
||||
}
|
||||
return aw;
|
||||
}
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
|
||||
ByteVector bv = new ByteVector();
|
||||
// write type, and reserve space for values count
|
||||
bv.putShort(cw.newUTF8(desc)).putShort(0);
|
||||
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
|
||||
if (visible) {
|
||||
aw.next = anns;
|
||||
anns = aw;
|
||||
} else {
|
||||
aw.next = ianns;
|
||||
ianns = aw;
|
||||
}
|
||||
return aw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitTypeAnnotation(
|
||||
final int typeRef, final TypePath typePath, final String desc, final boolean visible) {
|
||||
ByteVector bv = new ByteVector();
|
||||
// write target_type and target_info
|
||||
AnnotationWriter.putTarget(typeRef, typePath, bv);
|
||||
// write type, and reserve space for values count
|
||||
bv.putShort(cw.newUTF8(desc)).putShort(0);
|
||||
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
|
||||
if (visible) {
|
||||
aw.next = tanns;
|
||||
tanns = aw;
|
||||
} else {
|
||||
aw.next = itanns;
|
||||
itanns = aw;
|
||||
}
|
||||
return aw;
|
||||
}
|
||||
@Override
|
||||
public AnnotationVisitor visitTypeAnnotation(
|
||||
final int typeRef, final TypePath typePath, final String desc, final boolean visible) {
|
||||
ByteVector bv = new ByteVector();
|
||||
// write target_type and target_info
|
||||
AnnotationWriter.putTarget(typeRef, typePath, bv);
|
||||
// write type, and reserve space for values count
|
||||
bv.putShort(cw.newUTF8(desc)).putShort(0);
|
||||
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
|
||||
if (visible) {
|
||||
aw.next = tanns;
|
||||
tanns = aw;
|
||||
} else {
|
||||
aw.next = itanns;
|
||||
itanns = aw;
|
||||
}
|
||||
return aw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(final Attribute attr) {
|
||||
attr.next = attrs;
|
||||
attrs = attr;
|
||||
}
|
||||
@Override
|
||||
public void visitAttribute(final Attribute attr) {
|
||||
attr.next = attrs;
|
||||
attrs = attr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
// do nothing
|
||||
}
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
// ------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the size of this field.
|
||||
*
|
||||
* @return the size of this field.
|
||||
*/
|
||||
int getSize() {
|
||||
int size = 8;
|
||||
if (value != 0) {
|
||||
cw.newUTF8("ConstantValue");
|
||||
size += 8;
|
||||
}
|
||||
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
|
||||
if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
|
||||
cw.newUTF8("Synthetic");
|
||||
size += 6;
|
||||
}
|
||||
}
|
||||
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
cw.newUTF8("Deprecated");
|
||||
size += 6;
|
||||
}
|
||||
if (signature != 0) {
|
||||
cw.newUTF8("Signature");
|
||||
size += 8;
|
||||
}
|
||||
if (anns != null) {
|
||||
cw.newUTF8("RuntimeVisibleAnnotations");
|
||||
size += 8 + anns.getSize();
|
||||
}
|
||||
if (ianns != null) {
|
||||
cw.newUTF8("RuntimeInvisibleAnnotations");
|
||||
size += 8 + ianns.getSize();
|
||||
}
|
||||
if (tanns != null) {
|
||||
cw.newUTF8("RuntimeVisibleTypeAnnotations");
|
||||
size += 8 + tanns.getSize();
|
||||
}
|
||||
if (itanns != null) {
|
||||
cw.newUTF8("RuntimeInvisibleTypeAnnotations");
|
||||
size += 8 + itanns.getSize();
|
||||
}
|
||||
if (attrs != null) {
|
||||
size += attrs.getSize(cw, null, 0, -1, -1);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
/**
|
||||
* Returns the size of this field.
|
||||
*
|
||||
* @return the size of this field.
|
||||
*/
|
||||
int getSize() {
|
||||
int size = 8;
|
||||
if (value != 0) {
|
||||
cw.newUTF8("ConstantValue");
|
||||
size += 8;
|
||||
}
|
||||
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
|
||||
if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
|
||||
cw.newUTF8("Synthetic");
|
||||
size += 6;
|
||||
}
|
||||
}
|
||||
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
cw.newUTF8("Deprecated");
|
||||
size += 6;
|
||||
}
|
||||
if (signature != 0) {
|
||||
cw.newUTF8("Signature");
|
||||
size += 8;
|
||||
}
|
||||
if (anns != null) {
|
||||
cw.newUTF8("RuntimeVisibleAnnotations");
|
||||
size += 8 + anns.getSize();
|
||||
}
|
||||
if (ianns != null) {
|
||||
cw.newUTF8("RuntimeInvisibleAnnotations");
|
||||
size += 8 + ianns.getSize();
|
||||
}
|
||||
if (tanns != null) {
|
||||
cw.newUTF8("RuntimeVisibleTypeAnnotations");
|
||||
size += 8 + tanns.getSize();
|
||||
}
|
||||
if (itanns != null) {
|
||||
cw.newUTF8("RuntimeInvisibleTypeAnnotations");
|
||||
size += 8 + itanns.getSize();
|
||||
}
|
||||
if (attrs != null) {
|
||||
size += attrs.getSize(cw, null, 0, -1, -1);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the content of this field into the given byte vector.
|
||||
*
|
||||
* @param out where the content of this field must be put.
|
||||
*/
|
||||
void put(final ByteVector out) {
|
||||
final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
|
||||
int mask = Opcodes.ACC_DEPRECATED
|
||||
| ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
|
||||
| ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
|
||||
out.putShort(access & ~mask).putShort(name).putShort(desc);
|
||||
int attributeCount = 0;
|
||||
if (value != 0) {
|
||||
++attributeCount;
|
||||
}
|
||||
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
|
||||
if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
|
||||
++attributeCount;
|
||||
}
|
||||
}
|
||||
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (signature != 0) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (anns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (ianns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (tanns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (itanns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (attrs != null) {
|
||||
attributeCount += attrs.getCount();
|
||||
}
|
||||
out.putShort(attributeCount);
|
||||
if (value != 0) {
|
||||
out.putShort(cw.newUTF8("ConstantValue"));
|
||||
out.putInt(2).putShort(value);
|
||||
}
|
||||
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
|
||||
if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
|
||||
out.putShort(cw.newUTF8("Synthetic")).putInt(0);
|
||||
}
|
||||
}
|
||||
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
out.putShort(cw.newUTF8("Deprecated")).putInt(0);
|
||||
}
|
||||
if (signature != 0) {
|
||||
out.putShort(cw.newUTF8("Signature"));
|
||||
out.putInt(2).putShort(signature);
|
||||
}
|
||||
if (anns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
|
||||
anns.put(out);
|
||||
}
|
||||
if (ianns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
|
||||
ianns.put(out);
|
||||
}
|
||||
if (tanns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
|
||||
tanns.put(out);
|
||||
}
|
||||
if (itanns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
|
||||
itanns.put(out);
|
||||
}
|
||||
if (attrs != null) {
|
||||
attrs.put(cw, null, 0, -1, -1, out);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Puts the content of this field into the given byte vector.
|
||||
*
|
||||
* @param out where the content of this field must be put.
|
||||
*/
|
||||
void put(final ByteVector out) {
|
||||
final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
|
||||
int mask = Opcodes.ACC_DEPRECATED
|
||||
| ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
|
||||
| ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
|
||||
out.putShort(access & ~mask).putShort(name).putShort(desc);
|
||||
int attributeCount = 0;
|
||||
if (value != 0) {
|
||||
++attributeCount;
|
||||
}
|
||||
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
|
||||
if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
|
||||
++attributeCount;
|
||||
}
|
||||
}
|
||||
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (signature != 0) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (anns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (ianns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (tanns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (itanns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (attrs != null) {
|
||||
attributeCount += attrs.getCount();
|
||||
}
|
||||
out.putShort(attributeCount);
|
||||
if (value != 0) {
|
||||
out.putShort(cw.newUTF8("ConstantValue"));
|
||||
out.putInt(2).putShort(value);
|
||||
}
|
||||
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
|
||||
if ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
|
||||
out.putShort(cw.newUTF8("Synthetic")).putInt(0);
|
||||
}
|
||||
}
|
||||
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
out.putShort(cw.newUTF8("Deprecated")).putInt(0);
|
||||
}
|
||||
if (signature != 0) {
|
||||
out.putShort(cw.newUTF8("Signature"));
|
||||
out.putInt(2).putShort(signature);
|
||||
}
|
||||
if (anns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
|
||||
anns.put(out);
|
||||
}
|
||||
if (ianns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
|
||||
ianns.put(out);
|
||||
}
|
||||
if (tanns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
|
||||
tanns.put(out);
|
||||
}
|
||||
if (itanns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
|
||||
itanns.put(out);
|
||||
}
|
||||
if (attrs != null) {
|
||||
attrs.put(cw, null, 0, -1, -1, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -67,124 +67,124 @@ package org.redkale.asm;
|
||||
*/
|
||||
public final class Handle {
|
||||
|
||||
/**
|
||||
* The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD},
|
||||
* {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
|
||||
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
|
||||
* {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
|
||||
*/
|
||||
final int tag;
|
||||
/**
|
||||
* The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD},
|
||||
* {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
|
||||
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
|
||||
* {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
|
||||
*/
|
||||
final int tag;
|
||||
|
||||
/** The internal name of the class that owns the field or method designated by this handle. */
|
||||
final String owner;
|
||||
/** The internal name of the class that owns the field or method designated by this handle. */
|
||||
final String owner;
|
||||
|
||||
/** The name of the field or method designated by this handle. */
|
||||
final String name;
|
||||
/** The name of the field or method designated by this handle. */
|
||||
final String name;
|
||||
|
||||
/** The descriptor of the field or method designated by this handle. */
|
||||
final String desc;
|
||||
/** The descriptor of the field or method designated by this handle. */
|
||||
final String desc;
|
||||
|
||||
/** Indicate if the owner is an interface or not. */
|
||||
final boolean itf;
|
||||
/** Indicate if the owner is an interface or not. */
|
||||
final boolean itf;
|
||||
|
||||
/**
|
||||
* Constructs a new field or method handle.
|
||||
*
|
||||
* @param tag the kind of field or method designated by this Handle. Must be {@link Opcodes#H_GETFIELD},
|
||||
* {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
|
||||
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
|
||||
* {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
|
||||
* @param owner the internal name of the class that owns the field or method designated by this handle.
|
||||
* @param name the name of the field or method designated by this handle.
|
||||
* @param desc the descriptor of the field or method designated by this handle.
|
||||
* @param itf true if the owner is an interface.
|
||||
*/
|
||||
public Handle(int tag, String owner, String name, String desc, boolean itf) {
|
||||
this.tag = tag;
|
||||
this.owner = owner;
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
this.itf = itf;
|
||||
}
|
||||
/**
|
||||
* Constructs a new field or method handle.
|
||||
*
|
||||
* @param tag the kind of field or method designated by this Handle. Must be {@link Opcodes#H_GETFIELD},
|
||||
* {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
|
||||
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
|
||||
* {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
|
||||
* @param owner the internal name of the class that owns the field or method designated by this handle.
|
||||
* @param name the name of the field or method designated by this handle.
|
||||
* @param desc the descriptor of the field or method designated by this handle.
|
||||
* @param itf true if the owner is an interface.
|
||||
*/
|
||||
public Handle(int tag, String owner, String name, String desc, boolean itf) {
|
||||
this.tag = tag;
|
||||
this.owner = owner;
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
this.itf = itf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the kind of field or method designated by this handle.
|
||||
*
|
||||
* @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
|
||||
* {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
|
||||
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
|
||||
*/
|
||||
public int getTag() {
|
||||
return tag;
|
||||
}
|
||||
/**
|
||||
* Returns the kind of field or method designated by this handle.
|
||||
*
|
||||
* @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
|
||||
* {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
|
||||
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
|
||||
*/
|
||||
public int getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the internal name of the class that owns the field or method designated by this handle.
|
||||
*
|
||||
* @return the internal name of the class that owns the field or method designated by this handle.
|
||||
*/
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
/**
|
||||
* Returns the internal name of the class that owns the field or method designated by this handle.
|
||||
*
|
||||
* @return the internal name of the class that owns the field or method designated by this handle.
|
||||
*/
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the field or method designated by this handle.
|
||||
*
|
||||
* @return the name of the field or method designated by this handle.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
/**
|
||||
* Returns the name of the field or method designated by this handle.
|
||||
*
|
||||
* @return the name of the field or method designated by this handle.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the descriptor of the field or method designated by this handle.
|
||||
*
|
||||
* @return the descriptor of the field or method designated by this handle.
|
||||
*/
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
/**
|
||||
* Returns the descriptor of the field or method designated by this handle.
|
||||
*
|
||||
* @return the descriptor of the field or method designated by this handle.
|
||||
*/
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the owner of the field or method designated by this handle is an interface.
|
||||
*
|
||||
* @return true if the owner of the field or method designated by this handle is an interface.
|
||||
*/
|
||||
public boolean isInterface() {
|
||||
return itf;
|
||||
}
|
||||
/**
|
||||
* Returns true if the owner of the field or method designated by this handle is an interface.
|
||||
*
|
||||
* @return true if the owner of the field or method designated by this handle is an interface.
|
||||
*/
|
||||
public boolean isInterface() {
|
||||
return itf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Handle)) {
|
||||
return false;
|
||||
}
|
||||
Handle h = (Handle) obj;
|
||||
return tag == h.tag && itf == h.itf && owner.equals(h.owner) && name.equals(h.name) && desc.equals(h.desc);
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Handle)) {
|
||||
return false;
|
||||
}
|
||||
Handle h = (Handle) obj;
|
||||
return tag == h.tag && itf == h.itf && owner.equals(h.owner) && name.equals(h.name) && desc.equals(h.desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return tag + (itf ? 64 : 0) + owner.hashCode() * name.hashCode() * desc.hashCode();
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return tag + (itf ? 64 : 0) + owner.hashCode() * name.hashCode() * desc.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the textual representation of this handle. The textual representation is:
|
||||
*
|
||||
* <pre>
|
||||
* for a reference to a class:
|
||||
* owner '.' name desc ' ' '(' tag ')'
|
||||
* for a reference to an interface:
|
||||
* owner '.' name desc ' ' '(' tag ' ' itf ')'
|
||||
* </pre>
|
||||
*
|
||||
* . As this format is unambiguous, it can be parsed if necessary.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return owner + '.' + name + desc + " (" + tag + (itf ? " itf" : "") + ')';
|
||||
}
|
||||
/**
|
||||
* Returns the textual representation of this handle. The textual representation is:
|
||||
*
|
||||
* <pre>
|
||||
* for a reference to a class:
|
||||
* owner '.' name desc ' ' '(' tag ')'
|
||||
* for a reference to an interface:
|
||||
* owner '.' name desc ' ' '(' tag ' ' itf ')'
|
||||
* </pre>
|
||||
*
|
||||
* . As this format is unambiguous, it can be parsed if necessary.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return owner + '.' + name + desc + " (" + tag + (itf ? " itf" : "") + ')';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,74 +65,74 @@ package org.redkale.asm;
|
||||
*/
|
||||
class Handler {
|
||||
|
||||
/** Beginning of the exception handler's scope (inclusive). */
|
||||
Label start;
|
||||
/** Beginning of the exception handler's scope (inclusive). */
|
||||
Label start;
|
||||
|
||||
/** End of the exception handler's scope (exclusive). */
|
||||
Label end;
|
||||
/** End of the exception handler's scope (exclusive). */
|
||||
Label end;
|
||||
|
||||
/** Beginning of the exception handler's code. */
|
||||
Label handler;
|
||||
/** Beginning of the exception handler's code. */
|
||||
Label handler;
|
||||
|
||||
/**
|
||||
* Internal name of the type of exceptions handled by this handler, or <tt>null</tt> to catch any
|
||||
* exceptions.
|
||||
*/
|
||||
String desc;
|
||||
/**
|
||||
* Internal name of the type of exceptions handled by this handler, or <tt>null</tt> to catch any
|
||||
* exceptions.
|
||||
*/
|
||||
String desc;
|
||||
|
||||
/**
|
||||
* Constant pool index of the internal name of the type of exceptions handled by this handler, or 0 to catch any
|
||||
* exceptions.
|
||||
*/
|
||||
int type;
|
||||
/**
|
||||
* Constant pool index of the internal name of the type of exceptions handled by this handler, or 0 to catch any
|
||||
* exceptions.
|
||||
*/
|
||||
int type;
|
||||
|
||||
/** Next exception handler block info. */
|
||||
Handler next;
|
||||
/** Next exception handler block info. */
|
||||
Handler next;
|
||||
|
||||
/**
|
||||
* Removes the range between start and end from the given exception handlers.
|
||||
*
|
||||
* @param h an exception handler list.
|
||||
* @param start the start of the range to be removed.
|
||||
* @param end the end of the range to be removed. Maybe null.
|
||||
* @return the exception handler list with the start-end range removed.
|
||||
*/
|
||||
static Handler remove(Handler h, Label start, Label end) {
|
||||
if (h == null) {
|
||||
return null;
|
||||
} else {
|
||||
h.next = remove(h.next, start, end);
|
||||
}
|
||||
int hstart = h.start.position;
|
||||
int hend = h.end.position;
|
||||
int s = start.position;
|
||||
int e = end == null ? Integer.MAX_VALUE : end.position;
|
||||
// if [hstart,hend[ and [s,e[ intervals intersect...
|
||||
if (s < hend && e > hstart) {
|
||||
if (s <= hstart) {
|
||||
if (e >= hend) {
|
||||
// [hstart,hend[ fully included in [s,e[, h removed
|
||||
h = h.next;
|
||||
} else {
|
||||
// [hstart,hend[ minus [s,e[ = [e,hend[
|
||||
h.start = end;
|
||||
}
|
||||
} else if (e >= hend) {
|
||||
// [hstart,hend[ minus [s,e[ = [hstart,s[
|
||||
h.end = start;
|
||||
} else {
|
||||
// [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
|
||||
Handler g = new Handler();
|
||||
g.start = end;
|
||||
g.end = h.end;
|
||||
g.handler = h.handler;
|
||||
g.desc = h.desc;
|
||||
g.type = h.type;
|
||||
g.next = h.next;
|
||||
h.end = start;
|
||||
h.next = g;
|
||||
}
|
||||
}
|
||||
return h;
|
||||
}
|
||||
/**
|
||||
* Removes the range between start and end from the given exception handlers.
|
||||
*
|
||||
* @param h an exception handler list.
|
||||
* @param start the start of the range to be removed.
|
||||
* @param end the end of the range to be removed. Maybe null.
|
||||
* @return the exception handler list with the start-end range removed.
|
||||
*/
|
||||
static Handler remove(Handler h, Label start, Label end) {
|
||||
if (h == null) {
|
||||
return null;
|
||||
} else {
|
||||
h.next = remove(h.next, start, end);
|
||||
}
|
||||
int hstart = h.start.position;
|
||||
int hend = h.end.position;
|
||||
int s = start.position;
|
||||
int e = end == null ? Integer.MAX_VALUE : end.position;
|
||||
// if [hstart,hend[ and [s,e[ intervals intersect...
|
||||
if (s < hend && e > hstart) {
|
||||
if (s <= hstart) {
|
||||
if (e >= hend) {
|
||||
// [hstart,hend[ fully included in [s,e[, h removed
|
||||
h = h.next;
|
||||
} else {
|
||||
// [hstart,hend[ minus [s,e[ = [e,hend[
|
||||
h.start = end;
|
||||
}
|
||||
} else if (e >= hend) {
|
||||
// [hstart,hend[ minus [s,e[ = [hstart,s[
|
||||
h.end = start;
|
||||
} else {
|
||||
// [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
|
||||
Handler g = new Handler();
|
||||
g.start = end;
|
||||
g.end = h.end;
|
||||
g.handler = h.handler;
|
||||
g.desc = h.desc;
|
||||
g.type = h.type;
|
||||
g.next = h.next;
|
||||
h.end = start;
|
||||
h.next = g;
|
||||
}
|
||||
}
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,225 +65,225 @@ package org.redkale.asm;
|
||||
*/
|
||||
final class Item {
|
||||
|
||||
/** Index of this item in the constant pool. */
|
||||
int index;
|
||||
/** Index of this item in the constant pool. */
|
||||
int index;
|
||||
|
||||
/**
|
||||
* Type of this constant pool item. A single class is used to represent all constant pool item types, in order to
|
||||
* minimize the bytecode size of this package. The value of this field is one of {@link ClassWriter#INT},
|
||||
* {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT}, {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
|
||||
* {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
|
||||
* {@link ClassWriter#METH}, {@link ClassWriter#IMETH}, {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE},
|
||||
* {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* <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
|
||||
* constant pool's hash table. These special item types are {@link ClassWriter#TYPE_NORMAL},
|
||||
* {@link ClassWriter#TYPE_UNINIT} and {@link ClassWriter#TYPE_MERGED}.
|
||||
*/
|
||||
int type;
|
||||
/**
|
||||
* Type of this constant pool item. A single class is used to represent all constant pool item types, in order to
|
||||
* minimize the bytecode size of this package. The value of this field is one of {@link ClassWriter#INT},
|
||||
* {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT}, {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
|
||||
* {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
|
||||
* {@link ClassWriter#METH}, {@link ClassWriter#IMETH}, {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE},
|
||||
* {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* <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
|
||||
* constant pool's hash table. These special item types are {@link ClassWriter#TYPE_NORMAL},
|
||||
* {@link ClassWriter#TYPE_UNINIT} and {@link ClassWriter#TYPE_MERGED}.
|
||||
*/
|
||||
int type;
|
||||
|
||||
/** Value of this item, for an integer item. */
|
||||
int intVal;
|
||||
/** Value of this item, for an integer item. */
|
||||
int intVal;
|
||||
|
||||
/** Value of this item, for a long item. */
|
||||
long longVal;
|
||||
/** Value of this item, for a long item. */
|
||||
long longVal;
|
||||
|
||||
/** First part of the value of this item, for items that do not hold a primitive value. */
|
||||
String strVal1;
|
||||
/** First part of the value of this item, for items that do not hold a primitive value. */
|
||||
String strVal1;
|
||||
|
||||
/** Second part of the value of this item, for items that do not hold a primitive value. */
|
||||
String strVal2;
|
||||
/** Second part of the value of this item, for items that do not hold a primitive value. */
|
||||
String strVal2;
|
||||
|
||||
/** Third part of the value of this item, for items that do not hold a primitive value. */
|
||||
String strVal3;
|
||||
/** Third part of the value of this item, for items that do not hold a primitive value. */
|
||||
String strVal3;
|
||||
|
||||
/** The hash code value of this constant pool item. */
|
||||
int hashCode;
|
||||
/** The hash code value of this constant pool item. */
|
||||
int hashCode;
|
||||
|
||||
/** Link to another constant pool item, used for collision lists in the constant pool's hash table. */
|
||||
Item next;
|
||||
/** Link to another constant pool item, used for collision lists in the constant pool's hash table. */
|
||||
Item next;
|
||||
|
||||
/** Constructs an uninitialized {@link Item}. */
|
||||
Item() {}
|
||||
/** Constructs an uninitialized {@link Item}. */
|
||||
Item() {}
|
||||
|
||||
/**
|
||||
* Constructs an uninitialized {@link Item} for constant pool element at given position.
|
||||
*
|
||||
* @param index index of the item to be constructed.
|
||||
*/
|
||||
Item(final int index) {
|
||||
this.index = index;
|
||||
}
|
||||
/**
|
||||
* Constructs an uninitialized {@link Item} for constant pool element at given position.
|
||||
*
|
||||
* @param index index of the item to be constructed.
|
||||
*/
|
||||
Item(final int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a copy of the given item.
|
||||
*
|
||||
* @param index index of the item to be constructed.
|
||||
* @param i the item that must be copied into the item to be constructed.
|
||||
*/
|
||||
Item(final int index, final Item i) {
|
||||
this.index = index;
|
||||
type = i.type;
|
||||
intVal = i.intVal;
|
||||
longVal = i.longVal;
|
||||
strVal1 = i.strVal1;
|
||||
strVal2 = i.strVal2;
|
||||
strVal3 = i.strVal3;
|
||||
hashCode = i.hashCode;
|
||||
}
|
||||
/**
|
||||
* Constructs a copy of the given item.
|
||||
*
|
||||
* @param index index of the item to be constructed.
|
||||
* @param i the item that must be copied into the item to be constructed.
|
||||
*/
|
||||
Item(final int index, final Item i) {
|
||||
this.index = index;
|
||||
type = i.type;
|
||||
intVal = i.intVal;
|
||||
longVal = i.longVal;
|
||||
strVal1 = i.strVal1;
|
||||
strVal2 = i.strVal2;
|
||||
strVal3 = i.strVal3;
|
||||
hashCode = i.hashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item to an integer item.
|
||||
*
|
||||
* @param intVal the value of this item.
|
||||
*/
|
||||
void set(final int intVal) {
|
||||
this.type = ClassWriter.INT;
|
||||
this.intVal = intVal;
|
||||
this.hashCode = 0x7FFFFFFF & (type + intVal);
|
||||
}
|
||||
/**
|
||||
* Sets this item to an integer item.
|
||||
*
|
||||
* @param intVal the value of this item.
|
||||
*/
|
||||
void set(final int intVal) {
|
||||
this.type = ClassWriter.INT;
|
||||
this.intVal = intVal;
|
||||
this.hashCode = 0x7FFFFFFF & (type + intVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item to a long item.
|
||||
*
|
||||
* @param longVal the value of this item.
|
||||
*/
|
||||
void set(final long longVal) {
|
||||
this.type = ClassWriter.LONG;
|
||||
this.longVal = longVal;
|
||||
this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
|
||||
}
|
||||
/**
|
||||
* Sets this item to a long item.
|
||||
*
|
||||
* @param longVal the value of this item.
|
||||
*/
|
||||
void set(final long longVal) {
|
||||
this.type = ClassWriter.LONG;
|
||||
this.longVal = longVal;
|
||||
this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item to a float item.
|
||||
*
|
||||
* @param floatVal the value of this item.
|
||||
*/
|
||||
void set(final float floatVal) {
|
||||
this.type = ClassWriter.FLOAT;
|
||||
this.intVal = Float.floatToRawIntBits(floatVal);
|
||||
this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
|
||||
}
|
||||
/**
|
||||
* Sets this item to a float item.
|
||||
*
|
||||
* @param floatVal the value of this item.
|
||||
*/
|
||||
void set(final float floatVal) {
|
||||
this.type = ClassWriter.FLOAT;
|
||||
this.intVal = Float.floatToRawIntBits(floatVal);
|
||||
this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item to a double item.
|
||||
*
|
||||
* @param doubleVal the value of this item.
|
||||
*/
|
||||
void set(final double doubleVal) {
|
||||
this.type = ClassWriter.DOUBLE;
|
||||
this.longVal = Double.doubleToRawLongBits(doubleVal);
|
||||
this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
|
||||
}
|
||||
/**
|
||||
* Sets this item to a double item.
|
||||
*
|
||||
* @param doubleVal the value of this item.
|
||||
*/
|
||||
void set(final double doubleVal) {
|
||||
this.type = ClassWriter.DOUBLE;
|
||||
this.longVal = Double.doubleToRawLongBits(doubleVal);
|
||||
this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item to an item that do not hold a primitive value.
|
||||
*
|
||||
* @param type the type of this item.
|
||||
* @param strVal1 first part of the value of this item.
|
||||
* @param strVal2 second part of the value of this item.
|
||||
* @param strVal3 third part of the value of this item.
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
void set(final int type, final String strVal1, final String strVal2, final String strVal3) {
|
||||
this.type = type;
|
||||
this.strVal1 = strVal1;
|
||||
this.strVal2 = strVal2;
|
||||
this.strVal3 = strVal3;
|
||||
switch (type) {
|
||||
case ClassWriter.CLASS:
|
||||
this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
|
||||
case ClassWriter.UTF8:
|
||||
case ClassWriter.STR:
|
||||
case ClassWriter.MTYPE:
|
||||
case ClassWriter.MODULE:
|
||||
case ClassWriter.PACKAGE:
|
||||
case ClassWriter.TYPE_NORMAL:
|
||||
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
|
||||
return;
|
||||
case ClassWriter.NAME_TYPE: {
|
||||
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode());
|
||||
return;
|
||||
}
|
||||
// ClassWriter.FIELD:
|
||||
// ClassWriter.METH:
|
||||
// ClassWriter.IMETH:
|
||||
// ClassWriter.HANDLE_BASE + 1..9
|
||||
default:
|
||||
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode() * strVal3.hashCode());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sets this item to an item that do not hold a primitive value.
|
||||
*
|
||||
* @param type the type of this item.
|
||||
* @param strVal1 first part of the value of this item.
|
||||
* @param strVal2 second part of the value of this item.
|
||||
* @param strVal3 third part of the value of this item.
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
void set(final int type, final String strVal1, final String strVal2, final String strVal3) {
|
||||
this.type = type;
|
||||
this.strVal1 = strVal1;
|
||||
this.strVal2 = strVal2;
|
||||
this.strVal3 = strVal3;
|
||||
switch (type) {
|
||||
case ClassWriter.CLASS:
|
||||
this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
|
||||
case ClassWriter.UTF8:
|
||||
case ClassWriter.STR:
|
||||
case ClassWriter.MTYPE:
|
||||
case ClassWriter.MODULE:
|
||||
case ClassWriter.PACKAGE:
|
||||
case ClassWriter.TYPE_NORMAL:
|
||||
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
|
||||
return;
|
||||
case ClassWriter.NAME_TYPE: {
|
||||
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode());
|
||||
return;
|
||||
}
|
||||
// ClassWriter.FIELD:
|
||||
// ClassWriter.METH:
|
||||
// ClassWriter.IMETH:
|
||||
// ClassWriter.HANDLE_BASE + 1..9
|
||||
default:
|
||||
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode() * strVal3.hashCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the item to an InvokeDynamic item.
|
||||
*
|
||||
* @param name invokedynamic's name.
|
||||
* @param desc invokedynamic's desc.
|
||||
* @param bsmIndex zero based index into the class attribute BootrapMethods.
|
||||
*/
|
||||
void set(String name, String desc, int bsmIndex) {
|
||||
this.type = ClassWriter.INDY;
|
||||
this.longVal = bsmIndex;
|
||||
this.strVal1 = name;
|
||||
this.strVal2 = desc;
|
||||
this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex * strVal1.hashCode() * strVal2.hashCode());
|
||||
}
|
||||
/**
|
||||
* Sets the item to an InvokeDynamic item.
|
||||
*
|
||||
* @param name invokedynamic's name.
|
||||
* @param desc invokedynamic's desc.
|
||||
* @param bsmIndex zero based index into the class attribute BootrapMethods.
|
||||
*/
|
||||
void set(String name, String desc, int bsmIndex) {
|
||||
this.type = ClassWriter.INDY;
|
||||
this.longVal = bsmIndex;
|
||||
this.strVal1 = name;
|
||||
this.strVal2 = desc;
|
||||
this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex * strVal1.hashCode() * strVal2.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the item to a BootstrapMethod item.
|
||||
*
|
||||
* @param position position in byte in the class attribute BootrapMethods.
|
||||
* @param hashCode hashcode of the item. This hashcode is processed from the hashcode of the bootstrap method and
|
||||
* the hashcode of all bootstrap arguments.
|
||||
*/
|
||||
void set(int position, int hashCode) {
|
||||
this.type = ClassWriter.BSM;
|
||||
this.intVal = position;
|
||||
this.hashCode = hashCode;
|
||||
}
|
||||
/**
|
||||
* Sets the item to a BootstrapMethod item.
|
||||
*
|
||||
* @param position position in byte in the class attribute BootrapMethods.
|
||||
* @param hashCode hashcode of the item. This hashcode is processed from the hashcode of the bootstrap method and
|
||||
* the hashcode of all bootstrap arguments.
|
||||
*/
|
||||
void set(int position, int hashCode) {
|
||||
this.type = ClassWriter.BSM;
|
||||
this.intVal = position;
|
||||
this.hashCode = hashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the given item is equal to this one. <i>This method assumes that the two items have the same
|
||||
* {@link #type}</i>.
|
||||
*
|
||||
* @param i the item to be compared to this one. Both items must have the same {@link #type}.
|
||||
* @return <tt>true</tt> if the given item if equal to this one, <tt>false</tt>
|
||||
* otherwise.
|
||||
*/
|
||||
boolean isEqualTo(final Item i) {
|
||||
switch (type) {
|
||||
case ClassWriter.UTF8:
|
||||
case ClassWriter.STR:
|
||||
case ClassWriter.CLASS:
|
||||
case ClassWriter.MODULE:
|
||||
case ClassWriter.PACKAGE:
|
||||
case ClassWriter.MTYPE:
|
||||
case ClassWriter.TYPE_NORMAL:
|
||||
return i.strVal1.equals(strVal1);
|
||||
case ClassWriter.TYPE_MERGED:
|
||||
case ClassWriter.LONG:
|
||||
case ClassWriter.DOUBLE:
|
||||
return i.longVal == longVal;
|
||||
case ClassWriter.INT:
|
||||
case ClassWriter.FLOAT:
|
||||
return i.intVal == intVal;
|
||||
case ClassWriter.TYPE_UNINIT:
|
||||
return i.intVal == intVal && i.strVal1.equals(strVal1);
|
||||
case ClassWriter.NAME_TYPE:
|
||||
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
|
||||
case ClassWriter.INDY: {
|
||||
return i.longVal == longVal && i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
|
||||
}
|
||||
// case ClassWriter.FIELD:
|
||||
// case ClassWriter.METH:
|
||||
// case ClassWriter.IMETH:
|
||||
// case ClassWriter.HANDLE_BASE + 1..9
|
||||
default:
|
||||
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2) && i.strVal3.equals(strVal3);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Indicates if the given item is equal to this one. <i>This method assumes that the two items have the same
|
||||
* {@link #type}</i>.
|
||||
*
|
||||
* @param i the item to be compared to this one. Both items must have the same {@link #type}.
|
||||
* @return <tt>true</tt> if the given item if equal to this one, <tt>false</tt>
|
||||
* otherwise.
|
||||
*/
|
||||
boolean isEqualTo(final Item i) {
|
||||
switch (type) {
|
||||
case ClassWriter.UTF8:
|
||||
case ClassWriter.STR:
|
||||
case ClassWriter.CLASS:
|
||||
case ClassWriter.MODULE:
|
||||
case ClassWriter.PACKAGE:
|
||||
case ClassWriter.MTYPE:
|
||||
case ClassWriter.TYPE_NORMAL:
|
||||
return i.strVal1.equals(strVal1);
|
||||
case ClassWriter.TYPE_MERGED:
|
||||
case ClassWriter.LONG:
|
||||
case ClassWriter.DOUBLE:
|
||||
return i.longVal == longVal;
|
||||
case ClassWriter.INT:
|
||||
case ClassWriter.FLOAT:
|
||||
return i.intVal == intVal;
|
||||
case ClassWriter.TYPE_UNINIT:
|
||||
return i.intVal == intVal && i.strVal1.equals(strVal1);
|
||||
case ClassWriter.NAME_TYPE:
|
||||
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
|
||||
case ClassWriter.INDY: {
|
||||
return i.longVal == longVal && i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
|
||||
}
|
||||
// case ClassWriter.FIELD:
|
||||
// case ClassWriter.METH:
|
||||
// case ClassWriter.IMETH:
|
||||
// case ClassWriter.HANDLE_BASE + 1..9
|
||||
default:
|
||||
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2) && i.strVal3.equals(strVal3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,442 +68,442 @@ package org.redkale.asm;
|
||||
*/
|
||||
public class Label {
|
||||
|
||||
/**
|
||||
* Indicates if this label is only used for debug attributes. Such a label is not the start of a basic block, the
|
||||
* target of a jump instruction, or an exception handler. It can be safely ignored in control flow graph analysis
|
||||
* algorithms (for optimization purposes).
|
||||
*/
|
||||
static final int DEBUG = 1;
|
||||
/**
|
||||
* Indicates if this label is only used for debug attributes. Such a label is not the start of a basic block, the
|
||||
* target of a jump instruction, or an exception handler. It can be safely ignored in control flow graph analysis
|
||||
* algorithms (for optimization purposes).
|
||||
*/
|
||||
static final int DEBUG = 1;
|
||||
|
||||
/** Indicates if the position of this label is known. */
|
||||
static final int RESOLVED = 2;
|
||||
/** Indicates if the position of this label is known. */
|
||||
static final int RESOLVED = 2;
|
||||
|
||||
/** Indicates if this label has been updated, after instruction resizing. */
|
||||
static final int RESIZED = 4;
|
||||
/** Indicates if this label has been updated, after instruction resizing. */
|
||||
static final int RESIZED = 4;
|
||||
|
||||
/**
|
||||
* Indicates if this basic block has been pushed in the basic block stack. See {@link MethodWriter#visitMaxs
|
||||
* visitMaxs}.
|
||||
*/
|
||||
static final int PUSHED = 8;
|
||||
/**
|
||||
* Indicates if this basic block has been pushed in the basic block stack. See {@link MethodWriter#visitMaxs
|
||||
* visitMaxs}.
|
||||
*/
|
||||
static final int PUSHED = 8;
|
||||
|
||||
/** Indicates if this label is the target of a jump instruction, or the start of an exception handler. */
|
||||
static final int TARGET = 16;
|
||||
/** Indicates if this label is the target of a jump instruction, or the start of an exception handler. */
|
||||
static final int TARGET = 16;
|
||||
|
||||
/** Indicates if a stack map frame must be stored for this label. */
|
||||
static final int STORE = 32;
|
||||
/** Indicates if a stack map frame must be stored for this label. */
|
||||
static final int STORE = 32;
|
||||
|
||||
/** Indicates if this label corresponds to a reachable basic block. */
|
||||
static final int REACHABLE = 64;
|
||||
/** Indicates if this label corresponds to a reachable basic block. */
|
||||
static final int REACHABLE = 64;
|
||||
|
||||
/** Indicates if this basic block ends with a JSR instruction. */
|
||||
static final int JSR = 128;
|
||||
/** Indicates if this basic block ends with a JSR instruction. */
|
||||
static final int JSR = 128;
|
||||
|
||||
/** Indicates if this basic block ends with a RET instruction. */
|
||||
static final int RET = 256;
|
||||
/** Indicates if this basic block ends with a RET instruction. */
|
||||
static final int RET = 256;
|
||||
|
||||
/** Indicates if this basic block is the start of a subroutine. */
|
||||
static final int SUBROUTINE = 512;
|
||||
/** Indicates if this basic block is the start of a subroutine. */
|
||||
static final int SUBROUTINE = 512;
|
||||
|
||||
/** Indicates if this subroutine basic block has been visited by a visitSubroutine(null, ...) call. */
|
||||
static final int VISITED = 1024;
|
||||
/** Indicates if this subroutine basic block has been visited by a visitSubroutine(null, ...) call. */
|
||||
static final int VISITED = 1024;
|
||||
|
||||
/** Indicates if this subroutine basic block has been visited by a visitSubroutine(!null, ...) call. */
|
||||
static final int VISITED2 = 2048;
|
||||
/** Indicates if this subroutine basic block has been visited by a visitSubroutine(!null, ...) call. */
|
||||
static final int VISITED2 = 2048;
|
||||
|
||||
/**
|
||||
* Field used to associate user information to a label. Warning: this field is used by the ASM tree package. In
|
||||
* order to use it with the ASM tree package you must override the
|
||||
*/
|
||||
public Object info;
|
||||
/**
|
||||
* Field used to associate user information to a label. Warning: this field is used by the ASM tree package. In
|
||||
* order to use it with the ASM tree package you must override the
|
||||
*/
|
||||
public Object info;
|
||||
|
||||
/**
|
||||
* Flags that indicate the status of this label.
|
||||
*
|
||||
* @see #DEBUG
|
||||
* @see #RESOLVED
|
||||
* @see #RESIZED
|
||||
* @see #PUSHED
|
||||
* @see #TARGET
|
||||
* @see #STORE
|
||||
* @see #REACHABLE
|
||||
* @see #JSR
|
||||
* @see #RET
|
||||
*/
|
||||
int status;
|
||||
/**
|
||||
* Flags that indicate the status of this label.
|
||||
*
|
||||
* @see #DEBUG
|
||||
* @see #RESOLVED
|
||||
* @see #RESIZED
|
||||
* @see #PUSHED
|
||||
* @see #TARGET
|
||||
* @see #STORE
|
||||
* @see #REACHABLE
|
||||
* @see #JSR
|
||||
* @see #RET
|
||||
*/
|
||||
int status;
|
||||
|
||||
/**
|
||||
* The line number corresponding to this label, if known. If there are several lines, each line is stored in a
|
||||
* separate label, all linked via their next field (these links are created in ClassReader and removed just before
|
||||
* visitLabel is called, so that this does not impact the rest of the code).
|
||||
*/
|
||||
int line;
|
||||
/**
|
||||
* The line number corresponding to this label, if known. If there are several lines, each line is stored in a
|
||||
* separate label, all linked via their next field (these links are created in ClassReader and removed just before
|
||||
* visitLabel is called, so that this does not impact the rest of the code).
|
||||
*/
|
||||
int line;
|
||||
|
||||
/** The position of this label in the code, if known. */
|
||||
int position;
|
||||
/** The position of this label in the code, if known. */
|
||||
int position;
|
||||
|
||||
/** Number of forward references to this label, times two. */
|
||||
private int referenceCount;
|
||||
/** Number of forward references to this label, times two. */
|
||||
private int referenceCount;
|
||||
|
||||
/**
|
||||
* Informations about forward references. Each forward reference is described by two consecutive integers in this
|
||||
* array: the first one is the position of the first byte of the bytecode instruction that contains the forward
|
||||
* reference, while the second is the position of the first byte of the forward reference itself. In fact the sign
|
||||
* of the first integer indicates if this reference uses 2 or 4 bytes, and its absolute value gives the position of
|
||||
* the bytecode instruction. This array is also used as a bitset to store the subroutines to which a basic block
|
||||
* belongs. This information is needed in {@linked MethodWriter#visitMaxs}, after all forward references have been
|
||||
* resolved. Hence the same array can be used for both purposes without problems.
|
||||
*/
|
||||
private int[] srcAndRefPositions;
|
||||
/**
|
||||
* Informations about forward references. Each forward reference is described by two consecutive integers in this
|
||||
* array: the first one is the position of the first byte of the bytecode instruction that contains the forward
|
||||
* reference, while the second is the position of the first byte of the forward reference itself. In fact the sign
|
||||
* of the first integer indicates if this reference uses 2 or 4 bytes, and its absolute value gives the position of
|
||||
* the bytecode instruction. This array is also used as a bitset to store the subroutines to which a basic block
|
||||
* belongs. This information is needed in {@linked MethodWriter#visitMaxs}, after all forward references have been
|
||||
* resolved. Hence the same array can be used for both purposes without problems.
|
||||
*/
|
||||
private int[] srcAndRefPositions;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Fields for the control flow and data flow graph analysis algorithms (used
|
||||
* to compute the maximum stack size or the stack map frames). A control
|
||||
* flow graph contains one node per "basic block", and one edge per "jump"
|
||||
* from one basic block to another. Each node (i.e., each basic block) is
|
||||
* represented by the Label object that corresponds to the first instruction
|
||||
* of this basic block. Each node also stores the list of its successors in
|
||||
* the graph, as a linked list of Edge objects.
|
||||
*
|
||||
* The control flow analysis algorithms used to compute the maximum stack
|
||||
* size or the stack map frames are similar and use two steps. The first
|
||||
* step, during the visit of each instruction, builds information about the
|
||||
* state of the local variables and the operand stack at the end of each
|
||||
* basic block, called the "output frame", <i>relatively</i> to the frame
|
||||
* state at the beginning of the basic block, which is called the "input
|
||||
* frame", and which is <i>unknown</i> during this step. The second step, in
|
||||
* {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes
|
||||
* information about the input frame of each basic block, from the input
|
||||
* state of the first basic block (known from the method signature), and by
|
||||
* the using the previously computed relative output frames.
|
||||
*
|
||||
* The algorithm used to compute the maximum stack size only computes the
|
||||
* relative output and absolute input stack heights, while the algorithm
|
||||
* used to compute stack map frames computes relative output frames and
|
||||
* absolute input frames.
|
||||
*/
|
||||
/*
|
||||
* Fields for the control flow and data flow graph analysis algorithms (used
|
||||
* to compute the maximum stack size or the stack map frames). A control
|
||||
* flow graph contains one node per "basic block", and one edge per "jump"
|
||||
* from one basic block to another. Each node (i.e., each basic block) is
|
||||
* represented by the Label object that corresponds to the first instruction
|
||||
* of this basic block. Each node also stores the list of its successors in
|
||||
* the graph, as a linked list of Edge objects.
|
||||
*
|
||||
* The control flow analysis algorithms used to compute the maximum stack
|
||||
* size or the stack map frames are similar and use two steps. The first
|
||||
* step, during the visit of each instruction, builds information about the
|
||||
* state of the local variables and the operand stack at the end of each
|
||||
* basic block, called the "output frame", <i>relatively</i> to the frame
|
||||
* state at the beginning of the basic block, which is called the "input
|
||||
* frame", and which is <i>unknown</i> during this step. The second step, in
|
||||
* {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes
|
||||
* information about the input frame of each basic block, from the input
|
||||
* state of the first basic block (known from the method signature), and by
|
||||
* the using the previously computed relative output frames.
|
||||
*
|
||||
* The algorithm used to compute the maximum stack size only computes the
|
||||
* relative output and absolute input stack heights, while the algorithm
|
||||
* used to compute stack map frames computes relative output frames and
|
||||
* absolute input frames.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Start of the output stack relatively to the input stack. The exact semantics of this field depends on the
|
||||
* algorithm that is used.
|
||||
*
|
||||
* <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
|
||||
* relatively to the top of the input stack. This offset is always negative or null. A null offset means that the
|
||||
* output stack must be appended to the input stack. A -n offset means that the first n output stack elements must
|
||||
* replace the top n input stack elements, and that the other elements must be appended to the input stack.
|
||||
*/
|
||||
int inputStackTop;
|
||||
/**
|
||||
* Start of the output stack relatively to the input stack. The exact semantics of this field depends on the
|
||||
* 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 the stack map frames are completely computed, this field is the offset of the first output stack element
|
||||
* relatively to the top of the input stack. This offset is always negative or null. A null offset means that the
|
||||
* output stack must be appended to the input stack. A -n offset means that the first n output stack elements must
|
||||
* replace the top n input stack elements, and that the other elements must be appended to the input stack.
|
||||
*/
|
||||
int inputStackTop;
|
||||
|
||||
/**
|
||||
* Maximum height reached by the output stack, relatively to the top of the input stack. This maximum is always
|
||||
* positive or null.
|
||||
*/
|
||||
int outputStackMax;
|
||||
/**
|
||||
* Maximum height reached by the output stack, relatively to the top of the input stack. This maximum is always
|
||||
* positive or null.
|
||||
*/
|
||||
int outputStackMax;
|
||||
|
||||
/**
|
||||
* Information about the input and output stack map frames of this basic block. This field is only used when
|
||||
* {@link ClassWriter#COMPUTE_FRAMES} option is used.
|
||||
*/
|
||||
Frame frame;
|
||||
/**
|
||||
* Information about the input and output stack map frames of this basic block. This field is only used when
|
||||
* {@link ClassWriter#COMPUTE_FRAMES} option is used.
|
||||
*/
|
||||
Frame frame;
|
||||
|
||||
/**
|
||||
* The successor of this label, in the order they are visited. This linked list does not include labels used for
|
||||
* debug info only. If {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it does not contain
|
||||
* successive labels that denote the same bytecode position (in this case only the first label appears in this
|
||||
* list).
|
||||
*/
|
||||
Label successor;
|
||||
/**
|
||||
* The successor of this label, in the order they are visited. This linked list does not include labels used for
|
||||
* debug info only. If {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it does not contain
|
||||
* successive labels that denote the same bytecode position (in this case only the first label appears in this
|
||||
* list).
|
||||
*/
|
||||
Label successor;
|
||||
|
||||
/**
|
||||
* The successors of this node in the control flow graph. These successors are stored in a linked list of
|
||||
* {@link Edge Edge} objects, linked to each other by their {@link Edge#next} field.
|
||||
*/
|
||||
Edge successors;
|
||||
/**
|
||||
* The successors of this node in the control flow graph. These successors are stored in a linked list of
|
||||
* {@link Edge Edge} objects, linked to each other by their {@link Edge#next} field.
|
||||
*/
|
||||
Edge successors;
|
||||
|
||||
/**
|
||||
* The next basic block in the basic block stack. This stack is used in the main loop of the fix point algorithm
|
||||
* used in the second step of the control flow analysis algorithms. It is also used in {@link #visitSubroutine} to
|
||||
* avoid using a recursive method, and in ClassReader to temporarily store multiple source lines for a label.
|
||||
*
|
||||
* @see MethodWriter#visitMaxs
|
||||
*/
|
||||
Label next;
|
||||
/**
|
||||
* The next basic block in the basic block stack. This stack is used in the main loop of the fix point algorithm
|
||||
* used in the second step of the control flow analysis algorithms. It is also used in {@link #visitSubroutine} to
|
||||
* avoid using a recursive method, and in ClassReader to temporarily store multiple source lines for a label.
|
||||
*
|
||||
* @see MethodWriter#visitMaxs
|
||||
*/
|
||||
Label next;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// ------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Constructs a new label. */
|
||||
public Label() {
|
||||
// do nothing
|
||||
}
|
||||
/** Constructs a new label. */
|
||||
public Label() {
|
||||
// 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.
|
||||
* <i>This method is intended for {@link Attribute} sub classes, and is normally not needed by class generators or
|
||||
* adapters.</i>
|
||||
*
|
||||
* @return the offset corresponding to this label.
|
||||
* @throws IllegalStateException if this label is not resolved yet.
|
||||
*/
|
||||
public int getOffset() {
|
||||
if ((status & RESOLVED) == 0) {
|
||||
throw new IllegalStateException("Label offset position has not been resolved yet");
|
||||
}
|
||||
return position;
|
||||
}
|
||||
/**
|
||||
* Returns the offset corresponding to this label. This offset is computed from the start of the method's bytecode.
|
||||
* <i>This method is intended for {@link Attribute} sub classes, and is normally not needed by class generators or
|
||||
* adapters.</i>
|
||||
*
|
||||
* @return the offset corresponding to this label.
|
||||
* @throws IllegalStateException if this label is not resolved yet.
|
||||
*/
|
||||
public int getOffset() {
|
||||
if ((status & RESOLVED) == 0) {
|
||||
throw new IllegalStateException("Label offset position has not been resolved yet");
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a reference to this label in the bytecode of a method. If the position of the label is known, the offset is
|
||||
* computed and written directly. Otherwise, a null offset is written and a new forward reference is declared for
|
||||
* this label.
|
||||
*
|
||||
* @param owner the code writer that calls this method.
|
||||
* @param out the bytecode of the method.
|
||||
* @param source the position of first byte of the bytecode instruction that contains this label.
|
||||
* @param wideOffset <tt>true</tt> if the reference must be stored in 4 bytes, or
|
||||
* <tt>false</tt> if it must be stored with 2 bytes.
|
||||
* @throws IllegalArgumentException if this label has not been created by the given code writer.
|
||||
*/
|
||||
void put(final MethodWriter owner, final ByteVector out, final int source, final boolean wideOffset) {
|
||||
if ((status & RESOLVED) == 0) {
|
||||
if (wideOffset) {
|
||||
addReference(-1 - source, out.length);
|
||||
out.putInt(-1);
|
||||
} else {
|
||||
addReference(source, out.length);
|
||||
out.putShort(-1);
|
||||
}
|
||||
} else {
|
||||
if (wideOffset) {
|
||||
out.putInt(position - source);
|
||||
} else {
|
||||
out.putShort(position - source);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Puts a reference to this label in the bytecode of a method. If the position of the label is known, the offset is
|
||||
* computed and written directly. Otherwise, a null offset is written and a new forward reference is declared for
|
||||
* this label.
|
||||
*
|
||||
* @param owner the code writer that calls this method.
|
||||
* @param out the bytecode of the method.
|
||||
* @param source the position of first byte of the bytecode instruction that contains this label.
|
||||
* @param wideOffset <tt>true</tt> if the reference must be stored in 4 bytes, or
|
||||
* <tt>false</tt> if it must be stored with 2 bytes.
|
||||
* @throws IllegalArgumentException if this label has not been created by the given code writer.
|
||||
*/
|
||||
void put(final MethodWriter owner, final ByteVector out, final int source, final boolean wideOffset) {
|
||||
if ((status & RESOLVED) == 0) {
|
||||
if (wideOffset) {
|
||||
addReference(-1 - source, out.length);
|
||||
out.putInt(-1);
|
||||
} else {
|
||||
addReference(source, out.length);
|
||||
out.putShort(-1);
|
||||
}
|
||||
} else {
|
||||
if (wideOffset) {
|
||||
out.putInt(position - source);
|
||||
} else {
|
||||
out.putShort(position - source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a forward reference to this label. This method must be called only for a true forward reference, i.e. only
|
||||
* if this label is not resolved yet. For backward references, the offset of the reference can be, and must be,
|
||||
* computed and stored directly.
|
||||
*
|
||||
* @param sourcePosition the position of the referencing instruction. This position will be used to compute the
|
||||
* offset of this forward reference.
|
||||
* @param referencePosition the position where the offset for this forward reference must be stored.
|
||||
*/
|
||||
private void addReference(final int sourcePosition, final int referencePosition) {
|
||||
if (srcAndRefPositions == null) {
|
||||
srcAndRefPositions = new int[6];
|
||||
}
|
||||
if (referenceCount >= srcAndRefPositions.length) {
|
||||
int[] a = new int[srcAndRefPositions.length + 6];
|
||||
System.arraycopy(srcAndRefPositions, 0, a, 0, srcAndRefPositions.length);
|
||||
srcAndRefPositions = a;
|
||||
}
|
||||
srcAndRefPositions[referenceCount++] = sourcePosition;
|
||||
srcAndRefPositions[referenceCount++] = referencePosition;
|
||||
}
|
||||
/**
|
||||
* Adds a forward reference to this label. This method must be called only for a true forward reference, i.e. only
|
||||
* if this label is not resolved yet. For backward references, the offset of the reference can be, and must be,
|
||||
* computed and stored directly.
|
||||
*
|
||||
* @param sourcePosition the position of the referencing instruction. This position will be used to compute the
|
||||
* offset of this forward reference.
|
||||
* @param referencePosition the position where the offset for this forward reference must be stored.
|
||||
*/
|
||||
private void addReference(final int sourcePosition, final int referencePosition) {
|
||||
if (srcAndRefPositions == null) {
|
||||
srcAndRefPositions = new int[6];
|
||||
}
|
||||
if (referenceCount >= srcAndRefPositions.length) {
|
||||
int[] a = new int[srcAndRefPositions.length + 6];
|
||||
System.arraycopy(srcAndRefPositions, 0, a, 0, srcAndRefPositions.length);
|
||||
srcAndRefPositions = a;
|
||||
}
|
||||
srcAndRefPositions[referenceCount++] = sourcePosition;
|
||||
srcAndRefPositions[referenceCount++] = referencePosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves all forward references to this label. This method must be called when this label is added to the
|
||||
* bytecode of the method, i.e. when its position becomes known. This method fills in the blanks that where left in
|
||||
* the bytecode by each forward reference previously added to this label.
|
||||
*
|
||||
* @param owner the code writer that calls this method.
|
||||
* @param position the position of this label in the bytecode.
|
||||
* @param data the bytecode of the method.
|
||||
* @return <tt>true</tt> if a blank that was left for this label was too small to store the offset.
|
||||
* In such a case the corresponding jump instruction is replaced with a pseudo instruction (using unused
|
||||
* opcodes) using an unsigned two bytes offset. These pseudo instructions will be replaced with standard
|
||||
* bytecode instructions with wider offsets (4 bytes instead of 2), in ClassReader.
|
||||
* @throws IllegalArgumentException if this label has already been resolved, or if it has not been created by the
|
||||
* given code writer.
|
||||
*/
|
||||
boolean resolve(final MethodWriter owner, final int position, final byte[] data) {
|
||||
boolean needUpdate = false;
|
||||
this.status |= RESOLVED;
|
||||
this.position = position;
|
||||
int i = 0;
|
||||
while (i < referenceCount) {
|
||||
int source = srcAndRefPositions[i++];
|
||||
int reference = srcAndRefPositions[i++];
|
||||
int offset;
|
||||
if (source >= 0) {
|
||||
offset = position - source;
|
||||
if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
|
||||
/*
|
||||
* changes the opcode of the jump instruction, in order to
|
||||
* be able to find it later (see resizeInstructions in
|
||||
* MethodWriter). These temporary opcodes are similar to
|
||||
* jump instruction opcodes, except that the 2 bytes offset
|
||||
* is unsigned (and can therefore represent values from 0 to
|
||||
* 65535, which is sufficient since the size of a method is
|
||||
* limited to 65535 bytes).
|
||||
*/
|
||||
int opcode = data[reference - 1] & 0xFF;
|
||||
if (opcode <= Opcodes.JSR) {
|
||||
// changes IFEQ ... JSR to opcodes 202 to 217
|
||||
data[reference - 1] = (byte) (opcode + 49);
|
||||
} else {
|
||||
// changes IFNULL and IFNONNULL to opcodes 218 and 219
|
||||
data[reference - 1] = (byte) (opcode + 20);
|
||||
}
|
||||
needUpdate = true;
|
||||
}
|
||||
data[reference++] = (byte) (offset >>> 8);
|
||||
data[reference] = (byte) offset;
|
||||
} else {
|
||||
offset = position + source + 1;
|
||||
data[reference++] = (byte) (offset >>> 24);
|
||||
data[reference++] = (byte) (offset >>> 16);
|
||||
data[reference++] = (byte) (offset >>> 8);
|
||||
data[reference] = (byte) offset;
|
||||
}
|
||||
}
|
||||
return needUpdate;
|
||||
}
|
||||
/**
|
||||
* Resolves all forward references to this label. This method must be called when this label is added to the
|
||||
* bytecode of the method, i.e. when its position becomes known. This method fills in the blanks that where left in
|
||||
* the bytecode by each forward reference previously added to this label.
|
||||
*
|
||||
* @param owner the code writer that calls this method.
|
||||
* @param position the position of this label in the bytecode.
|
||||
* @param data the bytecode of the method.
|
||||
* @return <tt>true</tt> if a blank that was left for this label was too small to store the offset.
|
||||
* In such a case the corresponding jump instruction is replaced with a pseudo instruction (using unused
|
||||
* opcodes) using an unsigned two bytes offset. These pseudo instructions will be replaced with standard
|
||||
* bytecode instructions with wider offsets (4 bytes instead of 2), in ClassReader.
|
||||
* @throws IllegalArgumentException if this label has already been resolved, or if it has not been created by the
|
||||
* given code writer.
|
||||
*/
|
||||
boolean resolve(final MethodWriter owner, final int position, final byte[] data) {
|
||||
boolean needUpdate = false;
|
||||
this.status |= RESOLVED;
|
||||
this.position = position;
|
||||
int i = 0;
|
||||
while (i < referenceCount) {
|
||||
int source = srcAndRefPositions[i++];
|
||||
int reference = srcAndRefPositions[i++];
|
||||
int offset;
|
||||
if (source >= 0) {
|
||||
offset = position - source;
|
||||
if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
|
||||
/*
|
||||
* changes the opcode of the jump instruction, in order to
|
||||
* be able to find it later (see resizeInstructions in
|
||||
* MethodWriter). These temporary opcodes are similar to
|
||||
* jump instruction opcodes, except that the 2 bytes offset
|
||||
* is unsigned (and can therefore represent values from 0 to
|
||||
* 65535, which is sufficient since the size of a method is
|
||||
* limited to 65535 bytes).
|
||||
*/
|
||||
int opcode = data[reference - 1] & 0xFF;
|
||||
if (opcode <= Opcodes.JSR) {
|
||||
// changes IFEQ ... JSR to opcodes 202 to 217
|
||||
data[reference - 1] = (byte) (opcode + 49);
|
||||
} else {
|
||||
// changes IFNULL and IFNONNULL to opcodes 218 and 219
|
||||
data[reference - 1] = (byte) (opcode + 20);
|
||||
}
|
||||
needUpdate = true;
|
||||
}
|
||||
data[reference++] = (byte) (offset >>> 8);
|
||||
data[reference] = (byte) offset;
|
||||
} else {
|
||||
offset = position + source + 1;
|
||||
data[reference++] = (byte) (offset >>> 24);
|
||||
data[reference++] = (byte) (offset >>> 16);
|
||||
data[reference++] = (byte) (offset >>> 8);
|
||||
data[reference] = (byte) offset;
|
||||
}
|
||||
}
|
||||
return needUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first label of the series to which this label belongs. For an isolated label or for the first label
|
||||
* in a series of successive labels, this method returns the label itself. For other labels it returns the first
|
||||
* label of the series.
|
||||
*
|
||||
* @return the first label of the series to which this label belongs.
|
||||
*/
|
||||
Label getFirst() {
|
||||
return frame == null ? this : frame.owner;
|
||||
}
|
||||
/**
|
||||
* Returns the first label of the series to which this label belongs. For an isolated label or for the first label
|
||||
* in a series of successive labels, this method returns the label itself. For other labels it returns the first
|
||||
* label of the series.
|
||||
*
|
||||
* @return the first label of the series to which this label belongs.
|
||||
*/
|
||||
Label getFirst() {
|
||||
return frame == null ? this : frame.owner;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Methods related to subroutines
|
||||
// ------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
// Methods related to subroutines
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns true is this basic block belongs to the given subroutine.
|
||||
*
|
||||
* @param id a subroutine id.
|
||||
* @return true is this basic block belongs to the given subroutine.
|
||||
*/
|
||||
boolean inSubroutine(final long id) {
|
||||
if ((status & Label.VISITED) != 0) {
|
||||
return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns true is this basic block belongs to the given subroutine.
|
||||
*
|
||||
* @param id a subroutine id.
|
||||
* @return true is this basic block belongs to the given subroutine.
|
||||
*/
|
||||
boolean inSubroutine(final long id) {
|
||||
if ((status & Label.VISITED) != 0) {
|
||||
return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this basic block and the given one belong to a common subroutine.
|
||||
*
|
||||
* @param block another basic block.
|
||||
* @return true if this basic block and the given one belong to a common subroutine.
|
||||
*/
|
||||
boolean inSameSubroutine(final Label block) {
|
||||
if ((status & VISITED) == 0 || (block.status & VISITED) == 0) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < srcAndRefPositions.length; ++i) {
|
||||
if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns true if this basic block and the given one belong to a common subroutine.
|
||||
*
|
||||
* @param block another basic block.
|
||||
* @return true if this basic block and the given one belong to a common subroutine.
|
||||
*/
|
||||
boolean inSameSubroutine(final Label block) {
|
||||
if ((status & VISITED) == 0 || (block.status & VISITED) == 0) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < srcAndRefPositions.length; ++i) {
|
||||
if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this basic block as belonging to the given subroutine.
|
||||
*
|
||||
* @param id a subroutine id.
|
||||
* @param nbSubroutines the total number of subroutines in the method.
|
||||
*/
|
||||
void addToSubroutine(final long id, final int nbSubroutines) {
|
||||
if ((status & VISITED) == 0) {
|
||||
status |= VISITED;
|
||||
srcAndRefPositions = new int[nbSubroutines / 32 + 1];
|
||||
}
|
||||
srcAndRefPositions[(int) (id >>> 32)] |= (int) id;
|
||||
}
|
||||
/**
|
||||
* Marks this basic block as belonging to the given subroutine.
|
||||
*
|
||||
* @param id a subroutine id.
|
||||
* @param nbSubroutines the total number of subroutines in the method.
|
||||
*/
|
||||
void addToSubroutine(final long id, final int nbSubroutines) {
|
||||
if ((status & VISITED) == 0) {
|
||||
status |= VISITED;
|
||||
srcAndRefPositions = new int[nbSubroutines / 32 + 1];
|
||||
}
|
||||
srcAndRefPositions[(int) (id >>> 32)] |= (int) id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the basic blocks that belong to a given subroutine, and marks these blocks as belonging to this subroutine.
|
||||
* This method follows the control flow graph to find all the blocks that are reachable from the current block
|
||||
* WITHOUT following any JSR target.
|
||||
*
|
||||
* @param JSR a JSR block that jumps to this subroutine. If this JSR is not null it is added to the successor of the
|
||||
* RET blocks found in the subroutine.
|
||||
* @param id the id of this subroutine.
|
||||
* @param nbSubroutines the total number of subroutines in the method.
|
||||
*/
|
||||
void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) {
|
||||
// user managed stack of labels, to avoid using a recursive method
|
||||
// (recursivity can lead to stack overflow with very large methods)
|
||||
Label stack = this;
|
||||
while (stack != null) {
|
||||
// removes a label l from the stack
|
||||
Label l = stack;
|
||||
stack = l.next;
|
||||
l.next = null;
|
||||
/**
|
||||
* Finds the basic blocks that belong to a given subroutine, and marks these blocks as belonging to this subroutine.
|
||||
* This method follows the control flow graph to find all the blocks that are reachable from the current block
|
||||
* WITHOUT following any JSR target.
|
||||
*
|
||||
* @param JSR a JSR block that jumps to this subroutine. If this JSR is not null it is added to the successor of the
|
||||
* RET blocks found in the subroutine.
|
||||
* @param id the id of this subroutine.
|
||||
* @param nbSubroutines the total number of subroutines in the method.
|
||||
*/
|
||||
void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) {
|
||||
// user managed stack of labels, to avoid using a recursive method
|
||||
// (recursivity can lead to stack overflow with very large methods)
|
||||
Label stack = this;
|
||||
while (stack != null) {
|
||||
// removes a label l from the stack
|
||||
Label l = stack;
|
||||
stack = l.next;
|
||||
l.next = null;
|
||||
|
||||
if (JSR != null) {
|
||||
if ((l.status & VISITED2) != 0) {
|
||||
continue;
|
||||
}
|
||||
l.status |= VISITED2;
|
||||
// adds JSR to the successors of l, if it is a RET block
|
||||
if ((l.status & RET) != 0) {
|
||||
if (!l.inSameSubroutine(JSR)) {
|
||||
Edge e = new Edge();
|
||||
e.info = l.inputStackTop;
|
||||
e.successor = JSR.successors.successor;
|
||||
e.next = l.successors;
|
||||
l.successors = e;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if the l block already belongs to subroutine 'id', continue
|
||||
if (l.inSubroutine(id)) {
|
||||
continue;
|
||||
}
|
||||
// marks the l block as belonging to subroutine 'id'
|
||||
l.addToSubroutine(id, nbSubroutines);
|
||||
}
|
||||
// pushes each successor of l on the stack, except JSR targets
|
||||
Edge e = l.successors;
|
||||
while (e != null) {
|
||||
// if the l block is a JSR block, then 'l.successors.next' leads
|
||||
// to the JSR target (see {@link #visitJumpInsn}) and must
|
||||
// therefore not be followed
|
||||
if ((l.status & Label.JSR) == 0 || e != l.successors.next) {
|
||||
// pushes e.successor on the stack if it not already added
|
||||
if (e.successor.next == null) {
|
||||
e.successor.next = stack;
|
||||
stack = e.successor;
|
||||
}
|
||||
}
|
||||
e = e.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (JSR != null) {
|
||||
if ((l.status & VISITED2) != 0) {
|
||||
continue;
|
||||
}
|
||||
l.status |= VISITED2;
|
||||
// adds JSR to the successors of l, if it is a RET block
|
||||
if ((l.status & RET) != 0) {
|
||||
if (!l.inSameSubroutine(JSR)) {
|
||||
Edge e = new Edge();
|
||||
e.info = l.inputStackTop;
|
||||
e.successor = JSR.successors.successor;
|
||||
e.next = l.successors;
|
||||
l.successors = e;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if the l block already belongs to subroutine 'id', continue
|
||||
if (l.inSubroutine(id)) {
|
||||
continue;
|
||||
}
|
||||
// marks the l block as belonging to subroutine 'id'
|
||||
l.addToSubroutine(id, nbSubroutines);
|
||||
}
|
||||
// pushes each successor of l on the stack, except JSR targets
|
||||
Edge e = l.successors;
|
||||
while (e != null) {
|
||||
// if the l block is a JSR block, then 'l.successors.next' leads
|
||||
// to the JSR target (see {@link #visitJumpInsn}) and must
|
||||
// therefore not be followed
|
||||
if ((l.status & Label.JSR) == 0 || e != l.successors.next) {
|
||||
// pushes e.successor on the stack if it not already added
|
||||
if (e.successor.next == null) {
|
||||
e.successor.next = stack;
|
||||
stack = e.successor;
|
||||
}
|
||||
}
|
||||
e = e.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Overriden Object methods
|
||||
// ------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
// Overriden Object methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a string representation of this label.
|
||||
*
|
||||
* @return a string representation of this label.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "L" + System.identityHashCode(this);
|
||||
}
|
||||
/**
|
||||
* Returns a string representation of this label.
|
||||
*
|
||||
* @return a string representation of this label.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "L" + System.identityHashCode(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,248 +16,248 @@ import java.util.*;
|
||||
*/
|
||||
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) {
|
||||
debug = d;
|
||||
return this;
|
||||
}
|
||||
public MethodDebugVisitor setDebug(boolean d) {
|
||||
debug = d;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void debugLine() {
|
||||
if (!debug) {
|
||||
return;
|
||||
}
|
||||
System.out.println();
|
||||
System.out.println();
|
||||
System.out.println();
|
||||
}
|
||||
public void debugLine() {
|
||||
if (!debug) {
|
||||
return;
|
||||
}
|
||||
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 {
|
||||
try {
|
||||
for (java.lang.reflect.Field field : Opcodes.class.getFields()) {
|
||||
String name = field.getName();
|
||||
if (name.startsWith("ASM")) {
|
||||
continue;
|
||||
}
|
||||
if (name.startsWith("V1_")) {
|
||||
continue;
|
||||
}
|
||||
if (name.startsWith("ACC_")) {
|
||||
continue;
|
||||
}
|
||||
if (name.startsWith("T_")) {
|
||||
continue;
|
||||
}
|
||||
if (name.startsWith("H_")) {
|
||||
continue;
|
||||
}
|
||||
if (name.startsWith("F_")) {
|
||||
continue;
|
||||
}
|
||||
if (field.getType() != int.class) {
|
||||
continue;
|
||||
}
|
||||
opcodes[(int) (Integer) field.get(null)] = name;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex); // 不可能会发生
|
||||
}
|
||||
}
|
||||
static {
|
||||
try {
|
||||
for (java.lang.reflect.Field field : Opcodes.class.getFields()) {
|
||||
String name = field.getName();
|
||||
if (name.startsWith("ASM")) {
|
||||
continue;
|
||||
}
|
||||
if (name.startsWith("V1_")) {
|
||||
continue;
|
||||
}
|
||||
if (name.startsWith("ACC_")) {
|
||||
continue;
|
||||
}
|
||||
if (name.startsWith("T_")) {
|
||||
continue;
|
||||
}
|
||||
if (name.startsWith("H_")) {
|
||||
continue;
|
||||
}
|
||||
if (name.startsWith("F_")) {
|
||||
continue;
|
||||
}
|
||||
if (field.getType() != int.class) {
|
||||
continue;
|
||||
}
|
||||
opcodes[(int) (Integer) field.get(null)] = name;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex); // 不可能会发生
|
||||
}
|
||||
}
|
||||
|
||||
/** @param visitor MethodVisitor */
|
||||
public MethodDebugVisitor(MethodVisitor visitor) {
|
||||
super(Opcodes.ASM6, visitor);
|
||||
this.visitor = visitor;
|
||||
}
|
||||
/** @param visitor MethodVisitor */
|
||||
public MethodDebugVisitor(MethodVisitor visitor) {
|
||||
super(Opcodes.ASM6, visitor);
|
||||
this.visitor = visitor;
|
||||
}
|
||||
|
||||
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
|
||||
visitor.visitTryCatchBlock(start, end, handler, type);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitTryCatchBlock(label0, label1, label2, \"" + type + "\");");
|
||||
}
|
||||
}
|
||||
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
|
||||
visitor.visitTryCatchBlock(start, end, handler, type);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitTryCatchBlock(label0, label1, label2, \"" + type + "\");");
|
||||
}
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitParameterAnnotation(int i, String string, boolean bln) {
|
||||
AnnotationVisitor av = visitor.visitParameterAnnotation(i, string, bln);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitParameterAnnotation(" + i + ", \"" + string + "\", " + bln + ");");
|
||||
}
|
||||
return av;
|
||||
}
|
||||
public AnnotationVisitor visitParameterAnnotation(int i, String string, boolean bln) {
|
||||
AnnotationVisitor av = visitor.visitParameterAnnotation(i, string, bln);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitParameterAnnotation(" + i + ", \"" + string + "\", " + bln + ");");
|
||||
}
|
||||
return av;
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean flag) {
|
||||
AnnotationVisitor av = visitor.visitAnnotation(desc, flag);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitAnnotation(\"" + desc + "\", " + flag + ");");
|
||||
}
|
||||
return av;
|
||||
}
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean flag) {
|
||||
AnnotationVisitor av = visitor.visitAnnotation(desc, flag);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitAnnotation(\"" + desc + "\", " + flag + ");");
|
||||
}
|
||||
return av;
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
|
||||
AnnotationVisitor av = visitor.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
if (debug) {
|
||||
System.out.println(
|
||||
"mv.visitTypeAnnotation(" + typeRef + ", " + typePath + ", \"" + desc + "\", " + visible + ");");
|
||||
}
|
||||
return av;
|
||||
}
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
|
||||
AnnotationVisitor av = visitor.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
if (debug) {
|
||||
System.out.println(
|
||||
"mv.visitTypeAnnotation(" + typeRef + ", " + typePath + ", \"" + desc + "\", " + visible + ");");
|
||||
}
|
||||
return av;
|
||||
}
|
||||
|
||||
public void visitParameter(String name, int access) {
|
||||
visitor.visitParameter(name, access);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitParameter(" + name + ", " + access + ");");
|
||||
}
|
||||
}
|
||||
public void visitParameter(String name, int access) {
|
||||
visitor.visitParameter(name, access);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitParameter(" + name + ", " + access + ");");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitVarInsn(int opcode, int var) {
|
||||
visitor.visitVarInsn(opcode, var);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitVarInsn(" + opcodes[opcode] + ", " + var + ");");
|
||||
}
|
||||
}
|
||||
public void visitVarInsn(int opcode, int var) {
|
||||
visitor.visitVarInsn(opcode, var);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitVarInsn(" + opcodes[opcode] + ", " + var + ");");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
|
||||
visitor.visitFrame(type, nLocal, local, nStack, stack);
|
||||
if (debug) {
|
||||
String typestr = "" + type;
|
||||
if (type == -1) {
|
||||
typestr = "Opcodes.F_NEW";
|
||||
} else if (type == 1) {
|
||||
typestr = "Opcodes.F_APPEND";
|
||||
} else if (type == 2) {
|
||||
typestr = "Opcodes.F_CHOP";
|
||||
} else if (type == 3) {
|
||||
typestr = "Opcodes.F_SAME";
|
||||
} else if (type == 4) {
|
||||
typestr = "Opcodes.F_SAME1";
|
||||
}
|
||||
System.out.println("mv.visitFrame(" + typestr + ", " + nLocal + ", " + Arrays.toString(local) + ", "
|
||||
+ nStack + ", " + Arrays.toString(stack) + ");");
|
||||
}
|
||||
}
|
||||
public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
|
||||
visitor.visitFrame(type, nLocal, local, nStack, stack);
|
||||
if (debug) {
|
||||
String typestr = "" + type;
|
||||
if (type == -1) {
|
||||
typestr = "Opcodes.F_NEW";
|
||||
} else if (type == 1) {
|
||||
typestr = "Opcodes.F_APPEND";
|
||||
} else if (type == 2) {
|
||||
typestr = "Opcodes.F_CHOP";
|
||||
} else if (type == 3) {
|
||||
typestr = "Opcodes.F_SAME";
|
||||
} else if (type == 4) {
|
||||
typestr = "Opcodes.F_SAME1";
|
||||
}
|
||||
System.out.println("mv.visitFrame(" + typestr + ", " + nLocal + ", " + Arrays.toString(local) + ", "
|
||||
+ nStack + ", " + Arrays.toString(stack) + ");");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitJumpInsn(int opcode, Label var) { // 调用此方法的 ClassWriter 必须由 COMPUTE_FRAMES 构建
|
||||
visitor.visitJumpInsn(opcode, var);
|
||||
if (debug) {
|
||||
Integer index = labels.get(var);
|
||||
if (index == null) {
|
||||
index = labels.size();
|
||||
labels.put(var, index);
|
||||
System.out.println("Label l" + index + " = new Label();");
|
||||
}
|
||||
System.out.println("mv.visitJumpInsn(" + opcodes[opcode] + ", l" + index + ");");
|
||||
}
|
||||
}
|
||||
public void visitJumpInsn(int opcode, Label var) { // 调用此方法的 ClassWriter 必须由 COMPUTE_FRAMES 构建
|
||||
visitor.visitJumpInsn(opcode, var);
|
||||
if (debug) {
|
||||
Integer index = labels.get(var);
|
||||
if (index == null) {
|
||||
index = labels.size();
|
||||
labels.put(var, index);
|
||||
System.out.println("Label l" + index + " = new Label();");
|
||||
}
|
||||
System.out.println("mv.visitJumpInsn(" + opcodes[opcode] + ", l" + index + ");");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitCode() {
|
||||
visitor.visitCode();
|
||||
if (debug) {
|
||||
System.out.println("mv.visitCode();");
|
||||
}
|
||||
}
|
||||
public void visitCode() {
|
||||
visitor.visitCode();
|
||||
if (debug) {
|
||||
System.out.println("mv.visitCode();");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitLabel(Label var) {
|
||||
visitor.visitLabel(var);
|
||||
if (debug) {
|
||||
Integer index = labels.get(var);
|
||||
if (index == null) {
|
||||
index = labels.size();
|
||||
labels.put(var, index);
|
||||
System.out.println("Label l" + index + " = new Label();");
|
||||
}
|
||||
System.out.println("mv.visitLabel(l" + index + ");");
|
||||
}
|
||||
}
|
||||
public void visitLabel(Label var) {
|
||||
visitor.visitLabel(var);
|
||||
if (debug) {
|
||||
Integer index = labels.get(var);
|
||||
if (index == null) {
|
||||
index = labels.size();
|
||||
labels.put(var, index);
|
||||
System.out.println("Label l" + index + " = new Label();");
|
||||
}
|
||||
System.out.println("mv.visitLabel(l" + index + ");");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
|
||||
visitor.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitMethodInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \""
|
||||
+ desc + "\", " + itf + ");");
|
||||
}
|
||||
}
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
|
||||
visitor.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitMethodInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \""
|
||||
+ desc + "\", " + itf + ");");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
|
||||
visitor.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitInvokeDynamicInsn(\"" + name + "\", \"" + desc + "\", null, null);");
|
||||
}
|
||||
}
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
|
||||
visitor.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitInvokeDynamicInsn(\"" + name + "\", \"" + desc + "\", null, null);");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
|
||||
visitor.visitLocalVariable(name, desc, signature, start, end, index);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitLocalVariable(\"" + name + "\", \"" + desc + "\", \"" + signature
|
||||
+ "\", null, null, " + index + ");");
|
||||
}
|
||||
}
|
||||
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
|
||||
visitor.visitLocalVariable(name, desc, signature, start, end, index);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitLocalVariable(\"" + name + "\", \"" + desc + "\", \"" + signature
|
||||
+ "\", null, null, " + index + ");");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
|
||||
visitor.visitFieldInsn(opcode, owner, name, desc);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitFieldInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \""
|
||||
+ desc + "\");");
|
||||
}
|
||||
}
|
||||
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
|
||||
visitor.visitFieldInsn(opcode, owner, name, desc);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitFieldInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \""
|
||||
+ desc + "\");");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitTypeInsn(int opcode, String type) {
|
||||
visitor.visitTypeInsn(opcode, type);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitTypeInsn(" + opcodes[opcode] + ", \"" + type + "\");");
|
||||
}
|
||||
}
|
||||
public void visitTypeInsn(int opcode, String type) {
|
||||
visitor.visitTypeInsn(opcode, type);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitTypeInsn(" + opcodes[opcode] + ", \"" + type + "\");");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitInsn(int opcode) {
|
||||
visitor.visitInsn(opcode);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitInsn(" + opcodes[opcode] + ");");
|
||||
}
|
||||
}
|
||||
public void visitInsn(int opcode) {
|
||||
visitor.visitInsn(opcode);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitInsn(" + opcodes[opcode] + ");");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitIntInsn(int opcode, int value) {
|
||||
visitor.visitIntInsn(opcode, value);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitIntInsn(" + opcodes[opcode] + ", " + value + ");");
|
||||
}
|
||||
}
|
||||
public void visitIntInsn(int opcode, int value) {
|
||||
visitor.visitIntInsn(opcode, value);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitIntInsn(" + opcodes[opcode] + ", " + value + ");");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitIincInsn(int opcode, int value) {
|
||||
visitor.visitIincInsn(opcode, value);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitIincInsn(" + opcode + ", " + value + ");");
|
||||
}
|
||||
}
|
||||
public void visitIincInsn(int opcode, int value) {
|
||||
visitor.visitIincInsn(opcode, value);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitIincInsn(" + opcode + ", " + value + ");");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitLdcInsn(Object o) {
|
||||
visitor.visitLdcInsn(o);
|
||||
if (debug) {
|
||||
if (o instanceof CharSequence) {
|
||||
System.out.println("mv.visitLdcInsn(\"" + o + "\");");
|
||||
} else if (o instanceof org.redkale.asm.Type) {
|
||||
System.out.println("mv.visitLdcInsn(Type.getType(\"" + o + "\"));");
|
||||
} else {
|
||||
System.out.println("mv.visitLdcInsn(" + o + ");");
|
||||
}
|
||||
}
|
||||
}
|
||||
public void visitLdcInsn(Object o) {
|
||||
visitor.visitLdcInsn(o);
|
||||
if (debug) {
|
||||
if (o instanceof CharSequence) {
|
||||
System.out.println("mv.visitLdcInsn(\"" + o + "\");");
|
||||
} else if (o instanceof org.redkale.asm.Type) {
|
||||
System.out.println("mv.visitLdcInsn(Type.getType(\"" + o + "\"));");
|
||||
} else {
|
||||
System.out.println("mv.visitLdcInsn(" + o + ");");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
visitor.visitMaxs(maxStack, maxLocals);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitMaxs(" + maxStack + ", " + maxLocals + ");");
|
||||
}
|
||||
}
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
visitor.visitMaxs(maxStack, maxLocals);
|
||||
if (debug) {
|
||||
System.out.println("mv.visitMaxs(" + maxStack + ", " + maxLocals + ");");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitEnd() {
|
||||
visitor.visitEnd();
|
||||
if (debug) {
|
||||
System.out.println("mv.visitEnd();\r\n\r\n\r\n");
|
||||
}
|
||||
}
|
||||
public void visitEnd() {
|
||||
visitor.visitEnd();
|
||||
if (debug) {
|
||||
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
@@ -72,131 +72,131 @@ package org.redkale.asm;
|
||||
* @author Remi Forax
|
||||
*/
|
||||
public abstract class ModuleVisitor {
|
||||
/** The ASM API version implemented by this visitor. The value of this field must be {@link Opcodes#ASM6}. */
|
||||
protected final int api;
|
||||
/** The ASM API version implemented by this visitor. The value of this field must be {@link Opcodes#ASM6}. */
|
||||
protected final int api;
|
||||
|
||||
/** The module visitor to which this visitor must delegate method calls. May be null. */
|
||||
protected ModuleVisitor mv;
|
||||
/** The module visitor to which this visitor must delegate method calls. May be null. */
|
||||
protected ModuleVisitor mv;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ModuleVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
|
||||
*/
|
||||
public ModuleVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@link ModuleVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
|
||||
*/
|
||||
public ModuleVisitor(final int api) {
|
||||
this(api, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ModuleVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
|
||||
* @param mv the module visitor to which this visitor must delegate method calls. May be null.
|
||||
*/
|
||||
public ModuleVisitor(final int api, final ModuleVisitor mv) {
|
||||
if (api != Opcodes.ASM6) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.api = api;
|
||||
this.mv = mv;
|
||||
}
|
||||
/**
|
||||
* Constructs a new {@link ModuleVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
|
||||
* @param mv the module visitor to which this visitor must delegate method calls. May be null.
|
||||
*/
|
||||
public ModuleVisitor(final int api, final ModuleVisitor mv) {
|
||||
if (api != Opcodes.ASM6) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.api = api;
|
||||
this.mv = mv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit the main class of the current module.
|
||||
*
|
||||
* @param mainClass the internal name of the main class of the current module.
|
||||
*/
|
||||
public void visitMainClass(String mainClass) {
|
||||
if (mv != null) {
|
||||
mv.visitMainClass(mainClass);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visit the main class of the current module.
|
||||
*
|
||||
* @param mainClass the internal name of the main class of the current module.
|
||||
*/
|
||||
public void visitMainClass(String mainClass) {
|
||||
if (mv != null) {
|
||||
mv.visitMainClass(mainClass);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit a package of the current module.
|
||||
*
|
||||
* @param packaze the qualified name of a package.
|
||||
*/
|
||||
public void visitPackage(String packaze) {
|
||||
if (mv != null) {
|
||||
mv.visitPackage(packaze);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visit a package of the current module.
|
||||
*
|
||||
* @param packaze the qualified name of a package.
|
||||
*/
|
||||
public void visitPackage(String packaze) {
|
||||
if (mv != null) {
|
||||
mv.visitPackage(packaze);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a dependence of the current module.
|
||||
*
|
||||
* @param module the qualified name of the dependence.
|
||||
* @param access the access flag of the dependence among ACC_TRANSITIVE, ACC_STATIC_PHASE, ACC_SYNTHETIC and
|
||||
* ACC_MANDATED.
|
||||
* @param version the module version at compile time or null.
|
||||
*/
|
||||
public void visitRequire(String module, int access, String version) {
|
||||
if (mv != null) {
|
||||
mv.visitRequire(module, access, version);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visits a dependence of the current module.
|
||||
*
|
||||
* @param module the qualified name of the dependence.
|
||||
* @param access the access flag of the dependence among ACC_TRANSITIVE, ACC_STATIC_PHASE, ACC_SYNTHETIC and
|
||||
* ACC_MANDATED.
|
||||
* @param version the module version at compile time or null.
|
||||
*/
|
||||
public void visitRequire(String module, int access, String version) {
|
||||
if (mv != null) {
|
||||
mv.visitRequire(module, access, version);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit an exported package of the current module.
|
||||
*
|
||||
* @param packaze the qualified name of the exported package.
|
||||
* @param access the access flag of the exported package, valid values are among {@code ACC_SYNTHETIC} and
|
||||
* {@code ACC_MANDATED}.
|
||||
* @param modules the qualified names of the modules that can access to the public classes of the exported package
|
||||
* or <tt>null</tt>.
|
||||
*/
|
||||
public void visitExport(String packaze, int access, String... modules) {
|
||||
if (mv != null) {
|
||||
mv.visitExport(packaze, access, modules);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visit an exported package of the current module.
|
||||
*
|
||||
* @param packaze the qualified name of the exported package.
|
||||
* @param access the access flag of the exported package, valid values are among {@code ACC_SYNTHETIC} and
|
||||
* {@code ACC_MANDATED}.
|
||||
* @param modules the qualified names of the modules that can access to the public classes of the exported package
|
||||
* or <tt>null</tt>.
|
||||
*/
|
||||
public void visitExport(String packaze, int access, String... modules) {
|
||||
if (mv != null) {
|
||||
mv.visitExport(packaze, access, modules);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit an open package of the current module.
|
||||
*
|
||||
* @param packaze the qualified name of the opened package.
|
||||
* @param access the access flag of the opened package, valid values are among {@code ACC_SYNTHETIC} and
|
||||
* {@code ACC_MANDATED}.
|
||||
* @param modules the qualified names of the modules that can use deep reflection to the classes of the open package
|
||||
* or <tt>null</tt>.
|
||||
*/
|
||||
public void visitOpen(String packaze, int access, String... modules) {
|
||||
if (mv != null) {
|
||||
mv.visitOpen(packaze, access, modules);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visit an open package of the current module.
|
||||
*
|
||||
* @param packaze the qualified name of the opened package.
|
||||
* @param access the access flag of the opened package, valid values are among {@code ACC_SYNTHETIC} and
|
||||
* {@code ACC_MANDATED}.
|
||||
* @param modules the qualified names of the modules that can use deep reflection to the classes of the open package
|
||||
* or <tt>null</tt>.
|
||||
*/
|
||||
public void visitOpen(String packaze, int access, String... modules) {
|
||||
if (mv != null) {
|
||||
mv.visitOpen(packaze, access, modules);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit a service used by the current module. The name must be the internal name of an interface or a class.
|
||||
*
|
||||
* @param service the internal name of the service.
|
||||
*/
|
||||
public void visitUse(String service) {
|
||||
if (mv != null) {
|
||||
mv.visitUse(service);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visit a service used by the current module. The name must be the internal name of an interface or a class.
|
||||
*
|
||||
* @param service the internal name of the service.
|
||||
*/
|
||||
public void visitUse(String service) {
|
||||
if (mv != null) {
|
||||
mv.visitUse(service);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit an implementation of a service.
|
||||
*
|
||||
* @param service the internal name of the service
|
||||
* @param providers the internal names of the implementations of the service (there is at least one provider).
|
||||
*/
|
||||
public void visitProvide(String service, String... providers) {
|
||||
if (mv != null) {
|
||||
mv.visitProvide(service, providers);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visit an implementation of a service.
|
||||
*
|
||||
* @param service the internal name of the service
|
||||
* @param providers the internal names of the implementations of the service (there is at least one provider).
|
||||
*/
|
||||
public void visitProvide(String service, String... providers) {
|
||||
if (mv != null) {
|
||||
mv.visitProvide(service, providers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the end of the module. This method, which is the last one to be called, is used to inform the visitor that
|
||||
* everything have been visited.
|
||||
*/
|
||||
public void visitEnd() {
|
||||
if (mv != null) {
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visits the end of the module. This method, which is the last one to be called, is used to inform the visitor that
|
||||
* everything have been visited.
|
||||
*/
|
||||
public void visitEnd() {
|
||||
if (mv != null) {
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,228 +61,228 @@ package org.redkale.asm;
|
||||
|
||||
/** @author Remi Forax */
|
||||
final class ModuleWriter extends ModuleVisitor {
|
||||
/** The class writer to which this Module attribute must be added. */
|
||||
private final ClassWriter cw;
|
||||
/** The class writer to which this Module attribute must be added. */
|
||||
private final ClassWriter cw;
|
||||
|
||||
/** size in byte of the Module attribute. */
|
||||
int size;
|
||||
/** size in byte of the Module attribute. */
|
||||
int size;
|
||||
|
||||
/** Number of attributes associated with the current module (Version, ConcealPackages, etc) */
|
||||
int attributeCount;
|
||||
/** Number of attributes associated with the current module (Version, ConcealPackages, etc) */
|
||||
int attributeCount;
|
||||
|
||||
/** Size in bytes of the attributes associated with the current module */
|
||||
int attributesSize;
|
||||
/** Size in bytes of the attributes associated with the current module */
|
||||
int attributesSize;
|
||||
|
||||
/** module name index in the constant pool */
|
||||
private final int name;
|
||||
/** module name index in the constant pool */
|
||||
private final int name;
|
||||
|
||||
/** module access flags */
|
||||
private final int access;
|
||||
/** module access flags */
|
||||
private final int access;
|
||||
|
||||
/** module version index in the constant pool or 0 */
|
||||
private final int version;
|
||||
/** module version index in the constant pool or 0 */
|
||||
private final int version;
|
||||
|
||||
/** module main class index in the constant pool or 0 */
|
||||
private int mainClass;
|
||||
/** module main class index in the constant pool or 0 */
|
||||
private int mainClass;
|
||||
|
||||
/** number of packages */
|
||||
private int packageCount;
|
||||
/** number of packages */
|
||||
private int packageCount;
|
||||
|
||||
/**
|
||||
* The packages in bytecode form. This byte vector only contains the items themselves, the number of items is store
|
||||
* in packageCount
|
||||
*/
|
||||
private ByteVector packages;
|
||||
/**
|
||||
* The packages in bytecode form. This byte vector only contains the items themselves, the number of items is store
|
||||
* in packageCount
|
||||
*/
|
||||
private ByteVector packages;
|
||||
|
||||
/** number of requires items */
|
||||
private int requireCount;
|
||||
/** number of requires items */
|
||||
private int requireCount;
|
||||
|
||||
/**
|
||||
* The requires items in bytecode form. This byte vector only contains the items themselves, the number of items is
|
||||
* store in requireCount
|
||||
*/
|
||||
private ByteVector requires;
|
||||
/**
|
||||
* The requires items in bytecode form. This byte vector only contains the items themselves, the number of items is
|
||||
* store in requireCount
|
||||
*/
|
||||
private ByteVector requires;
|
||||
|
||||
/** number of exports items */
|
||||
private int exportCount;
|
||||
/** number of exports items */
|
||||
private int exportCount;
|
||||
|
||||
/**
|
||||
* The exports items in bytecode form. This byte vector only contains the items themselves, the number of items is
|
||||
* store in exportCount
|
||||
*/
|
||||
private ByteVector exports;
|
||||
/**
|
||||
* The exports items in bytecode form. This byte vector only contains the items themselves, the number of items is
|
||||
* store in exportCount
|
||||
*/
|
||||
private ByteVector exports;
|
||||
|
||||
/** number of opens items */
|
||||
private int openCount;
|
||||
/** number of opens items */
|
||||
private int openCount;
|
||||
|
||||
/**
|
||||
* The opens items in bytecode form. This byte vector only contains the items themselves, the number of items is
|
||||
* store in openCount
|
||||
*/
|
||||
private ByteVector opens;
|
||||
/**
|
||||
* The opens items in bytecode form. This byte vector only contains the items themselves, the number of items is
|
||||
* store in openCount
|
||||
*/
|
||||
private ByteVector opens;
|
||||
|
||||
/** number of uses items */
|
||||
private int useCount;
|
||||
/** number of uses items */
|
||||
private int useCount;
|
||||
|
||||
/**
|
||||
* The uses items in bytecode form. This byte vector only contains the items themselves, the number of items is
|
||||
* store in useCount
|
||||
*/
|
||||
private ByteVector uses;
|
||||
/**
|
||||
* The uses items in bytecode form. This byte vector only contains the items themselves, the number of items is
|
||||
* store in useCount
|
||||
*/
|
||||
private ByteVector uses;
|
||||
|
||||
/** number of provides items */
|
||||
private int provideCount;
|
||||
/** number of provides items */
|
||||
private int provideCount;
|
||||
|
||||
/**
|
||||
* The uses provides in bytecode form. This byte vector only contains the items themselves, the number of items is
|
||||
* store in provideCount
|
||||
*/
|
||||
private ByteVector provides;
|
||||
/**
|
||||
* The uses provides in bytecode form. This byte vector only contains the items themselves, the number of items is
|
||||
* store in provideCount
|
||||
*/
|
||||
private ByteVector provides;
|
||||
|
||||
ModuleWriter(final ClassWriter cw, final int name, final int access, final int version) {
|
||||
super(Opcodes.ASM6);
|
||||
this.cw = cw;
|
||||
this.size = 16; // name + access + version + 5 counts
|
||||
this.name = name;
|
||||
this.access = access;
|
||||
this.version = version;
|
||||
}
|
||||
ModuleWriter(final ClassWriter cw, final int name, final int access, final int version) {
|
||||
super(Opcodes.ASM6);
|
||||
this.cw = cw;
|
||||
this.size = 16; // name + access + version + 5 counts
|
||||
this.name = name;
|
||||
this.access = access;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMainClass(String mainClass) {
|
||||
if (this.mainClass == 0) { // protect against several calls to visitMainClass
|
||||
cw.newUTF8("ModuleMainClass");
|
||||
attributeCount++;
|
||||
attributesSize += 8;
|
||||
}
|
||||
this.mainClass = cw.newClass(mainClass);
|
||||
}
|
||||
@Override
|
||||
public void visitMainClass(String mainClass) {
|
||||
if (this.mainClass == 0) { // protect against several calls to visitMainClass
|
||||
cw.newUTF8("ModuleMainClass");
|
||||
attributeCount++;
|
||||
attributesSize += 8;
|
||||
}
|
||||
this.mainClass = cw.newClass(mainClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPackage(String packaze) {
|
||||
if (packages == null) {
|
||||
// protect against several calls to visitPackage
|
||||
cw.newUTF8("ModulePackages");
|
||||
packages = new ByteVector();
|
||||
attributeCount++;
|
||||
attributesSize += 8;
|
||||
}
|
||||
packages.putShort(cw.newPackage(packaze));
|
||||
packageCount++;
|
||||
attributesSize += 2;
|
||||
}
|
||||
@Override
|
||||
public void visitPackage(String packaze) {
|
||||
if (packages == null) {
|
||||
// protect against several calls to visitPackage
|
||||
cw.newUTF8("ModulePackages");
|
||||
packages = new ByteVector();
|
||||
attributeCount++;
|
||||
attributesSize += 8;
|
||||
}
|
||||
packages.putShort(cw.newPackage(packaze));
|
||||
packageCount++;
|
||||
attributesSize += 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitRequire(String module, int access, String version) {
|
||||
if (requires == null) {
|
||||
requires = new ByteVector();
|
||||
}
|
||||
requires.putShort(cw.newModule(module)).putShort(access).putShort(version == null ? 0 : cw.newUTF8(version));
|
||||
requireCount++;
|
||||
size += 6;
|
||||
}
|
||||
@Override
|
||||
public void visitRequire(String module, int access, String version) {
|
||||
if (requires == null) {
|
||||
requires = new ByteVector();
|
||||
}
|
||||
requires.putShort(cw.newModule(module)).putShort(access).putShort(version == null ? 0 : cw.newUTF8(version));
|
||||
requireCount++;
|
||||
size += 6;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitExport(String packaze, int access, String... modules) {
|
||||
if (exports == null) {
|
||||
exports = new ByteVector();
|
||||
}
|
||||
exports.putShort(cw.newPackage(packaze)).putShort(access);
|
||||
if (modules == null) {
|
||||
exports.putShort(0);
|
||||
size += 6;
|
||||
} else {
|
||||
exports.putShort(modules.length);
|
||||
for (String module : modules) {
|
||||
exports.putShort(cw.newModule(module));
|
||||
}
|
||||
size += 6 + 2 * modules.length;
|
||||
}
|
||||
exportCount++;
|
||||
}
|
||||
@Override
|
||||
public void visitExport(String packaze, int access, String... modules) {
|
||||
if (exports == null) {
|
||||
exports = new ByteVector();
|
||||
}
|
||||
exports.putShort(cw.newPackage(packaze)).putShort(access);
|
||||
if (modules == null) {
|
||||
exports.putShort(0);
|
||||
size += 6;
|
||||
} else {
|
||||
exports.putShort(modules.length);
|
||||
for (String module : modules) {
|
||||
exports.putShort(cw.newModule(module));
|
||||
}
|
||||
size += 6 + 2 * modules.length;
|
||||
}
|
||||
exportCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOpen(String packaze, int access, String... modules) {
|
||||
if (opens == null) {
|
||||
opens = new ByteVector();
|
||||
}
|
||||
opens.putShort(cw.newPackage(packaze)).putShort(access);
|
||||
if (modules == null) {
|
||||
opens.putShort(0);
|
||||
size += 6;
|
||||
} else {
|
||||
opens.putShort(modules.length);
|
||||
for (String module : modules) {
|
||||
opens.putShort(cw.newModule(module));
|
||||
}
|
||||
size += 6 + 2 * modules.length;
|
||||
}
|
||||
openCount++;
|
||||
}
|
||||
@Override
|
||||
public void visitOpen(String packaze, int access, String... modules) {
|
||||
if (opens == null) {
|
||||
opens = new ByteVector();
|
||||
}
|
||||
opens.putShort(cw.newPackage(packaze)).putShort(access);
|
||||
if (modules == null) {
|
||||
opens.putShort(0);
|
||||
size += 6;
|
||||
} else {
|
||||
opens.putShort(modules.length);
|
||||
for (String module : modules) {
|
||||
opens.putShort(cw.newModule(module));
|
||||
}
|
||||
size += 6 + 2 * modules.length;
|
||||
}
|
||||
openCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitUse(String service) {
|
||||
if (uses == null) {
|
||||
uses = new ByteVector();
|
||||
}
|
||||
uses.putShort(cw.newClass(service));
|
||||
useCount++;
|
||||
size += 2;
|
||||
}
|
||||
@Override
|
||||
public void visitUse(String service) {
|
||||
if (uses == null) {
|
||||
uses = new ByteVector();
|
||||
}
|
||||
uses.putShort(cw.newClass(service));
|
||||
useCount++;
|
||||
size += 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitProvide(String service, String... providers) {
|
||||
if (provides == null) {
|
||||
provides = new ByteVector();
|
||||
}
|
||||
provides.putShort(cw.newClass(service));
|
||||
provides.putShort(providers.length);
|
||||
for (String provider : providers) {
|
||||
provides.putShort(cw.newClass(provider));
|
||||
}
|
||||
provideCount++;
|
||||
size += 4 + 2 * providers.length;
|
||||
}
|
||||
@Override
|
||||
public void visitProvide(String service, String... providers) {
|
||||
if (provides == null) {
|
||||
provides = new ByteVector();
|
||||
}
|
||||
provides.putShort(cw.newClass(service));
|
||||
provides.putShort(providers.length);
|
||||
for (String provider : providers) {
|
||||
provides.putShort(cw.newClass(provider));
|
||||
}
|
||||
provideCount++;
|
||||
size += 4 + 2 * providers.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
// empty
|
||||
}
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
// empty
|
||||
}
|
||||
|
||||
void putAttributes(ByteVector out) {
|
||||
if (mainClass != 0) {
|
||||
out.putShort(cw.newUTF8("ModuleMainClass")).putInt(2).putShort(mainClass);
|
||||
}
|
||||
if (packages != null) {
|
||||
out.putShort(cw.newUTF8("ModulePackages"))
|
||||
.putInt(2 + 2 * packageCount)
|
||||
.putShort(packageCount)
|
||||
.putByteArray(packages.data, 0, packages.length);
|
||||
}
|
||||
}
|
||||
void putAttributes(ByteVector out) {
|
||||
if (mainClass != 0) {
|
||||
out.putShort(cw.newUTF8("ModuleMainClass")).putInt(2).putShort(mainClass);
|
||||
}
|
||||
if (packages != null) {
|
||||
out.putShort(cw.newUTF8("ModulePackages"))
|
||||
.putInt(2 + 2 * packageCount)
|
||||
.putShort(packageCount)
|
||||
.putByteArray(packages.data, 0, packages.length);
|
||||
}
|
||||
}
|
||||
|
||||
void put(ByteVector out) {
|
||||
out.putInt(size);
|
||||
out.putShort(name).putShort(access).putShort(version);
|
||||
out.putShort(requireCount);
|
||||
if (requires != null) {
|
||||
out.putByteArray(requires.data, 0, requires.length);
|
||||
}
|
||||
out.putShort(exportCount);
|
||||
if (exports != null) {
|
||||
out.putByteArray(exports.data, 0, exports.length);
|
||||
}
|
||||
out.putShort(openCount);
|
||||
if (opens != null) {
|
||||
out.putByteArray(opens.data, 0, opens.length);
|
||||
}
|
||||
out.putShort(useCount);
|
||||
if (uses != null) {
|
||||
out.putByteArray(uses.data, 0, uses.length);
|
||||
}
|
||||
out.putShort(provideCount);
|
||||
if (provides != null) {
|
||||
out.putByteArray(provides.data, 0, provides.length);
|
||||
}
|
||||
}
|
||||
void put(ByteVector out) {
|
||||
out.putInt(size);
|
||||
out.putShort(name).putShort(access).putShort(version);
|
||||
out.putShort(requireCount);
|
||||
if (requires != null) {
|
||||
out.putByteArray(requires.data, 0, requires.length);
|
||||
}
|
||||
out.putShort(exportCount);
|
||||
if (exports != null) {
|
||||
out.putByteArray(exports.data, 0, exports.length);
|
||||
}
|
||||
out.putShort(openCount);
|
||||
if (opens != null) {
|
||||
out.putByteArray(opens.data, 0, opens.length);
|
||||
}
|
||||
out.putShort(useCount);
|
||||
if (uses != null) {
|
||||
out.putByteArray(uses.data, 0, uses.length);
|
||||
}
|
||||
out.putShort(provideCount);
|
||||
if (provides != null) {
|
||||
out.putByteArray(provides.data, 0, provides.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,334 +69,334 @@ package org.redkale.asm;
|
||||
*/
|
||||
public interface Opcodes {
|
||||
|
||||
// ASM API versions
|
||||
int ASM4 = 4 << 16 | 0 << 8;
|
||||
int ASM5 = 5 << 16 | 0 << 8;
|
||||
int ASM6 = 6 << 16 | 0 << 8;
|
||||
// ASM API versions
|
||||
int ASM4 = 4 << 16 | 0 << 8;
|
||||
int ASM5 = 5 << 16 | 0 << 8;
|
||||
int ASM6 = 6 << 16 | 0 << 8;
|
||||
|
||||
// versions
|
||||
// versions
|
||||
|
||||
int V1_1 = 3 << 16 | 45;
|
||||
int V1_2 = 0 << 16 | 46;
|
||||
int V1_3 = 0 << 16 | 47;
|
||||
int V1_4 = 0 << 16 | 48;
|
||||
int V1_5 = 0 << 16 | 49;
|
||||
int V1_6 = 0 << 16 | 50;
|
||||
int V1_7 = 0 << 16 | 51;
|
||||
int V1_8 = 0 << 16 | 52;
|
||||
int V9 = 0 << 16 | 53;
|
||||
int V10 = 0 << 16 | 54;
|
||||
int V11 = 0 << 16 | 55;
|
||||
int V1_1 = 3 << 16 | 45;
|
||||
int V1_2 = 0 << 16 | 46;
|
||||
int V1_3 = 0 << 16 | 47;
|
||||
int V1_4 = 0 << 16 | 48;
|
||||
int V1_5 = 0 << 16 | 49;
|
||||
int V1_6 = 0 << 16 | 50;
|
||||
int V1_7 = 0 << 16 | 51;
|
||||
int V1_8 = 0 << 16 | 52;
|
||||
int V9 = 0 << 16 | 53;
|
||||
int V10 = 0 << 16 | 54;
|
||||
int V11 = 0 << 16 | 55;
|
||||
|
||||
// access flags
|
||||
// access flags
|
||||
|
||||
int ACC_PUBLIC = 0x0001; // class, field, method
|
||||
int ACC_PRIVATE = 0x0002; // class, field, method
|
||||
int ACC_PROTECTED = 0x0004; // class, field, method
|
||||
int ACC_STATIC = 0x0008; // field, method
|
||||
int ACC_FINAL = 0x0010; // class, field, method, parameter
|
||||
int ACC_SUPER = 0x0020; // class
|
||||
int ACC_SYNCHRONIZED = 0x0020; // method
|
||||
int ACC_OPEN = 0x0020; // module
|
||||
int ACC_TRANSITIVE = 0x0020; // module requires
|
||||
int ACC_VOLATILE = 0x0040; // field
|
||||
int ACC_BRIDGE = 0x0040; // method
|
||||
int ACC_STATIC_PHASE = 0x0040; // module requires
|
||||
int ACC_VARARGS = 0x0080; // method
|
||||
int ACC_TRANSIENT = 0x0080; // field
|
||||
int ACC_NATIVE = 0x0100; // method
|
||||
int ACC_INTERFACE = 0x0200; // class
|
||||
int ACC_ABSTRACT = 0x0400; // class, method
|
||||
int ACC_STRICT = 0x0800; // method
|
||||
int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
|
||||
int ACC_ANNOTATION = 0x2000; // class
|
||||
int ACC_ENUM = 0x4000; // class(?) field inner
|
||||
int ACC_MANDATED = 0x8000; // parameter, module, module *
|
||||
int ACC_MODULE = 0x8000; // class
|
||||
int ACC_PUBLIC = 0x0001; // class, field, method
|
||||
int ACC_PRIVATE = 0x0002; // class, field, method
|
||||
int ACC_PROTECTED = 0x0004; // class, field, method
|
||||
int ACC_STATIC = 0x0008; // field, method
|
||||
int ACC_FINAL = 0x0010; // class, field, method, parameter
|
||||
int ACC_SUPER = 0x0020; // class
|
||||
int ACC_SYNCHRONIZED = 0x0020; // method
|
||||
int ACC_OPEN = 0x0020; // module
|
||||
int ACC_TRANSITIVE = 0x0020; // module requires
|
||||
int ACC_VOLATILE = 0x0040; // field
|
||||
int ACC_BRIDGE = 0x0040; // method
|
||||
int ACC_STATIC_PHASE = 0x0040; // module requires
|
||||
int ACC_VARARGS = 0x0080; // method
|
||||
int ACC_TRANSIENT = 0x0080; // field
|
||||
int ACC_NATIVE = 0x0100; // method
|
||||
int ACC_INTERFACE = 0x0200; // class
|
||||
int ACC_ABSTRACT = 0x0400; // class, method
|
||||
int ACC_STRICT = 0x0800; // method
|
||||
int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
|
||||
int ACC_ANNOTATION = 0x2000; // class
|
||||
int ACC_ENUM = 0x4000; // class(?) field inner
|
||||
int ACC_MANDATED = 0x8000; // parameter, module, module *
|
||||
int ACC_MODULE = 0x8000; // class
|
||||
|
||||
// ASM specific pseudo access flags
|
||||
// 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_CHAR = 5;
|
||||
int T_FLOAT = 6;
|
||||
int T_DOUBLE = 7;
|
||||
int T_BYTE = 8;
|
||||
int T_SHORT = 9;
|
||||
int T_INT = 10;
|
||||
int T_LONG = 11;
|
||||
int T_BOOLEAN = 4;
|
||||
int T_CHAR = 5;
|
||||
int T_FLOAT = 6;
|
||||
int T_DOUBLE = 7;
|
||||
int T_BYTE = 8;
|
||||
int T_SHORT = 9;
|
||||
int T_INT = 10;
|
||||
int T_LONG = 11;
|
||||
|
||||
// tags for Handle
|
||||
// tags for Handle
|
||||
|
||||
int H_GETFIELD = 1;
|
||||
int H_GETSTATIC = 2;
|
||||
int H_PUTFIELD = 3;
|
||||
int H_PUTSTATIC = 4;
|
||||
int H_INVOKEVIRTUAL = 5;
|
||||
int H_INVOKESTATIC = 6;
|
||||
int H_INVOKESPECIAL = 7;
|
||||
int H_NEWINVOKESPECIAL = 8;
|
||||
int H_INVOKEINTERFACE = 9;
|
||||
int H_GETFIELD = 1;
|
||||
int H_GETSTATIC = 2;
|
||||
int H_PUTFIELD = 3;
|
||||
int H_PUTSTATIC = 4;
|
||||
int H_INVOKEVIRTUAL = 5;
|
||||
int H_INVOKESTATIC = 6;
|
||||
int H_INVOKESPECIAL = 7;
|
||||
int H_NEWINVOKESPECIAL = 8;
|
||||
int H_INVOKEINTERFACE = 9;
|
||||
|
||||
// stack map frame types
|
||||
// stack map frame types
|
||||
|
||||
/** Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */
|
||||
int F_NEW = -1;
|
||||
/** Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */
|
||||
int F_NEW = -1;
|
||||
|
||||
/** Represents a compressed frame with complete frame data. */
|
||||
int F_FULL = 0;
|
||||
/** Represents a compressed frame with complete frame data. */
|
||||
int F_FULL = 0;
|
||||
|
||||
/**
|
||||
* Represents a compressed frame where locals are the same as the locals in the previous frame, except that
|
||||
* additional 1-3 locals are defined, and with an empty stack.
|
||||
*/
|
||||
int F_APPEND = 1;
|
||||
/**
|
||||
* Represents a compressed frame where locals are the same as the locals in the previous frame, except that
|
||||
* additional 1-3 locals are defined, and with an empty stack.
|
||||
*/
|
||||
int F_APPEND = 1;
|
||||
|
||||
/**
|
||||
* Represents a compressed frame where locals are the same as the locals in the previous frame, except that the last
|
||||
* 1-3 locals are absent and with an empty stack.
|
||||
*/
|
||||
int F_CHOP = 2;
|
||||
/**
|
||||
* Represents a compressed frame where locals are the same as the locals in the previous frame, except that the last
|
||||
* 1-3 locals are absent and with an empty stack.
|
||||
*/
|
||||
int F_CHOP = 2;
|
||||
|
||||
/** Represents a compressed frame with exactly the same locals as the previous frame and with an empty stack. */
|
||||
int F_SAME = 3;
|
||||
/** Represents a compressed frame with exactly the same locals as the previous frame and with an empty stack. */
|
||||
int F_SAME = 3;
|
||||
|
||||
/**
|
||||
* Represents a compressed frame with exactly the same locals as the previous frame and with a single value on the
|
||||
* stack.
|
||||
*/
|
||||
int F_SAME1 = 4;
|
||||
/**
|
||||
* Represents a compressed frame with exactly the same locals as the previous frame and with a single value on the
|
||||
* stack.
|
||||
*/
|
||||
int F_SAME1 = 4;
|
||||
|
||||
// Do not try to change the following code to use auto-boxing,
|
||||
// these values are compared by reference and not by value
|
||||
// The constructor of Integer was deprecated in 9
|
||||
// but we are stuck with it by backward compatibility
|
||||
@SuppressWarnings("deprecation")
|
||||
Integer TOP = new Integer(0);
|
||||
// Do not try to change the following code to use auto-boxing,
|
||||
// these values are compared by reference and not by value
|
||||
// The constructor of Integer was deprecated in 9
|
||||
// but we are stuck with it by backward compatibility
|
||||
@SuppressWarnings("deprecation")
|
||||
Integer TOP = new Integer(0);
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
Integer INTEGER = new Integer(1);
|
||||
@SuppressWarnings("deprecation")
|
||||
Integer INTEGER = new Integer(1);
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
Integer FLOAT = new Integer(2);
|
||||
@SuppressWarnings("deprecation")
|
||||
Integer FLOAT = new Integer(2);
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
Integer DOUBLE = new Integer(3);
|
||||
@SuppressWarnings("deprecation")
|
||||
Integer DOUBLE = new Integer(3);
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
Integer LONG = new Integer(4);
|
||||
@SuppressWarnings("deprecation")
|
||||
Integer LONG = new Integer(4);
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
Integer NULL = new Integer(5);
|
||||
@SuppressWarnings("deprecation")
|
||||
Integer NULL = new Integer(5);
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
Integer UNINITIALIZED_THIS = new Integer(6);
|
||||
@SuppressWarnings("deprecation")
|
||||
Integer UNINITIALIZED_THIS = new Integer(6);
|
||||
|
||||
// opcodes // visit method (- = idem)
|
||||
// opcodes // visit method (- = idem)
|
||||
|
||||
int NOP = 0; // visitInsn
|
||||
int ACONST_NULL = 1; // -
|
||||
int ICONST_M1 = 2; // -
|
||||
int ICONST_0 = 3; // -
|
||||
int ICONST_1 = 4; // -
|
||||
int ICONST_2 = 5; // -
|
||||
int ICONST_3 = 6; // -
|
||||
int ICONST_4 = 7; // -
|
||||
int ICONST_5 = 8; // -
|
||||
int LCONST_0 = 9; // -
|
||||
int LCONST_1 = 10; // -
|
||||
int FCONST_0 = 11; // -
|
||||
int FCONST_1 = 12; // -
|
||||
int FCONST_2 = 13; // -
|
||||
int DCONST_0 = 14; // -
|
||||
int DCONST_1 = 15; // -
|
||||
int BIPUSH = 16; // visitIntInsn
|
||||
int SIPUSH = 17; // -
|
||||
int LDC = 18; // visitLdcInsn
|
||||
// int LDC_W = 19; // -
|
||||
// int LDC2_W = 20; // -
|
||||
int ILOAD = 21; // visitVarInsn
|
||||
int LLOAD = 22; // -
|
||||
int FLOAD = 23; // -
|
||||
int DLOAD = 24; // -
|
||||
int ALOAD = 25; // -
|
||||
// int ILOAD_0 = 26; // -
|
||||
// int ILOAD_1 = 27; // -
|
||||
// int ILOAD_2 = 28; // -
|
||||
// int ILOAD_3 = 29; // -
|
||||
// int LLOAD_0 = 30; // -
|
||||
// int LLOAD_1 = 31; // -
|
||||
// int LLOAD_2 = 32; // -
|
||||
// int LLOAD_3 = 33; // -
|
||||
// int FLOAD_0 = 34; // -
|
||||
// int FLOAD_1 = 35; // -
|
||||
// int FLOAD_2 = 36; // -
|
||||
// int FLOAD_3 = 37; // -
|
||||
// int DLOAD_0 = 38; // -
|
||||
// int DLOAD_1 = 39; // -
|
||||
// int DLOAD_2 = 40; // -
|
||||
// int DLOAD_3 = 41; // -
|
||||
// int ALOAD_0 = 42; // -
|
||||
// int ALOAD_1 = 43; // -
|
||||
// int ALOAD_2 = 44; // -
|
||||
// int ALOAD_3 = 45; // -
|
||||
int IALOAD = 46; // visitInsn
|
||||
int LALOAD = 47; // -
|
||||
int FALOAD = 48; // -
|
||||
int DALOAD = 49; // -
|
||||
int AALOAD = 50; // -
|
||||
int BALOAD = 51; // -
|
||||
int CALOAD = 52; // -
|
||||
int SALOAD = 53; // -
|
||||
int ISTORE = 54; // visitVarInsn
|
||||
int LSTORE = 55; // -
|
||||
int FSTORE = 56; // -
|
||||
int DSTORE = 57; // -
|
||||
int ASTORE = 58; // -
|
||||
// int ISTORE_0 = 59; // -
|
||||
// int ISTORE_1 = 60; // -
|
||||
// int ISTORE_2 = 61; // -
|
||||
// int ISTORE_3 = 62; // -
|
||||
// int LSTORE_0 = 63; // -
|
||||
// int LSTORE_1 = 64; // -
|
||||
// int LSTORE_2 = 65; // -
|
||||
// int LSTORE_3 = 66; // -
|
||||
// int FSTORE_0 = 67; // -
|
||||
// int FSTORE_1 = 68; // -
|
||||
// int FSTORE_2 = 69; // -
|
||||
// int FSTORE_3 = 70; // -
|
||||
// int DSTORE_0 = 71; // -
|
||||
// int DSTORE_1 = 72; // -
|
||||
// int DSTORE_2 = 73; // -
|
||||
// int DSTORE_3 = 74; // -
|
||||
// int ASTORE_0 = 75; // -
|
||||
// int ASTORE_1 = 76; // -
|
||||
// int ASTORE_2 = 77; // -
|
||||
// int ASTORE_3 = 78; // -
|
||||
int IASTORE = 79; // visitInsn
|
||||
int LASTORE = 80; // -
|
||||
int FASTORE = 81; // -
|
||||
int DASTORE = 82; // -
|
||||
int AASTORE = 83; // -
|
||||
int BASTORE = 84; // -
|
||||
int CASTORE = 85; // -
|
||||
int SASTORE = 86; // -
|
||||
int POP = 87; // -
|
||||
int POP2 = 88; // -
|
||||
int DUP = 89; // -
|
||||
int DUP_X1 = 90; // -
|
||||
int DUP_X2 = 91; // -
|
||||
int DUP2 = 92; // -
|
||||
int DUP2_X1 = 93; // -
|
||||
int DUP2_X2 = 94; // -
|
||||
int SWAP = 95; // -
|
||||
int IADD = 96; // -
|
||||
int LADD = 97; // -
|
||||
int FADD = 98; // -
|
||||
int DADD = 99; // -
|
||||
int ISUB = 100; // -
|
||||
int LSUB = 101; // -
|
||||
int FSUB = 102; // -
|
||||
int DSUB = 103; // -
|
||||
int IMUL = 104; // -
|
||||
int LMUL = 105; // -
|
||||
int FMUL = 106; // -
|
||||
int DMUL = 107; // -
|
||||
int IDIV = 108; // -
|
||||
int LDIV = 109; // -
|
||||
int FDIV = 110; // -
|
||||
int DDIV = 111; // -
|
||||
int IREM = 112; // -
|
||||
int LREM = 113; // -
|
||||
int FREM = 114; // -
|
||||
int DREM = 115; // -
|
||||
int INEG = 116; // -
|
||||
int LNEG = 117; // -
|
||||
int FNEG = 118; // -
|
||||
int DNEG = 119; // -
|
||||
int ISHL = 120; // -
|
||||
int LSHL = 121; // -
|
||||
int ISHR = 122; // -
|
||||
int LSHR = 123; // -
|
||||
int IUSHR = 124; // -
|
||||
int LUSHR = 125; // -
|
||||
int IAND = 126; // -
|
||||
int LAND = 127; // -
|
||||
int IOR = 128; // -
|
||||
int LOR = 129; // -
|
||||
int IXOR = 130; // -
|
||||
int LXOR = 131; // -
|
||||
int IINC = 132; // visitIincInsn
|
||||
int I2L = 133; // visitInsn
|
||||
int I2F = 134; // -
|
||||
int I2D = 135; // -
|
||||
int L2I = 136; // -
|
||||
int L2F = 137; // -
|
||||
int L2D = 138; // -
|
||||
int F2I = 139; // -
|
||||
int F2L = 140; // -
|
||||
int F2D = 141; // -
|
||||
int D2I = 142; // -
|
||||
int D2L = 143; // -
|
||||
int D2F = 144; // -
|
||||
int I2B = 145; // -
|
||||
int I2C = 146; // -
|
||||
int I2S = 147; // -
|
||||
int LCMP = 148; // -
|
||||
int FCMPL = 149; // -
|
||||
int FCMPG = 150; // -
|
||||
int DCMPL = 151; // -
|
||||
int DCMPG = 152; // -
|
||||
int IFEQ = 153; // visitJumpInsn
|
||||
int IFNE = 154; // -
|
||||
int IFLT = 155; // -
|
||||
int IFGE = 156; // -
|
||||
int IFGT = 157; // -
|
||||
int IFLE = 158; // -
|
||||
int IF_ICMPEQ = 159; // -
|
||||
int IF_ICMPNE = 160; // -
|
||||
int IF_ICMPLT = 161; // -
|
||||
int IF_ICMPGE = 162; // -
|
||||
int IF_ICMPGT = 163; // -
|
||||
int IF_ICMPLE = 164; // -
|
||||
int IF_ACMPEQ = 165; // -
|
||||
int IF_ACMPNE = 166; // -
|
||||
int GOTO = 167; // -
|
||||
int JSR = 168; // -
|
||||
int RET = 169; // visitVarInsn
|
||||
int TABLESWITCH = 170; // visiTableSwitchInsn
|
||||
int LOOKUPSWITCH = 171; // visitLookupSwitch
|
||||
int IRETURN = 172; // visitInsn
|
||||
int LRETURN = 173; // -
|
||||
int FRETURN = 174; // -
|
||||
int DRETURN = 175; // -
|
||||
int ARETURN = 176; // -
|
||||
int RETURN = 177; // -
|
||||
int GETSTATIC = 178; // visitFieldInsn
|
||||
int PUTSTATIC = 179; // -
|
||||
int GETFIELD = 180; // -
|
||||
int PUTFIELD = 181; // -
|
||||
int INVOKEVIRTUAL = 182; // visitMethodInsn
|
||||
int INVOKESPECIAL = 183; // -
|
||||
int INVOKESTATIC = 184; // -
|
||||
int INVOKEINTERFACE = 185; // -
|
||||
int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
|
||||
int NEW = 187; // visitTypeInsn
|
||||
int NEWARRAY = 188; // visitIntInsn
|
||||
int ANEWARRAY = 189; // visitTypeInsn
|
||||
int ARRAYLENGTH = 190; // visitInsn
|
||||
int ATHROW = 191; // -
|
||||
int CHECKCAST = 192; // visitTypeInsn
|
||||
int INSTANCEOF = 193; // -
|
||||
int MONITORENTER = 194; // visitInsn
|
||||
int MONITOREXIT = 195; // -
|
||||
// int WIDE = 196; // NOT VISITED
|
||||
int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
|
||||
int IFNULL = 198; // visitJumpInsn
|
||||
int IFNONNULL = 199; // -
|
||||
// int GOTO_W = 200; // -
|
||||
// int JSR_W = 201; // -
|
||||
int NOP = 0; // visitInsn
|
||||
int ACONST_NULL = 1; // -
|
||||
int ICONST_M1 = 2; // -
|
||||
int ICONST_0 = 3; // -
|
||||
int ICONST_1 = 4; // -
|
||||
int ICONST_2 = 5; // -
|
||||
int ICONST_3 = 6; // -
|
||||
int ICONST_4 = 7; // -
|
||||
int ICONST_5 = 8; // -
|
||||
int LCONST_0 = 9; // -
|
||||
int LCONST_1 = 10; // -
|
||||
int FCONST_0 = 11; // -
|
||||
int FCONST_1 = 12; // -
|
||||
int FCONST_2 = 13; // -
|
||||
int DCONST_0 = 14; // -
|
||||
int DCONST_1 = 15; // -
|
||||
int BIPUSH = 16; // visitIntInsn
|
||||
int SIPUSH = 17; // -
|
||||
int LDC = 18; // visitLdcInsn
|
||||
// int LDC_W = 19; // -
|
||||
// int LDC2_W = 20; // -
|
||||
int ILOAD = 21; // visitVarInsn
|
||||
int LLOAD = 22; // -
|
||||
int FLOAD = 23; // -
|
||||
int DLOAD = 24; // -
|
||||
int ALOAD = 25; // -
|
||||
// int ILOAD_0 = 26; // -
|
||||
// int ILOAD_1 = 27; // -
|
||||
// int ILOAD_2 = 28; // -
|
||||
// int ILOAD_3 = 29; // -
|
||||
// int LLOAD_0 = 30; // -
|
||||
// int LLOAD_1 = 31; // -
|
||||
// int LLOAD_2 = 32; // -
|
||||
// int LLOAD_3 = 33; // -
|
||||
// int FLOAD_0 = 34; // -
|
||||
// int FLOAD_1 = 35; // -
|
||||
// int FLOAD_2 = 36; // -
|
||||
// int FLOAD_3 = 37; // -
|
||||
// int DLOAD_0 = 38; // -
|
||||
// int DLOAD_1 = 39; // -
|
||||
// int DLOAD_2 = 40; // -
|
||||
// int DLOAD_3 = 41; // -
|
||||
// int ALOAD_0 = 42; // -
|
||||
// int ALOAD_1 = 43; // -
|
||||
// int ALOAD_2 = 44; // -
|
||||
// int ALOAD_3 = 45; // -
|
||||
int IALOAD = 46; // visitInsn
|
||||
int LALOAD = 47; // -
|
||||
int FALOAD = 48; // -
|
||||
int DALOAD = 49; // -
|
||||
int AALOAD = 50; // -
|
||||
int BALOAD = 51; // -
|
||||
int CALOAD = 52; // -
|
||||
int SALOAD = 53; // -
|
||||
int ISTORE = 54; // visitVarInsn
|
||||
int LSTORE = 55; // -
|
||||
int FSTORE = 56; // -
|
||||
int DSTORE = 57; // -
|
||||
int ASTORE = 58; // -
|
||||
// int ISTORE_0 = 59; // -
|
||||
// int ISTORE_1 = 60; // -
|
||||
// int ISTORE_2 = 61; // -
|
||||
// int ISTORE_3 = 62; // -
|
||||
// int LSTORE_0 = 63; // -
|
||||
// int LSTORE_1 = 64; // -
|
||||
// int LSTORE_2 = 65; // -
|
||||
// int LSTORE_3 = 66; // -
|
||||
// int FSTORE_0 = 67; // -
|
||||
// int FSTORE_1 = 68; // -
|
||||
// int FSTORE_2 = 69; // -
|
||||
// int FSTORE_3 = 70; // -
|
||||
// int DSTORE_0 = 71; // -
|
||||
// int DSTORE_1 = 72; // -
|
||||
// int DSTORE_2 = 73; // -
|
||||
// int DSTORE_3 = 74; // -
|
||||
// int ASTORE_0 = 75; // -
|
||||
// int ASTORE_1 = 76; // -
|
||||
// int ASTORE_2 = 77; // -
|
||||
// int ASTORE_3 = 78; // -
|
||||
int IASTORE = 79; // visitInsn
|
||||
int LASTORE = 80; // -
|
||||
int FASTORE = 81; // -
|
||||
int DASTORE = 82; // -
|
||||
int AASTORE = 83; // -
|
||||
int BASTORE = 84; // -
|
||||
int CASTORE = 85; // -
|
||||
int SASTORE = 86; // -
|
||||
int POP = 87; // -
|
||||
int POP2 = 88; // -
|
||||
int DUP = 89; // -
|
||||
int DUP_X1 = 90; // -
|
||||
int DUP_X2 = 91; // -
|
||||
int DUP2 = 92; // -
|
||||
int DUP2_X1 = 93; // -
|
||||
int DUP2_X2 = 94; // -
|
||||
int SWAP = 95; // -
|
||||
int IADD = 96; // -
|
||||
int LADD = 97; // -
|
||||
int FADD = 98; // -
|
||||
int DADD = 99; // -
|
||||
int ISUB = 100; // -
|
||||
int LSUB = 101; // -
|
||||
int FSUB = 102; // -
|
||||
int DSUB = 103; // -
|
||||
int IMUL = 104; // -
|
||||
int LMUL = 105; // -
|
||||
int FMUL = 106; // -
|
||||
int DMUL = 107; // -
|
||||
int IDIV = 108; // -
|
||||
int LDIV = 109; // -
|
||||
int FDIV = 110; // -
|
||||
int DDIV = 111; // -
|
||||
int IREM = 112; // -
|
||||
int LREM = 113; // -
|
||||
int FREM = 114; // -
|
||||
int DREM = 115; // -
|
||||
int INEG = 116; // -
|
||||
int LNEG = 117; // -
|
||||
int FNEG = 118; // -
|
||||
int DNEG = 119; // -
|
||||
int ISHL = 120; // -
|
||||
int LSHL = 121; // -
|
||||
int ISHR = 122; // -
|
||||
int LSHR = 123; // -
|
||||
int IUSHR = 124; // -
|
||||
int LUSHR = 125; // -
|
||||
int IAND = 126; // -
|
||||
int LAND = 127; // -
|
||||
int IOR = 128; // -
|
||||
int LOR = 129; // -
|
||||
int IXOR = 130; // -
|
||||
int LXOR = 131; // -
|
||||
int IINC = 132; // visitIincInsn
|
||||
int I2L = 133; // visitInsn
|
||||
int I2F = 134; // -
|
||||
int I2D = 135; // -
|
||||
int L2I = 136; // -
|
||||
int L2F = 137; // -
|
||||
int L2D = 138; // -
|
||||
int F2I = 139; // -
|
||||
int F2L = 140; // -
|
||||
int F2D = 141; // -
|
||||
int D2I = 142; // -
|
||||
int D2L = 143; // -
|
||||
int D2F = 144; // -
|
||||
int I2B = 145; // -
|
||||
int I2C = 146; // -
|
||||
int I2S = 147; // -
|
||||
int LCMP = 148; // -
|
||||
int FCMPL = 149; // -
|
||||
int FCMPG = 150; // -
|
||||
int DCMPL = 151; // -
|
||||
int DCMPG = 152; // -
|
||||
int IFEQ = 153; // visitJumpInsn
|
||||
int IFNE = 154; // -
|
||||
int IFLT = 155; // -
|
||||
int IFGE = 156; // -
|
||||
int IFGT = 157; // -
|
||||
int IFLE = 158; // -
|
||||
int IF_ICMPEQ = 159; // -
|
||||
int IF_ICMPNE = 160; // -
|
||||
int IF_ICMPLT = 161; // -
|
||||
int IF_ICMPGE = 162; // -
|
||||
int IF_ICMPGT = 163; // -
|
||||
int IF_ICMPLE = 164; // -
|
||||
int IF_ACMPEQ = 165; // -
|
||||
int IF_ACMPNE = 166; // -
|
||||
int GOTO = 167; // -
|
||||
int JSR = 168; // -
|
||||
int RET = 169; // visitVarInsn
|
||||
int TABLESWITCH = 170; // visiTableSwitchInsn
|
||||
int LOOKUPSWITCH = 171; // visitLookupSwitch
|
||||
int IRETURN = 172; // visitInsn
|
||||
int LRETURN = 173; // -
|
||||
int FRETURN = 174; // -
|
||||
int DRETURN = 175; // -
|
||||
int ARETURN = 176; // -
|
||||
int RETURN = 177; // -
|
||||
int GETSTATIC = 178; // visitFieldInsn
|
||||
int PUTSTATIC = 179; // -
|
||||
int GETFIELD = 180; // -
|
||||
int PUTFIELD = 181; // -
|
||||
int INVOKEVIRTUAL = 182; // visitMethodInsn
|
||||
int INVOKESPECIAL = 183; // -
|
||||
int INVOKESTATIC = 184; // -
|
||||
int INVOKEINTERFACE = 185; // -
|
||||
int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
|
||||
int NEW = 187; // visitTypeInsn
|
||||
int NEWARRAY = 188; // visitIntInsn
|
||||
int ANEWARRAY = 189; // visitTypeInsn
|
||||
int ARRAYLENGTH = 190; // visitInsn
|
||||
int ATHROW = 191; // -
|
||||
int CHECKCAST = 192; // visitTypeInsn
|
||||
int INSTANCEOF = 193; // -
|
||||
int MONITORENTER = 194; // visitInsn
|
||||
int MONITOREXIT = 195; // -
|
||||
// int WIDE = 196; // NOT VISITED
|
||||
int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
|
||||
int IFNULL = 198; // visitJumpInsn
|
||||
int IFNONNULL = 199; // -
|
||||
// int GOTO_W = 200; // -
|
||||
// int JSR_W = 201; // -
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -66,130 +66,130 @@ package org.redkale.asm;
|
||||
*/
|
||||
public class TypePath {
|
||||
|
||||
/** 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;
|
||||
/** 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;
|
||||
|
||||
/** 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;
|
||||
/** 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;
|
||||
|
||||
/** A type path step that steps into the bound of a wildcard type. See {@link #getStep getStep}. */
|
||||
public static final int WILDCARD_BOUND = 2;
|
||||
/** A type path step that steps into the bound of a wildcard type. See {@link #getStep getStep}. */
|
||||
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}. */
|
||||
public static final int TYPE_ARGUMENT = 3;
|
||||
/** 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;
|
||||
|
||||
/** The byte array where the path is stored, in Java class file format. */
|
||||
byte[] b;
|
||||
/** The byte array where the path is stored, in Java class file format. */
|
||||
byte[] b;
|
||||
|
||||
/** The offset of the first byte of the type path in 'b'. */
|
||||
int offset;
|
||||
/** The offset of the first byte of the type path in 'b'. */
|
||||
int offset;
|
||||
|
||||
/**
|
||||
* Creates a new type path.
|
||||
*
|
||||
* @param b the byte array containing the type path in Java class file format.
|
||||
* @param offset the offset of the first byte of the type path in 'b'.
|
||||
*/
|
||||
TypePath(byte[] b, int offset) {
|
||||
this.b = b;
|
||||
this.offset = offset;
|
||||
}
|
||||
/**
|
||||
* Creates a new type path.
|
||||
*
|
||||
* @param b the byte array containing the type path in Java class file format.
|
||||
* @param offset the offset of the first byte of the type path in 'b'.
|
||||
*/
|
||||
TypePath(byte[] b, int offset) {
|
||||
this.b = b;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of this path.
|
||||
*
|
||||
* @return the length of this path.
|
||||
*/
|
||||
public int getLength() {
|
||||
return b[offset];
|
||||
}
|
||||
/**
|
||||
* Returns the length of this path.
|
||||
*
|
||||
* @return the length of this path.
|
||||
*/
|
||||
public int getLength() {
|
||||
return b[offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the given step of this path.
|
||||
*
|
||||
* @param index an index between 0 and {@link #getLength()}, exclusive.
|
||||
* @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE INNER_TYPE}, {@link #WILDCARD_BOUND
|
||||
* WILDCARD_BOUND}, or {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
|
||||
*/
|
||||
public int getStep(int index) {
|
||||
return b[offset + 2 * index + 1];
|
||||
}
|
||||
/**
|
||||
* Returns the value of the given step of this path.
|
||||
*
|
||||
* @param index an index between 0 and {@link #getLength()}, exclusive.
|
||||
* @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE INNER_TYPE}, {@link #WILDCARD_BOUND
|
||||
* WILDCARD_BOUND}, or {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
|
||||
*/
|
||||
public int getStep(int index) {
|
||||
return b[offset + 2 * index + 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the type argument that the given step is stepping into. This method should only be used for
|
||||
* steps whose value is {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
|
||||
*
|
||||
* @param index an index between 0 and {@link #getLength()}, exclusive.
|
||||
* @return the index of the type argument that the given step is stepping into.
|
||||
*/
|
||||
public int getStepArgument(int index) {
|
||||
return b[offset + 2 * index + 2];
|
||||
}
|
||||
/**
|
||||
* Returns the index of the type argument that the given step is stepping into. This method should only be used for
|
||||
* steps whose value is {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
|
||||
*
|
||||
* @param index an index between 0 and {@link #getLength()}, exclusive.
|
||||
* @return the index of the type argument that the given step is stepping into.
|
||||
*/
|
||||
public int getStepArgument(int index) {
|
||||
return b[offset + 2 * index + 2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath object.
|
||||
*
|
||||
* @param typePath a type path in string form, in the format used by {@link #toString()}. May be null or empty.
|
||||
* @return the corresponding TypePath object, or null if the path is empty.
|
||||
*/
|
||||
public static TypePath fromString(final String typePath) {
|
||||
if (typePath == null || typePath.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
int n = typePath.length();
|
||||
ByteVector out = new ByteVector(n);
|
||||
out.putByte(0);
|
||||
for (int i = 0; i < n; ) {
|
||||
char c = typePath.charAt(i++);
|
||||
if (c == '[') {
|
||||
out.put11(ARRAY_ELEMENT, 0);
|
||||
} else if (c == '.') {
|
||||
out.put11(INNER_TYPE, 0);
|
||||
} else if (c == '*') {
|
||||
out.put11(WILDCARD_BOUND, 0);
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
int typeArg = c - '0';
|
||||
while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') {
|
||||
typeArg = typeArg * 10 + c - '0';
|
||||
i += 1;
|
||||
}
|
||||
if (i < n && typePath.charAt(i) == ';') {
|
||||
i += 1;
|
||||
}
|
||||
out.put11(TYPE_ARGUMENT, typeArg);
|
||||
}
|
||||
}
|
||||
out.data[0] = (byte) (out.length / 2);
|
||||
return new TypePath(out.data, 0);
|
||||
}
|
||||
/**
|
||||
* Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath object.
|
||||
*
|
||||
* @param typePath a type path in string form, in the format used by {@link #toString()}. May be null or empty.
|
||||
* @return the corresponding TypePath object, or null if the path is empty.
|
||||
*/
|
||||
public static TypePath fromString(final String typePath) {
|
||||
if (typePath == null || typePath.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
int n = typePath.length();
|
||||
ByteVector out = new ByteVector(n);
|
||||
out.putByte(0);
|
||||
for (int i = 0; i < n; ) {
|
||||
char c = typePath.charAt(i++);
|
||||
if (c == '[') {
|
||||
out.put11(ARRAY_ELEMENT, 0);
|
||||
} else if (c == '.') {
|
||||
out.put11(INNER_TYPE, 0);
|
||||
} else if (c == '*') {
|
||||
out.put11(WILDCARD_BOUND, 0);
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
int typeArg = c - '0';
|
||||
while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') {
|
||||
typeArg = typeArg * 10 + c - '0';
|
||||
i += 1;
|
||||
}
|
||||
if (i < n && typePath.charAt(i) == ';') {
|
||||
i += 1;
|
||||
}
|
||||
out.put11(TYPE_ARGUMENT, typeArg);
|
||||
}
|
||||
}
|
||||
out.data[0] = (byte) (out.length / 2);
|
||||
return new TypePath(out.data, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this type path. {@link #ARRAY_ELEMENT ARRAY_ELEMENT} steps are represented
|
||||
* with '[', {@link #INNER_TYPE INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps with '*'
|
||||
* and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
int length = getLength();
|
||||
StringBuilder result = new StringBuilder(length * 2);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
switch (getStep(i)) {
|
||||
case ARRAY_ELEMENT:
|
||||
result.append('[');
|
||||
break;
|
||||
case INNER_TYPE:
|
||||
result.append('.');
|
||||
break;
|
||||
case WILDCARD_BOUND:
|
||||
result.append('*');
|
||||
break;
|
||||
case TYPE_ARGUMENT:
|
||||
result.append(getStepArgument(i)).append(';');
|
||||
break;
|
||||
default:
|
||||
result.append('_');
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
/**
|
||||
* Returns a string representation of this type path. {@link #ARRAY_ELEMENT ARRAY_ELEMENT} steps are represented
|
||||
* with '[', {@link #INNER_TYPE INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps with '*'
|
||||
* and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
int length = getLength();
|
||||
StringBuilder result = new StringBuilder(length * 2);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
switch (getStep(i)) {
|
||||
case ARRAY_ELEMENT:
|
||||
result.append('[');
|
||||
break;
|
||||
case INNER_TYPE:
|
||||
result.append('.');
|
||||
break;
|
||||
case WILDCARD_BOUND:
|
||||
result.append('*');
|
||||
break;
|
||||
case TYPE_ARGUMENT:
|
||||
result.append(getStepArgument(i)).append(';');
|
||||
break;
|
||||
default:
|
||||
result.append('_');
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,335 +68,335 @@ package org.redkale.asm;
|
||||
*/
|
||||
public class TypeReference {
|
||||
|
||||
/** 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;
|
||||
/** 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;
|
||||
|
||||
/** 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;
|
||||
/** 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;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the super class of a class or one of the interfaces it implements. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public static final int CLASS_EXTENDS = 0x10;
|
||||
/**
|
||||
* The sort of type references that target the super class of a class or one of the interfaces it implements. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public 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
|
||||
* getSort}.
|
||||
*/
|
||||
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 class. See {@link #getSort
|
||||
* getSort}.
|
||||
*/
|
||||
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
|
||||
* getSort}.
|
||||
*/
|
||||
public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12;
|
||||
/**
|
||||
* The sort of type references that target a bound of a type parameter of a generic method. See {@link #getSort
|
||||
* getSort}.
|
||||
*/
|
||||
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}. */
|
||||
public static final int FIELD = 0x13;
|
||||
/** The sort of type references that target the type of a field. See {@link #getSort getSort}. */
|
||||
public static final int FIELD = 0x13;
|
||||
|
||||
/** The sort of type references that target the return type of a method. See {@link #getSort getSort}. */
|
||||
public static final int METHOD_RETURN = 0x14;
|
||||
/** The sort of type references that target the return type of a method. See {@link #getSort getSort}. */
|
||||
public static final int METHOD_RETURN = 0x14;
|
||||
|
||||
/** The sort of type references that target the receiver type of a method. See {@link #getSort getSort}. */
|
||||
public static final int METHOD_RECEIVER = 0x15;
|
||||
/** The sort of type references that target the receiver type of a method. See {@link #getSort getSort}. */
|
||||
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}.
|
||||
*/
|
||||
public static final int METHOD_FORMAL_PARAMETER = 0x16;
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the type of an exception declared in the throws clause of a method. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public static final int THROWS = 0x17;
|
||||
/**
|
||||
* The sort of type references that target the type of an exception declared in the throws clause of a method. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public 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}.
|
||||
*/
|
||||
public static final int LOCAL_VARIABLE = 0x40;
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the type of a resource variable in a method. See {@link #getSort
|
||||
* getSort}.
|
||||
*/
|
||||
public static final int RESOURCE_VARIABLE = 0x41;
|
||||
/**
|
||||
* The sort of type references that target the type of a resource variable in a method. See {@link #getSort
|
||||
* getSort}.
|
||||
*/
|
||||
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
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public static final int EXCEPTION_PARAMETER = 0x42;
|
||||
/**
|
||||
* The sort of type references that target the type of the exception of a 'catch' clause in a method. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public static final int EXCEPTION_PARAMETER = 0x42;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the type declared in an 'instanceof' instruction. See {@link #getSort
|
||||
* getSort}.
|
||||
*/
|
||||
public static final int INSTANCEOF = 0x43;
|
||||
/**
|
||||
* The sort of type references that target the type declared in an 'instanceof' instruction. See {@link #getSort
|
||||
* getSort}.
|
||||
*/
|
||||
public static final int INSTANCEOF = 0x43;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the type of the object created by a 'new' instruction. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public static final int NEW = 0x44;
|
||||
/**
|
||||
* The sort of type references that target the type of the object created by a 'new' instruction. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public static final int NEW = 0x44;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the receiver type of a constructor reference. See {@link #getSort
|
||||
* getSort}.
|
||||
*/
|
||||
public static final int CONSTRUCTOR_REFERENCE = 0x45;
|
||||
/**
|
||||
* The sort of type references that target the receiver type of a constructor reference. See {@link #getSort
|
||||
* getSort}.
|
||||
*/
|
||||
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}.
|
||||
*/
|
||||
public static final int METHOD_REFERENCE = 0x46;
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the type declared in an explicit or implicit cast instruction. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public static final int CAST = 0x47;
|
||||
/**
|
||||
* The sort of type references that target the type declared in an explicit or implicit cast instruction. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
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
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
|
||||
/**
|
||||
* The sort of type references that target a type parameter of a generic constructor in a constructor call. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
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
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
|
||||
/**
|
||||
* The sort of type references that target a type parameter of a generic method in a method call. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
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
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
|
||||
/**
|
||||
* The sort of type references that target a type parameter of a generic constructor in a constructor reference. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
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
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
|
||||
/**
|
||||
* The sort of type references that target a type parameter of a generic method in a method reference. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
|
||||
|
||||
/** The type reference value in Java class file format. */
|
||||
private int value;
|
||||
/** The type reference value in Java class file format. */
|
||||
private int value;
|
||||
|
||||
/**
|
||||
* Creates a new TypeReference.
|
||||
*
|
||||
* @param typeRef the int encoded value of the type reference, as received in a visit method related to type
|
||||
* annotations, like visitTypeAnnotation.
|
||||
*/
|
||||
public TypeReference(int typeRef) {
|
||||
this.value = typeRef;
|
||||
}
|
||||
/**
|
||||
* Creates a new TypeReference.
|
||||
*
|
||||
* @param typeRef the int encoded value of the type reference, as received in a visit method related to type
|
||||
* annotations, like visitTypeAnnotation.
|
||||
*/
|
||||
public TypeReference(int typeRef) {
|
||||
this.value = typeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a type reference of the given sort.
|
||||
*
|
||||
* @param sort {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, {@link #METHOD_RECEIVER METHOD_RECEIVER},
|
||||
* {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, {@link #INSTANCEOF
|
||||
* INSTANCEOF}, {@link #NEW NEW}, {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
|
||||
* {@link #METHOD_REFERENCE METHOD_REFERENCE}.
|
||||
* @return a type reference of the given sort.
|
||||
*/
|
||||
public static TypeReference newTypeReference(int sort) {
|
||||
return new TypeReference(sort << 24);
|
||||
}
|
||||
/**
|
||||
* Returns a type reference of the given sort.
|
||||
*
|
||||
* @param sort {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, {@link #METHOD_RECEIVER METHOD_RECEIVER},
|
||||
* {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, {@link #INSTANCEOF
|
||||
* INSTANCEOF}, {@link #NEW NEW}, {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
|
||||
* {@link #METHOD_REFERENCE METHOD_REFERENCE}.
|
||||
* @return a type reference of the given sort.
|
||||
*/
|
||||
public static TypeReference newTypeReference(int sort) {
|
||||
return new TypeReference(sort << 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to a type parameter of a generic class or method.
|
||||
*
|
||||
* @param sort {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER
|
||||
* METHOD_TYPE_PARAMETER}.
|
||||
* @param paramIndex the type parameter index.
|
||||
* @return a reference to the given generic class or method type parameter.
|
||||
*/
|
||||
public static TypeReference newTypeParameterReference(int sort, int paramIndex) {
|
||||
return new TypeReference((sort << 24) | (paramIndex << 16));
|
||||
}
|
||||
/**
|
||||
* Returns a reference to a type parameter of a generic class or method.
|
||||
*
|
||||
* @param sort {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER
|
||||
* METHOD_TYPE_PARAMETER}.
|
||||
* @param paramIndex the type parameter index.
|
||||
* @return a reference to the given generic class or method type parameter.
|
||||
*/
|
||||
public static TypeReference newTypeParameterReference(int sort, int paramIndex) {
|
||||
return new TypeReference((sort << 24) | (paramIndex << 16));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to a type parameter bound of a generic class or method.
|
||||
*
|
||||
* @param sort {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER
|
||||
* METHOD_TYPE_PARAMETER}.
|
||||
* @param paramIndex the type parameter index.
|
||||
* @param boundIndex the type bound index within the above type parameters.
|
||||
* @return a reference to the given generic class or method type parameter bound.
|
||||
*/
|
||||
public static TypeReference newTypeParameterBoundReference(int sort, int paramIndex, int boundIndex) {
|
||||
return new TypeReference((sort << 24) | (paramIndex << 16) | (boundIndex << 8));
|
||||
}
|
||||
/**
|
||||
* Returns a reference to a type parameter bound of a generic class or method.
|
||||
*
|
||||
* @param sort {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER
|
||||
* METHOD_TYPE_PARAMETER}.
|
||||
* @param paramIndex the type parameter index.
|
||||
* @param boundIndex the type bound index within the above type parameters.
|
||||
* @return a reference to the given generic class or method type parameter bound.
|
||||
*/
|
||||
public static TypeReference newTypeParameterBoundReference(int sort, int paramIndex, int boundIndex) {
|
||||
return new TypeReference((sort << 24) | (paramIndex << 16) | (boundIndex << 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the super class or to an interface of the 'implements' clause of a class.
|
||||
*
|
||||
* @param itfIndex the index of an interface in the 'implements' clause of a class, or -1 to reference the super
|
||||
* class of the class.
|
||||
* @return a reference to the given super type of a class.
|
||||
*/
|
||||
public static TypeReference newSuperTypeReference(int itfIndex) {
|
||||
itfIndex &= 0xFFFF;
|
||||
return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
|
||||
}
|
||||
/**
|
||||
* Returns a reference to the super class or to an interface of the 'implements' clause of a class.
|
||||
*
|
||||
* @param itfIndex the index of an interface in the 'implements' clause of a class, or -1 to reference the super
|
||||
* class of the class.
|
||||
* @return a reference to the given super type of a class.
|
||||
*/
|
||||
public static TypeReference newSuperTypeReference(int itfIndex) {
|
||||
itfIndex &= 0xFFFF;
|
||||
return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the type of a formal parameter of a method.
|
||||
*
|
||||
* @param paramIndex the formal parameter index.
|
||||
* @return a reference to the type of the given method formal parameter.
|
||||
*/
|
||||
public static TypeReference newFormalParameterReference(int paramIndex) {
|
||||
return new TypeReference((METHOD_FORMAL_PARAMETER << 24) | (paramIndex << 16));
|
||||
}
|
||||
/**
|
||||
* Returns a reference to the type of a formal parameter of a method.
|
||||
*
|
||||
* @param paramIndex the formal parameter index.
|
||||
* @return a reference to the type of the given method formal parameter.
|
||||
*/
|
||||
public static TypeReference newFormalParameterReference(int paramIndex) {
|
||||
return new TypeReference((METHOD_FORMAL_PARAMETER << 24) | (paramIndex << 16));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the type of an exception, in a 'throws' clause of a method.
|
||||
*
|
||||
* @param exceptionIndex the index of an exception in a 'throws' clause of a method.
|
||||
* @return a reference to the type of the given exception.
|
||||
*/
|
||||
public static TypeReference newExceptionReference(int exceptionIndex) {
|
||||
return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
|
||||
}
|
||||
/**
|
||||
* Returns a reference to the type of an exception, in a 'throws' clause of a method.
|
||||
*
|
||||
* @param exceptionIndex the index of an exception in a 'throws' clause of a method.
|
||||
* @return a reference to the type of the given exception.
|
||||
*/
|
||||
public static TypeReference newExceptionReference(int exceptionIndex) {
|
||||
return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the type of the exception declared in a 'catch' clause of a method.
|
||||
*
|
||||
* @param tryCatchBlockIndex the index of a try catch block (using the order in which they are visited with
|
||||
* visitTryCatchBlock).
|
||||
* @return a reference to the type of the given exception.
|
||||
*/
|
||||
public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
|
||||
return new TypeReference((EXCEPTION_PARAMETER << 24) | (tryCatchBlockIndex << 8));
|
||||
}
|
||||
/**
|
||||
* Returns a reference to the type of the exception declared in a 'catch' clause of a method.
|
||||
*
|
||||
* @param tryCatchBlockIndex the index of a try catch block (using the order in which they are visited with
|
||||
* visitTryCatchBlock).
|
||||
* @return a reference to the type of the given exception.
|
||||
*/
|
||||
public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
|
||||
return new TypeReference((EXCEPTION_PARAMETER << 24) | (tryCatchBlockIndex << 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the type of a type argument in a constructor or method call or reference.
|
||||
*
|
||||
* @param sort {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT
|
||||
* METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT
|
||||
* METHOD_REFERENCE_TYPE_ARGUMENT}.
|
||||
* @param argIndex the type argument index.
|
||||
* @return a reference to the type of the given type argument.
|
||||
*/
|
||||
public static TypeReference newTypeArgumentReference(int sort, int argIndex) {
|
||||
return new TypeReference((sort << 24) | argIndex);
|
||||
}
|
||||
/**
|
||||
* Returns a reference to the type of a type argument in a constructor or method call or reference.
|
||||
*
|
||||
* @param sort {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT
|
||||
* METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT
|
||||
* METHOD_REFERENCE_TYPE_ARGUMENT}.
|
||||
* @param argIndex the type argument index.
|
||||
* @return a reference to the type of the given type argument.
|
||||
*/
|
||||
public static TypeReference newTypeArgumentReference(int sort, int argIndex) {
|
||||
return new TypeReference((sort << 24) | argIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sort of this type reference.
|
||||
*
|
||||
* @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
|
||||
* {@link #CLASS_EXTENDS CLASS_EXTENDS}, {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},
|
||||
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}, {@link #FIELD FIELD}, {@link #METHOD_RETURN
|
||||
* METHOD_RETURN}, {@link #METHOD_RECEIVER METHOD_RECEIVER}, {@link #METHOD_FORMAL_PARAMETER
|
||||
* METHOD_FORMAL_PARAMETER}, {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
|
||||
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},
|
||||
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
|
||||
* {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT
|
||||
* METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT
|
||||
* METHOD_REFERENCE_TYPE_ARGUMENT}.
|
||||
*/
|
||||
public int getSort() {
|
||||
return value >>> 24;
|
||||
}
|
||||
/**
|
||||
* Returns the sort of this type reference.
|
||||
*
|
||||
* @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
|
||||
* {@link #CLASS_EXTENDS CLASS_EXTENDS}, {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},
|
||||
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}, {@link #FIELD FIELD}, {@link #METHOD_RETURN
|
||||
* METHOD_RETURN}, {@link #METHOD_RECEIVER METHOD_RECEIVER}, {@link #METHOD_FORMAL_PARAMETER
|
||||
* METHOD_FORMAL_PARAMETER}, {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
|
||||
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},
|
||||
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
|
||||
* {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT
|
||||
* METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT
|
||||
* METHOD_REFERENCE_TYPE_ARGUMENT}.
|
||||
*/
|
||||
public int getSort() {
|
||||
return value >>> 24;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the type parameter referenced by this type reference. This method must only be used for type
|
||||
* references whose sort is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER
|
||||
* METHOD_TYPE_PARAMETER}, {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
|
||||
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
|
||||
*
|
||||
* @return a type parameter index.
|
||||
*/
|
||||
public int getTypeParameterIndex() {
|
||||
return (value & 0x00FF0000) >> 16;
|
||||
}
|
||||
/**
|
||||
* Returns the index of the type parameter referenced by this type reference. This method must only be used for type
|
||||
* references whose sort is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER
|
||||
* METHOD_TYPE_PARAMETER}, {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
|
||||
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
|
||||
*
|
||||
* @return a type parameter index.
|
||||
*/
|
||||
public int getTypeParameterIndex() {
|
||||
return (value & 0x00FF0000) >> 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the type parameter bound, within the type parameter {@link #getTypeParameterIndex},
|
||||
* referenced by this type reference. This method must only be used for type references whose sort is
|
||||
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or {@link #METHOD_TYPE_PARAMETER_BOUND
|
||||
* METHOD_TYPE_PARAMETER_BOUND}.
|
||||
*
|
||||
* @return a type parameter bound index.
|
||||
*/
|
||||
public int getTypeParameterBoundIndex() {
|
||||
return (value & 0x0000FF00) >> 8;
|
||||
}
|
||||
/**
|
||||
* Returns the index of the type parameter bound, within the type parameter {@link #getTypeParameterIndex},
|
||||
* referenced by this type reference. This method must only be used for type references whose sort is
|
||||
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or {@link #METHOD_TYPE_PARAMETER_BOUND
|
||||
* METHOD_TYPE_PARAMETER_BOUND}.
|
||||
*
|
||||
* @return a type parameter bound index.
|
||||
*/
|
||||
public int getTypeParameterBoundIndex() {
|
||||
return (value & 0x0000FF00) >> 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the "super type" of a class that is referenced by this type reference. This method must only
|
||||
* be used for type references whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.
|
||||
*
|
||||
* @return the index of an interface in the 'implements' clause of a class, or -1 if this type reference references
|
||||
* the type of the super class.
|
||||
*/
|
||||
public int getSuperTypeIndex() {
|
||||
return (short) ((value & 0x00FFFF00) >> 8);
|
||||
}
|
||||
/**
|
||||
* Returns the index of the "super type" of a class that is referenced by this type reference. This method must only
|
||||
* be used for type references whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.
|
||||
*
|
||||
* @return the index of an interface in the 'implements' clause of a class, or -1 if this type reference references
|
||||
* the type of the super class.
|
||||
*/
|
||||
public int getSuperTypeIndex() {
|
||||
return (short) ((value & 0x00FFFF00) >> 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the formal parameter whose type is referenced by this type reference. This method must only
|
||||
* be used for type references whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.
|
||||
*
|
||||
* @return a formal parameter index.
|
||||
*/
|
||||
public int getFormalParameterIndex() {
|
||||
return (value & 0x00FF0000) >> 16;
|
||||
}
|
||||
/**
|
||||
* Returns the index of the formal parameter whose type is referenced by this type reference. This method must only
|
||||
* be used for type references whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.
|
||||
*
|
||||
* @return a formal parameter index.
|
||||
*/
|
||||
public int getFormalParameterIndex() {
|
||||
return (value & 0x00FF0000) >> 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the exception, in a 'throws' clause of a method, whose type is referenced by this type
|
||||
* reference. This method must only be used for type references whose sort is {@link #THROWS THROWS}.
|
||||
*
|
||||
* @return the index of an exception in the 'throws' clause of a method.
|
||||
*/
|
||||
public int getExceptionIndex() {
|
||||
return (value & 0x00FFFF00) >> 8;
|
||||
}
|
||||
/**
|
||||
* Returns the index of the exception, in a 'throws' clause of a method, whose type is referenced by this type
|
||||
* reference. This method must only be used for type references whose sort is {@link #THROWS THROWS}.
|
||||
*
|
||||
* @return the index of an exception in the 'throws' clause of a method.
|
||||
*/
|
||||
public int getExceptionIndex() {
|
||||
return (value & 0x00FFFF00) >> 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the try catch block (using the order in which they are visited with visitTryCatchBlock),
|
||||
* whose 'catch' type is referenced by this type reference. This method must only be used for type references whose
|
||||
* sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .
|
||||
*
|
||||
* @return the index of an exception in the 'throws' clause of a method.
|
||||
*/
|
||||
public int getTryCatchBlockIndex() {
|
||||
return (value & 0x00FFFF00) >> 8;
|
||||
}
|
||||
/**
|
||||
* Returns the index of the try catch block (using the order in which they are visited with visitTryCatchBlock),
|
||||
* whose 'catch' type is referenced by this type reference. This method must only be used for type references whose
|
||||
* sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .
|
||||
*
|
||||
* @return the index of an exception in the 'throws' clause of a method.
|
||||
*/
|
||||
public int getTryCatchBlockIndex() {
|
||||
return (value & 0x00FFFF00) >> 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the type argument referenced by this type reference. This method must only be used for type
|
||||
* references whose sort is {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
|
||||
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
|
||||
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
|
||||
*
|
||||
* @return a type parameter index.
|
||||
*/
|
||||
public int getTypeArgumentIndex() {
|
||||
return value & 0xFF;
|
||||
}
|
||||
/**
|
||||
* Returns the index of the type argument referenced by this type reference. This method must only be used for type
|
||||
* references whose sort is {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
|
||||
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
|
||||
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
|
||||
*
|
||||
* @return a type parameter index.
|
||||
*/
|
||||
public int getTypeArgumentIndex() {
|
||||
return value & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the int encoded value of this type reference, suitable for use in visit methods related to type
|
||||
* annotations, like visitTypeAnnotation.
|
||||
*
|
||||
* @return the int encoded value of this type reference.
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* Returns the int encoded value of this type reference, suitable for use in visit methods related to type
|
||||
* annotations, like visitTypeAnnotation.
|
||||
*
|
||||
* @return the int encoded value of this type reference.
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,457 +38,457 @@ import org.redkale.util.Utility;
|
||||
*/
|
||||
class AppConfig {
|
||||
|
||||
/**
|
||||
* 当前进程的配置文件, 类型:String、URI、File、Path <br>
|
||||
* 一般命名为: application.xml、application.onlyLogProps, 若配置文件不是本地文件, 则File、Path类型的值为null
|
||||
*/
|
||||
static final String PARAM_APP_CONF_FILE = "APP_CONF_FILE";
|
||||
/**
|
||||
* 当前进程的配置文件, 类型:String、URI、File、Path <br>
|
||||
* 一般命名为: application.xml、application.onlyLogProps, 若配置文件不是本地文件, 则File、Path类型的值为null
|
||||
*/
|
||||
static final String PARAM_APP_CONF_FILE = "APP_CONF_FILE";
|
||||
|
||||
// 是否用于main方法运行
|
||||
final boolean singletonMode;
|
||||
// 是否用于main方法运行
|
||||
final boolean singletonMode;
|
||||
|
||||
// 是否用于编译模式运行
|
||||
final boolean compileMode;
|
||||
// 是否用于编译模式运行
|
||||
final boolean compileMode;
|
||||
|
||||
// application.xml原始配置信息
|
||||
AnyValue config;
|
||||
// application.xml原始配置信息
|
||||
AnyValue config;
|
||||
|
||||
// 是否从/META-INF中读取配置
|
||||
boolean configFromCache;
|
||||
// 是否从/META-INF中读取配置
|
||||
boolean configFromCache;
|
||||
|
||||
// 本进程节点ID
|
||||
String nodeid;
|
||||
// 本进程节点ID
|
||||
String nodeid;
|
||||
|
||||
// 本进程节点ID
|
||||
String name;
|
||||
// 本进程节点ID
|
||||
String name;
|
||||
|
||||
// 本地IP地址
|
||||
InetSocketAddress localAddress;
|
||||
// 本地IP地址
|
||||
InetSocketAddress localAddress;
|
||||
|
||||
// 进程根目录
|
||||
File home;
|
||||
// 进程根目录
|
||||
File home;
|
||||
|
||||
// 配置文件目录
|
||||
File confFile;
|
||||
// 配置文件目录
|
||||
File confFile;
|
||||
|
||||
// 配置文件目录
|
||||
URI confDir;
|
||||
// 配置文件目录
|
||||
URI confDir;
|
||||
|
||||
// 根ClassLoader
|
||||
RedkaleClassLoader classLoader;
|
||||
// 根ClassLoader
|
||||
RedkaleClassLoader classLoader;
|
||||
|
||||
// Server根ClassLoader
|
||||
RedkaleClassLoader serverClassLoader;
|
||||
// Server根ClassLoader
|
||||
RedkaleClassLoader serverClassLoader;
|
||||
|
||||
// 本地文件日志配置项
|
||||
final Properties locaLogProperties = new Properties();
|
||||
// 本地文件日志配置项
|
||||
final Properties locaLogProperties = new Properties();
|
||||
|
||||
// 本地文件除logging配置之外的所有的配置项, 包含system.property.、mimetype.property.开头的
|
||||
final Properties localEnvProperties = new Properties();
|
||||
// 本地文件除logging配置之外的所有的配置项, 包含system.property.、mimetype.property.开头的
|
||||
final Properties localEnvProperties = new Properties();
|
||||
|
||||
public AppConfig(boolean singletonMode, boolean compileMode) {
|
||||
this.singletonMode = singletonMode;
|
||||
this.compileMode = compileMode;
|
||||
}
|
||||
public AppConfig(boolean singletonMode, boolean compileMode) {
|
||||
this.singletonMode = singletonMode;
|
||||
this.compileMode = compileMode;
|
||||
}
|
||||
|
||||
public static AppConfig create(boolean singletonMode, boolean compileMode) throws IOException {
|
||||
AppConfig rs = new AppConfig(singletonMode, compileMode);
|
||||
rs.init(loadAppConfig());
|
||||
return rs;
|
||||
}
|
||||
public static AppConfig create(boolean singletonMode, boolean compileMode) throws IOException {
|
||||
AppConfig rs = new AppConfig(singletonMode, compileMode);
|
||||
rs.init(loadAppConfig());
|
||||
return rs;
|
||||
}
|
||||
|
||||
private void init(AnyValue conf) {
|
||||
this.config = conf;
|
||||
this.name = checkName(config.getValue("name", ""));
|
||||
this.nodeid = checkNodeid(config.getValue("nodeid", String.valueOf(Math.abs(System.nanoTime()))));
|
||||
this.configFromCache = "true".equals(config.getValue("[config-from-cache]"));
|
||||
// 初始化classLoader、serverClassLoader
|
||||
this.initClassLoader();
|
||||
// 初始化home、confDir、localAddress等信息
|
||||
this.initAppHome();
|
||||
// 读取本地参数配置
|
||||
this.initLocalProperties();
|
||||
// 读取本地日志配置
|
||||
this.initLogProperties();
|
||||
// 读取本地数据库配置
|
||||
this.initSourceProperties();
|
||||
}
|
||||
private void init(AnyValue conf) {
|
||||
this.config = conf;
|
||||
this.name = checkName(config.getValue("name", ""));
|
||||
this.nodeid = checkNodeid(config.getValue("nodeid", String.valueOf(Math.abs(System.nanoTime()))));
|
||||
this.configFromCache = "true".equals(config.getValue("[config-from-cache]"));
|
||||
// 初始化classLoader、serverClassLoader
|
||||
this.initClassLoader();
|
||||
// 初始化home、confDir、localAddress等信息
|
||||
this.initAppHome();
|
||||
// 读取本地参数配置
|
||||
this.initLocalProperties();
|
||||
// 读取本地日志配置
|
||||
this.initLogProperties();
|
||||
// 读取本地数据库配置
|
||||
this.initSourceProperties();
|
||||
}
|
||||
|
||||
/** 初始化classLoader、serverClassLoader */
|
||||
private void initClassLoader() {
|
||||
ClassLoader currClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
if (currClassLoader instanceof RedkaleClassLoader) {
|
||||
this.classLoader = (RedkaleClassLoader) currClassLoader;
|
||||
} else {
|
||||
Set<String> cacheClasses = null;
|
||||
if (!singletonMode && !compileMode) {
|
||||
try {
|
||||
InputStream in =
|
||||
Application.class.getResourceAsStream(RedkaleClassLoader.RESOURCE_CACHE_CLASSES_PATH);
|
||||
if (in != null) {
|
||||
BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8), 1024);
|
||||
List<String> list = new ArrayList<>();
|
||||
reader.lines().forEach(list::add);
|
||||
Collections.sort(list);
|
||||
if (!list.isEmpty()) {
|
||||
cacheClasses = new LinkedHashSet<>(list);
|
||||
}
|
||||
in.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
if (cacheClasses == null) {
|
||||
this.classLoader = new RedkaleClassLoader(currClassLoader);
|
||||
} else {
|
||||
this.classLoader = new RedkaleClassLoader.RedkaleCacheClassLoader(currClassLoader, cacheClasses);
|
||||
}
|
||||
Thread.currentThread().setContextClassLoader(this.classLoader);
|
||||
}
|
||||
if (compileMode || this.classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader) {
|
||||
this.serverClassLoader = this.classLoader;
|
||||
} else {
|
||||
this.serverClassLoader = new RedkaleClassLoader(this.classLoader);
|
||||
}
|
||||
}
|
||||
/** 初始化classLoader、serverClassLoader */
|
||||
private void initClassLoader() {
|
||||
ClassLoader currClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
if (currClassLoader instanceof RedkaleClassLoader) {
|
||||
this.classLoader = (RedkaleClassLoader) currClassLoader;
|
||||
} else {
|
||||
Set<String> cacheClasses = null;
|
||||
if (!singletonMode && !compileMode) {
|
||||
try {
|
||||
InputStream in =
|
||||
Application.class.getResourceAsStream(RedkaleClassLoader.RESOURCE_CACHE_CLASSES_PATH);
|
||||
if (in != null) {
|
||||
BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8), 1024);
|
||||
List<String> list = new ArrayList<>();
|
||||
reader.lines().forEach(list::add);
|
||||
Collections.sort(list);
|
||||
if (!list.isEmpty()) {
|
||||
cacheClasses = new LinkedHashSet<>(list);
|
||||
}
|
||||
in.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
if (cacheClasses == null) {
|
||||
this.classLoader = new RedkaleClassLoader(currClassLoader);
|
||||
} else {
|
||||
this.classLoader = new RedkaleClassLoader.RedkaleCacheClassLoader(currClassLoader, cacheClasses);
|
||||
}
|
||||
Thread.currentThread().setContextClassLoader(this.classLoader);
|
||||
}
|
||||
if (compileMode || this.classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader) {
|
||||
this.serverClassLoader = this.classLoader;
|
||||
} else {
|
||||
this.serverClassLoader = new RedkaleClassLoader(this.classLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/** 初始化home、confDir、localAddress等信息 */
|
||||
private void initAppHome() {
|
||||
final File root = new File(System.getProperty(RESNAME_APP_HOME, ""));
|
||||
final String rootPath = getCanonicalPath(root);
|
||||
this.home = new File(rootPath);
|
||||
String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf");
|
||||
if (confDir.contains("://")
|
||||
|| confDir.startsWith("file:")
|
||||
|| confDir.startsWith("resource:")
|
||||
|| confDir.contains("!")) { // graalvm native-image startwith resource:META-INF
|
||||
this.confDir = URI.create(confDir);
|
||||
if (confDir.startsWith("file:")) {
|
||||
this.confFile = getCanonicalFile(new File(this.confDir.getPath()));
|
||||
}
|
||||
} else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > -1) {
|
||||
this.confFile = getCanonicalFile(new File(confDir));
|
||||
this.confDir = confFile.toURI();
|
||||
} else {
|
||||
this.confFile = new File(getCanonicalPath(new File(this.home, confDir)));
|
||||
this.confDir = confFile.toURI();
|
||||
}
|
||||
String localaddr = config.getValue("address", "").trim();
|
||||
InetAddress addr = localaddr.isEmpty()
|
||||
? Utility.localInetAddress()
|
||||
: new InetSocketAddress(localaddr, config.getIntValue("port")).getAddress();
|
||||
this.localAddress = new InetSocketAddress(addr, config.getIntValue("port"));
|
||||
}
|
||||
/** 初始化home、confDir、localAddress等信息 */
|
||||
private void initAppHome() {
|
||||
final File root = new File(System.getProperty(RESNAME_APP_HOME, ""));
|
||||
final String rootPath = getCanonicalPath(root);
|
||||
this.home = new File(rootPath);
|
||||
String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf");
|
||||
if (confDir.contains("://")
|
||||
|| confDir.startsWith("file:")
|
||||
|| confDir.startsWith("resource:")
|
||||
|| confDir.contains("!")) { // graalvm native-image startwith resource:META-INF
|
||||
this.confDir = URI.create(confDir);
|
||||
if (confDir.startsWith("file:")) {
|
||||
this.confFile = getCanonicalFile(new File(this.confDir.getPath()));
|
||||
}
|
||||
} else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > -1) {
|
||||
this.confFile = getCanonicalFile(new File(confDir));
|
||||
this.confDir = confFile.toURI();
|
||||
} else {
|
||||
this.confFile = new File(getCanonicalPath(new File(this.home, confDir)));
|
||||
this.confDir = confFile.toURI();
|
||||
}
|
||||
String localaddr = config.getValue("address", "").trim();
|
||||
InetAddress addr = localaddr.isEmpty()
|
||||
? Utility.localInetAddress()
|
||||
: new InetSocketAddress(localaddr, config.getIntValue("port")).getAddress();
|
||||
this.localAddress = new InetSocketAddress(addr, config.getIntValue("port"));
|
||||
}
|
||||
|
||||
/** 读取本地参数配置 */
|
||||
private void initLocalProperties() {
|
||||
// 环境变量的优先级最高
|
||||
System.getProperties().forEach((k, v) -> {
|
||||
if (k.toString().startsWith("redkale.")) {
|
||||
localEnvProperties.put(k, v);
|
||||
}
|
||||
});
|
||||
AnyValue propsConf = this.config.getAnyValue("properties");
|
||||
if (propsConf == null) {
|
||||
final AnyValue resources = config.getAnyValue("resources");
|
||||
if (resources != null) {
|
||||
System.err.println("<resources> in application config file is deprecated");
|
||||
propsConf = resources.getAnyValue("properties");
|
||||
}
|
||||
}
|
||||
if (propsConf != null) { // 设置配置文件中的系统变量
|
||||
for (AnyValue prop : propsConf.getAnyValues("property")) {
|
||||
String key = prop.getValue("name", "");
|
||||
String value = prop.getValue("value");
|
||||
if (value != null) {
|
||||
localEnvProperties.put(key, value);
|
||||
}
|
||||
}
|
||||
if (propsConf.getValue("load") != null) { // 加载本地配置项文件
|
||||
for (String dfload :
|
||||
propsConf.getValue("load").replace(',', ';').split(";")) {
|
||||
if (dfload.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
final URI df = RedkaleClassLoader.getConfResourceAsURI(
|
||||
configFromCache ? null : this.confDir.toString(), dfload.trim());
|
||||
if (df == null) {
|
||||
continue;
|
||||
}
|
||||
if (!"file".equals(df.getScheme()) || df.toString().contains("!") || new File(df).isFile()) {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
InputStream in = df.toURL().openStream();
|
||||
props.load(in);
|
||||
in.close();
|
||||
localEnvProperties.putAll(props);
|
||||
} catch (Exception e) {
|
||||
throw new RedkaleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 设置Convert默认配置项
|
||||
if (System.getProperty("redkale.convert.pool.size") == null
|
||||
&& localEnvProperties.getProperty("system.property.redkale.convert.pool.size") == null) {
|
||||
localEnvProperties.put("system.property.redkale.convert.pool.size", "128");
|
||||
}
|
||||
if (System.getProperty("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");
|
||||
}
|
||||
}
|
||||
/** 读取本地参数配置 */
|
||||
private void initLocalProperties() {
|
||||
// 环境变量的优先级最高
|
||||
System.getProperties().forEach((k, v) -> {
|
||||
if (k.toString().startsWith("redkale.")) {
|
||||
localEnvProperties.put(k, v);
|
||||
}
|
||||
});
|
||||
AnyValue propsConf = this.config.getAnyValue("properties");
|
||||
if (propsConf == null) {
|
||||
final AnyValue resources = config.getAnyValue("resources");
|
||||
if (resources != null) {
|
||||
System.err.println("<resources> in application config file is deprecated");
|
||||
propsConf = resources.getAnyValue("properties");
|
||||
}
|
||||
}
|
||||
if (propsConf != null) { // 设置配置文件中的系统变量
|
||||
for (AnyValue prop : propsConf.getAnyValues("property")) {
|
||||
String key = prop.getValue("name", "");
|
||||
String value = prop.getValue("value");
|
||||
if (value != null) {
|
||||
localEnvProperties.put(key, value);
|
||||
}
|
||||
}
|
||||
if (propsConf.getValue("load") != null) { // 加载本地配置项文件
|
||||
for (String dfload :
|
||||
propsConf.getValue("load").replace(',', ';').split(";")) {
|
||||
if (dfload.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
final URI df = RedkaleClassLoader.getConfResourceAsURI(
|
||||
configFromCache ? null : this.confDir.toString(), dfload.trim());
|
||||
if (df == null) {
|
||||
continue;
|
||||
}
|
||||
if (!"file".equals(df.getScheme()) || df.toString().contains("!") || new File(df).isFile()) {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
InputStream in = df.toURL().openStream();
|
||||
props.load(in);
|
||||
in.close();
|
||||
localEnvProperties.putAll(props);
|
||||
} catch (Exception e) {
|
||||
throw new RedkaleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 设置Convert默认配置项
|
||||
if (System.getProperty("redkale.convert.pool.size") == null
|
||||
&& localEnvProperties.getProperty("system.property.redkale.convert.pool.size") == null) {
|
||||
localEnvProperties.put("system.property.redkale.convert.pool.size", "128");
|
||||
}
|
||||
if (System.getProperty("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");
|
||||
}
|
||||
}
|
||||
|
||||
/** 读取本地DataSource、CacheSource配置 */
|
||||
private void initSourceProperties() {
|
||||
if ("file".equals(this.confDir.getScheme())) {
|
||||
File sourceFile = new File(new File(confDir), "source.properties");
|
||||
if (sourceFile.isFile() && sourceFile.canRead()) {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
InputStream in = new FileInputStream(sourceFile);
|
||||
props.load(in);
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
throw new RedkaleException(e);
|
||||
}
|
||||
this.localEnvProperties.putAll(props);
|
||||
} else {
|
||||
// 兼容 persistence.xml 【已废弃】
|
||||
File persist = new File(new File(confDir), "persistence.xml");
|
||||
if (persist.isFile() && persist.canRead()) {
|
||||
System.err.println("persistence.xml is deprecated, replaced by source.properties");
|
||||
try {
|
||||
InputStream in = new FileInputStream(persist);
|
||||
this.localEnvProperties.putAll(DataSources.loadSourceProperties(in));
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
throw new RedkaleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // 从url或jar文件中resources读取
|
||||
try {
|
||||
final URI sourceURI = RedkaleClassLoader.getConfResourceAsURI(
|
||||
configFromCache ? null : this.confDir.toString(), "source.properties");
|
||||
InputStream in = sourceURI.toURL().openStream();
|
||||
Properties props = new Properties();
|
||||
props.load(in);
|
||||
in.close();
|
||||
this.localEnvProperties.putAll(props);
|
||||
} catch (Exception e) {
|
||||
// 没有文件 跳过
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 读取本地DataSource、CacheSource配置 */
|
||||
private void initSourceProperties() {
|
||||
if ("file".equals(this.confDir.getScheme())) {
|
||||
File sourceFile = new File(new File(confDir), "source.properties");
|
||||
if (sourceFile.isFile() && sourceFile.canRead()) {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
InputStream in = new FileInputStream(sourceFile);
|
||||
props.load(in);
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
throw new RedkaleException(e);
|
||||
}
|
||||
this.localEnvProperties.putAll(props);
|
||||
} else {
|
||||
// 兼容 persistence.xml 【已废弃】
|
||||
File persist = new File(new File(confDir), "persistence.xml");
|
||||
if (persist.isFile() && persist.canRead()) {
|
||||
System.err.println("persistence.xml is deprecated, replaced by source.properties");
|
||||
try {
|
||||
InputStream in = new FileInputStream(persist);
|
||||
this.localEnvProperties.putAll(DataSources.loadSourceProperties(in));
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
throw new RedkaleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // 从url或jar文件中resources读取
|
||||
try {
|
||||
final URI sourceURI = RedkaleClassLoader.getConfResourceAsURI(
|
||||
configFromCache ? null : this.confDir.toString(), "source.properties");
|
||||
InputStream in = sourceURI.toURL().openStream();
|
||||
Properties props = new Properties();
|
||||
props.load(in);
|
||||
in.close();
|
||||
this.localEnvProperties.putAll(props);
|
||||
} catch (Exception e) {
|
||||
// 没有文件 跳过
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 读取本地日志配置 */
|
||||
private void initLogProperties() {
|
||||
URI logConfURI;
|
||||
File logConfFile = null;
|
||||
if (configFromCache) {
|
||||
logConfURI = RedkaleClassLoader.getConfResourceAsURI(null, "logging.properties");
|
||||
} else if ("file".equals(confDir.getScheme())) {
|
||||
logConfFile = new File(confDir.getPath(), "logging.properties");
|
||||
logConfURI = logConfFile.toURI();
|
||||
if (!logConfFile.isFile() || !logConfFile.canRead()) {
|
||||
logConfFile = null;
|
||||
}
|
||||
} else {
|
||||
logConfURI = URI.create(confDir + (confDir.toString().endsWith("/") ? "" : "/") + "logging.properties");
|
||||
}
|
||||
if (!"file".equals(confDir.getScheme()) || logConfFile != null) {
|
||||
try {
|
||||
InputStream fin = logConfURI.toURL().openStream();
|
||||
Properties properties0 = new Properties();
|
||||
properties0.load(fin);
|
||||
fin.close();
|
||||
properties0.forEach(locaLogProperties::put);
|
||||
} catch (IOException e) {
|
||||
throw new RedkaleException("read logging.properties error", e);
|
||||
}
|
||||
}
|
||||
if (compileMode) {
|
||||
putReflectionClass(java.lang.Class.class.getName());
|
||||
putReflectionPublicConstructors(SimpleFormatter.class, SimpleFormatter.class.getName());
|
||||
putReflectionPublicConstructors(LoggingSearchHandler.class, LoggingSearchHandler.class.getName());
|
||||
putReflectionPublicConstructors(LoggingFileHandler.class, LoggingFileHandler.class.getName());
|
||||
putReflectionPublicConstructors(
|
||||
LoggingFileHandler.LoggingFormater.class, LoggingFileHandler.LoggingFormater.class.getName());
|
||||
putReflectionPublicConstructors(
|
||||
LoggingFileHandler.LoggingConsoleHandler.class,
|
||||
LoggingFileHandler.LoggingConsoleHandler.class.getName());
|
||||
putReflectionPublicConstructors(
|
||||
LoggingFileHandler.LoggingSncpFileHandler.class,
|
||||
LoggingFileHandler.LoggingSncpFileHandler.class.getName());
|
||||
}
|
||||
}
|
||||
/** 读取本地日志配置 */
|
||||
private void initLogProperties() {
|
||||
URI logConfURI;
|
||||
File logConfFile = null;
|
||||
if (configFromCache) {
|
||||
logConfURI = RedkaleClassLoader.getConfResourceAsURI(null, "logging.properties");
|
||||
} else if ("file".equals(confDir.getScheme())) {
|
||||
logConfFile = new File(confDir.getPath(), "logging.properties");
|
||||
logConfURI = logConfFile.toURI();
|
||||
if (!logConfFile.isFile() || !logConfFile.canRead()) {
|
||||
logConfFile = null;
|
||||
}
|
||||
} else {
|
||||
logConfURI = URI.create(confDir + (confDir.toString().endsWith("/") ? "" : "/") + "logging.properties");
|
||||
}
|
||||
if (!"file".equals(confDir.getScheme()) || logConfFile != null) {
|
||||
try {
|
||||
InputStream fin = logConfURI.toURL().openStream();
|
||||
Properties properties0 = new Properties();
|
||||
properties0.load(fin);
|
||||
fin.close();
|
||||
properties0.forEach(locaLogProperties::put);
|
||||
} catch (IOException e) {
|
||||
throw new RedkaleException("read logging.properties error", e);
|
||||
}
|
||||
}
|
||||
if (compileMode) {
|
||||
putReflectionClass(java.lang.Class.class.getName());
|
||||
putReflectionPublicConstructors(SimpleFormatter.class, SimpleFormatter.class.getName());
|
||||
putReflectionPublicConstructors(LoggingSearchHandler.class, LoggingSearchHandler.class.getName());
|
||||
putReflectionPublicConstructors(LoggingFileHandler.class, LoggingFileHandler.class.getName());
|
||||
putReflectionPublicConstructors(
|
||||
LoggingFileHandler.LoggingFormater.class, LoggingFileHandler.LoggingFormater.class.getName());
|
||||
putReflectionPublicConstructors(
|
||||
LoggingFileHandler.LoggingConsoleHandler.class,
|
||||
LoggingFileHandler.LoggingConsoleHandler.class.getName());
|
||||
putReflectionPublicConstructors(
|
||||
LoggingFileHandler.LoggingSncpFileHandler.class,
|
||||
LoggingFileHandler.LoggingSncpFileHandler.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从本地application.xml或application.properties文件加载配置信息
|
||||
*
|
||||
* @return 配置信息
|
||||
* @throws IOException
|
||||
*/
|
||||
static AnyValue loadAppConfig() throws IOException {
|
||||
final String home = new File(System.getProperty(RESNAME_APP_HOME, ""))
|
||||
.getCanonicalPath()
|
||||
.replace('\\', '/');
|
||||
String sysConfFile = System.getProperty(PARAM_APP_CONF_FILE);
|
||||
if (sysConfFile != null) {
|
||||
String text;
|
||||
if (sysConfFile.contains("://")) {
|
||||
text = Utility.readThenClose(URI.create(sysConfFile).toURL().openStream());
|
||||
} else {
|
||||
File f = new File(sysConfFile);
|
||||
if (f.isFile() && f.canRead()) {
|
||||
text = Utility.readThenClose(new FileInputStream(f));
|
||||
} else {
|
||||
throw new IOException("Read application conf file (" + sysConfFile + ") error ");
|
||||
}
|
||||
}
|
||||
return text.trim().startsWith("<")
|
||||
? AnyValue.loadFromXml(text, (k, v) -> v.replace("${" + RESNAME_APP_HOME + "}", home))
|
||||
.getAnyValue("application")
|
||||
: AnyValue.loadFromProperties(text).getAnyValue("redkale");
|
||||
}
|
||||
String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf");
|
||||
URI appConfFile;
|
||||
boolean fromCache = false;
|
||||
if (confDir.contains("://")) { // jar内部资源
|
||||
appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.xml");
|
||||
try {
|
||||
appConfFile.toURL().openStream().close();
|
||||
} catch (IOException e) { // 没有application.xml就尝试读application.properties
|
||||
appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.properties");
|
||||
}
|
||||
} else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > 0) { // 绝对路径
|
||||
File f = new File(confDir, "application.xml");
|
||||
if (f.isFile() && f.canRead()) {
|
||||
appConfFile = f.toURI();
|
||||
confDir = f.getParentFile().getCanonicalPath();
|
||||
} else {
|
||||
f = new File(confDir, "application.properties");
|
||||
if (f.isFile() && f.canRead()) {
|
||||
appConfFile = f.toURI();
|
||||
confDir = f.getParentFile().getCanonicalPath();
|
||||
} else {
|
||||
appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); // 不能传confDir
|
||||
try {
|
||||
appConfFile.toURL().openStream().close();
|
||||
} catch (IOException e) { // 没有application.xml就尝试读application.properties
|
||||
appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.properties");
|
||||
}
|
||||
confDir = appConfFile
|
||||
.toString()
|
||||
.replace("/application.xml", "")
|
||||
.replace("/application.properties", "");
|
||||
fromCache = true;
|
||||
}
|
||||
}
|
||||
} else { // 相对路径
|
||||
File f = new File(new File(home, confDir), "application.xml");
|
||||
if (f.isFile() && f.canRead()) {
|
||||
appConfFile = f.toURI();
|
||||
confDir = f.getParentFile().getCanonicalPath();
|
||||
} else {
|
||||
f = new File(new File(home, confDir), "application.properties");
|
||||
if (f.isFile() && f.canRead()) {
|
||||
appConfFile = f.toURI();
|
||||
confDir = f.getParentFile().getCanonicalPath();
|
||||
} else {
|
||||
appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); // 不能传confDir
|
||||
try {
|
||||
appConfFile.toURL().openStream().close();
|
||||
} catch (IOException e) { // 没有application.xml就尝试读application.properties
|
||||
appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.properties");
|
||||
}
|
||||
confDir = appConfFile
|
||||
.toString()
|
||||
.replace("/application.xml", "")
|
||||
.replace("/application.properties", "");
|
||||
fromCache = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
System.setProperty(RESNAME_APP_CONF_DIR, confDir);
|
||||
String text = Utility.readThenClose(appConfFile.toURL().openStream());
|
||||
AnyValue conf;
|
||||
if (text.trim().startsWith("<")) {
|
||||
conf = AnyValue.loadFromXml(text, (k, v) -> v.replace("${APP_HOME}", home))
|
||||
.getAnyValue("application");
|
||||
} else {
|
||||
conf = AnyValue.loadFromProperties(text).getAnyValue("redkale");
|
||||
}
|
||||
if (fromCache) {
|
||||
((AnyValueWriter) conf).addValue("[config-from-cache]", "true");
|
||||
}
|
||||
/**
|
||||
* 从本地application.xml或application.properties文件加载配置信息
|
||||
*
|
||||
* @return 配置信息
|
||||
* @throws IOException
|
||||
*/
|
||||
static AnyValue loadAppConfig() throws IOException {
|
||||
final String home = new File(System.getProperty(RESNAME_APP_HOME, ""))
|
||||
.getCanonicalPath()
|
||||
.replace('\\', '/');
|
||||
String sysConfFile = System.getProperty(PARAM_APP_CONF_FILE);
|
||||
if (sysConfFile != null) {
|
||||
String text;
|
||||
if (sysConfFile.contains("://")) {
|
||||
text = Utility.readThenClose(URI.create(sysConfFile).toURL().openStream());
|
||||
} else {
|
||||
File f = new File(sysConfFile);
|
||||
if (f.isFile() && f.canRead()) {
|
||||
text = Utility.readThenClose(new FileInputStream(f));
|
||||
} else {
|
||||
throw new IOException("Read application conf file (" + sysConfFile + ") error ");
|
||||
}
|
||||
}
|
||||
return text.trim().startsWith("<")
|
||||
? AnyValue.loadFromXml(text, (k, v) -> v.replace("${" + RESNAME_APP_HOME + "}", home))
|
||||
.getAnyValue("application")
|
||||
: AnyValue.loadFromProperties(text).getAnyValue("redkale");
|
||||
}
|
||||
String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf");
|
||||
URI appConfFile;
|
||||
boolean fromCache = false;
|
||||
if (confDir.contains("://")) { // jar内部资源
|
||||
appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.xml");
|
||||
try {
|
||||
appConfFile.toURL().openStream().close();
|
||||
} catch (IOException e) { // 没有application.xml就尝试读application.properties
|
||||
appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.properties");
|
||||
}
|
||||
} else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > 0) { // 绝对路径
|
||||
File f = new File(confDir, "application.xml");
|
||||
if (f.isFile() && f.canRead()) {
|
||||
appConfFile = f.toURI();
|
||||
confDir = f.getParentFile().getCanonicalPath();
|
||||
} else {
|
||||
f = new File(confDir, "application.properties");
|
||||
if (f.isFile() && f.canRead()) {
|
||||
appConfFile = f.toURI();
|
||||
confDir = f.getParentFile().getCanonicalPath();
|
||||
} else {
|
||||
appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); // 不能传confDir
|
||||
try {
|
||||
appConfFile.toURL().openStream().close();
|
||||
} catch (IOException e) { // 没有application.xml就尝试读application.properties
|
||||
appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.properties");
|
||||
}
|
||||
confDir = appConfFile
|
||||
.toString()
|
||||
.replace("/application.xml", "")
|
||||
.replace("/application.properties", "");
|
||||
fromCache = true;
|
||||
}
|
||||
}
|
||||
} else { // 相对路径
|
||||
File f = new File(new File(home, confDir), "application.xml");
|
||||
if (f.isFile() && f.canRead()) {
|
||||
appConfFile = f.toURI();
|
||||
confDir = f.getParentFile().getCanonicalPath();
|
||||
} else {
|
||||
f = new File(new File(home, confDir), "application.properties");
|
||||
if (f.isFile() && f.canRead()) {
|
||||
appConfFile = f.toURI();
|
||||
confDir = f.getParentFile().getCanonicalPath();
|
||||
} else {
|
||||
appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); // 不能传confDir
|
||||
try {
|
||||
appConfFile.toURL().openStream().close();
|
||||
} catch (IOException e) { // 没有application.xml就尝试读application.properties
|
||||
appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.properties");
|
||||
}
|
||||
confDir = appConfFile
|
||||
.toString()
|
||||
.replace("/application.xml", "")
|
||||
.replace("/application.properties", "");
|
||||
fromCache = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
System.setProperty(RESNAME_APP_CONF_DIR, confDir);
|
||||
String text = Utility.readThenClose(appConfFile.toURL().openStream());
|
||||
AnyValue conf;
|
||||
if (text.trim().startsWith("<")) {
|
||||
conf = AnyValue.loadFromXml(text, (k, v) -> v.replace("${APP_HOME}", home))
|
||||
.getAnyValue("application");
|
||||
} else {
|
||||
conf = AnyValue.loadFromProperties(text).getAnyValue("redkale");
|
||||
}
|
||||
if (fromCache) {
|
||||
((AnyValueWriter) conf).addValue("[config-from-cache]", "true");
|
||||
}
|
||||
|
||||
return conf;
|
||||
}
|
||||
return conf;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查name是否含特殊字符
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
private static String checkName(String name) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
return name;
|
||||
}
|
||||
for (char ch : name.toCharArray()) {
|
||||
if (!((ch >= '0' && ch <= '9')
|
||||
|| (ch >= 'a' && ch <= 'z')
|
||||
|| (ch >= 'A' && ch <= 'Z')
|
||||
|| ch == '_'
|
||||
|| ch == '.'
|
||||
|| ch == '-')) { // 不能含特殊字符
|
||||
throw new RedkaleException("name only 0-9 a-z A-Z _ - .");
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
/**
|
||||
* 检查name是否含特殊字符
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
private static String checkName(String name) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
return name;
|
||||
}
|
||||
for (char ch : name.toCharArray()) {
|
||||
if (!((ch >= '0' && ch <= '9')
|
||||
|| (ch >= 'a' && ch <= 'z')
|
||||
|| (ch >= 'A' && ch <= 'Z')
|
||||
|| ch == '_'
|
||||
|| ch == '.'
|
||||
|| ch == '-')) { // 不能含特殊字符
|
||||
throw new RedkaleException("name only 0-9 a-z A-Z _ - .");
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查node是否含特殊字符
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
private static String checkNodeid(String nodeid) {
|
||||
if (nodeid == null || nodeid.isEmpty()) {
|
||||
return nodeid;
|
||||
}
|
||||
for (char ch : nodeid.toCharArray()) {
|
||||
if (!((ch >= '0' && ch <= '9')
|
||||
|| (ch >= 'a' && ch <= 'z')
|
||||
|| (ch >= 'A' && ch <= 'Z')
|
||||
|| ch == '_'
|
||||
|| ch == '.'
|
||||
|| ch == '-')) { // 不能含特殊字符
|
||||
throw new RedkaleException("nodeid only 0-9 a-z A-Z _ - .");
|
||||
}
|
||||
}
|
||||
return nodeid;
|
||||
}
|
||||
/**
|
||||
* 检查node是否含特殊字符
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
private static String checkNodeid(String nodeid) {
|
||||
if (nodeid == null || nodeid.isEmpty()) {
|
||||
return nodeid;
|
||||
}
|
||||
for (char ch : nodeid.toCharArray()) {
|
||||
if (!((ch >= '0' && ch <= '9')
|
||||
|| (ch >= 'a' && ch <= 'z')
|
||||
|| (ch >= 'A' && ch <= 'Z')
|
||||
|| ch == '_'
|
||||
|| ch == '.'
|
||||
|| ch == '-')) { // 不能含特殊字符
|
||||
throw new RedkaleException("nodeid only 0-9 a-z A-Z _ - .");
|
||||
}
|
||||
}
|
||||
return nodeid;
|
||||
}
|
||||
|
||||
private String getCanonicalPath(File file) {
|
||||
try {
|
||||
return file.getCanonicalPath();
|
||||
} catch (IOException e) {
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
private String getCanonicalPath(File file) {
|
||||
try {
|
||||
return file.getCanonicalPath();
|
||||
} catch (IOException e) {
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
private File getCanonicalFile(File file) {
|
||||
try {
|
||||
return file.getCanonicalFile();
|
||||
} catch (IOException e) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
private File getCanonicalFile(File file) {
|
||||
try {
|
||||
return file.getCanonicalFile();
|
||||
} catch (IOException e) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,59 +17,59 @@ import org.redkale.util.AnyValue;
|
||||
*/
|
||||
public interface ApplicationListener {
|
||||
|
||||
/**
|
||||
* 初始化方法
|
||||
*
|
||||
* @param config 配置参数
|
||||
*/
|
||||
default void init(AnyValue config) {}
|
||||
/**
|
||||
* 初始化方法
|
||||
*
|
||||
* @param config 配置参数
|
||||
*/
|
||||
default void init(AnyValue config) {}
|
||||
|
||||
/**
|
||||
* Application在运行start前调用
|
||||
*
|
||||
* @param application Application
|
||||
*/
|
||||
default void onPreStart(Application application) {}
|
||||
/**
|
||||
* Application在运行start前调用
|
||||
*
|
||||
* @param application Application
|
||||
*/
|
||||
default void onPreStart(Application application) {}
|
||||
|
||||
/**
|
||||
* 服务全部停掉前被调用
|
||||
*
|
||||
* @param application Application
|
||||
*/
|
||||
default void onServersPreStop(Application application) {}
|
||||
/**
|
||||
* 服务全部停掉前被调用
|
||||
*
|
||||
* @param application Application
|
||||
*/
|
||||
default void onServersPreStop(Application application) {}
|
||||
|
||||
/**
|
||||
* 服务全部停掉后被调用
|
||||
*
|
||||
* @param application Application
|
||||
*/
|
||||
default void onServersPostStop(Application application) {}
|
||||
/**
|
||||
* 服务全部停掉后被调用
|
||||
*
|
||||
* @param application Application
|
||||
*/
|
||||
default void onServersPostStop(Application application) {}
|
||||
|
||||
/**
|
||||
* Application在运行start后调用
|
||||
*
|
||||
* @param application Application
|
||||
*/
|
||||
default void onPostStart(Application application) {}
|
||||
/**
|
||||
* Application在运行start后调用
|
||||
*
|
||||
* @param application Application
|
||||
*/
|
||||
default void onPostStart(Application application) {}
|
||||
|
||||
/**
|
||||
* Application在运行Compile前调用
|
||||
*
|
||||
* @param application Application
|
||||
*/
|
||||
default void onPreCompile(Application application) {}
|
||||
/**
|
||||
* Application在运行Compile前调用
|
||||
*
|
||||
* @param application Application
|
||||
*/
|
||||
default void onPreCompile(Application application) {}
|
||||
|
||||
/**
|
||||
* Application在运行Compile后调用
|
||||
*
|
||||
* @param application Application
|
||||
*/
|
||||
default void onPostCompile(Application application) {}
|
||||
/**
|
||||
* Application在运行Compile后调用
|
||||
*
|
||||
* @param application Application
|
||||
*/
|
||||
default void onPostCompile(Application application) {}
|
||||
|
||||
/**
|
||||
* Application在运行shutdown前调用
|
||||
*
|
||||
* @param application Application
|
||||
*/
|
||||
default void onPreShutdown(Application application) {}
|
||||
/**
|
||||
* Application在运行shutdown前调用
|
||||
*
|
||||
* @param application Application
|
||||
*/
|
||||
default void onPreShutdown(Application application) {}
|
||||
}
|
||||
|
||||
@@ -13,40 +13,40 @@ import org.redkale.util.Environment;
|
||||
/** @author zhangjx */
|
||||
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) {
|
||||
this.application = application;
|
||||
this.resourceFactory = Objects.requireNonNull(application.resourceFactory);
|
||||
this.environment = Objects.requireNonNull(application.getEnvironment());
|
||||
}
|
||||
protected BootModule(Application application) {
|
||||
this.application = application;
|
||||
this.resourceFactory = Objects.requireNonNull(application.resourceFactory);
|
||||
this.environment = Objects.requireNonNull(application.getEnvironment());
|
||||
}
|
||||
|
||||
protected void removeEnvValue(String name) {
|
||||
application.envProperties.remove(name);
|
||||
}
|
||||
protected void removeEnvValue(String name) {
|
||||
application.envProperties.remove(name);
|
||||
}
|
||||
|
||||
protected void putEnvValue(Object name, Object value) {
|
||||
application.envProperties.put(name, value);
|
||||
}
|
||||
protected void putEnvValue(Object name, Object value) {
|
||||
application.envProperties.put(name, value);
|
||||
}
|
||||
|
||||
protected List<ModuleEngine> getModuleEngines() {
|
||||
return application.getModuleEngines();
|
||||
}
|
||||
protected List<ModuleEngine> getModuleEngines() {
|
||||
return application.getModuleEngines();
|
||||
}
|
||||
|
||||
protected void reconfigLogging(boolean first, Properties allProps) {
|
||||
application.loggingModule.reconfigLogging(first, allProps);
|
||||
}
|
||||
protected void reconfigLogging(boolean first, Properties allProps) {
|
||||
application.loggingModule.reconfigLogging(first, allProps);
|
||||
}
|
||||
|
||||
protected void onEnvironmentChanged(String namespace, List<ResourceEvent> events) {
|
||||
if (namespace != null && namespace.contains("logging")) {
|
||||
// 日志配置单独处理
|
||||
application.loggingModule.onEnvironmentUpdated(events);
|
||||
} else {
|
||||
application.onEnvironmentChanged(namespace, events);
|
||||
}
|
||||
}
|
||||
protected void onEnvironmentChanged(String namespace, List<ResourceEvent> events) {
|
||||
if (namespace != null && namespace.contains("logging")) {
|
||||
// 日志配置单独处理
|
||||
application.loggingModule.onEnvironmentUpdated(events);
|
||||
} else {
|
||||
application.onEnvironmentChanged(namespace, events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,126 +16,126 @@ import org.redkale.util.Traces;
|
||||
*/
|
||||
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";
|
||||
// 无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%n%5$s%6$s%n";
|
||||
// 无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";
|
||||
|
||||
// 有threadName
|
||||
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";
|
||||
// 有threadName
|
||||
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";
|
||||
|
||||
// 有threadName、TID
|
||||
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";
|
||||
// 有threadName、TID
|
||||
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";
|
||||
|
||||
static boolean traceEnable = false; // 防止设置system.property前调用Traces类导致enable提前初始化
|
||||
static boolean traceEnable = false; // 防止设置system.property前调用Traces类导致enable提前初始化
|
||||
|
||||
/** 默认的日志时间格式化类 与SimpleFormatter的区别在于level不使用本地化 */
|
||||
public static class LoggingFormater extends Formatter {
|
||||
/** 默认的日志时间格式化类 与SimpleFormatter的区别在于level不使用本地化 */
|
||||
public static class LoggingFormater extends Formatter {
|
||||
|
||||
@Override
|
||||
public String format(LogRecord log) {
|
||||
if (log.getThrown() == null
|
||||
&& log.getMessage() != null
|
||||
&& log.getMessage().startsWith("------")) {
|
||||
return formatMessage(log) + "\r\n";
|
||||
}
|
||||
String source;
|
||||
if (log.getSourceClassName() != null) {
|
||||
source = log.getSourceClassName();
|
||||
if (log.getSourceMethodName() != null) {
|
||||
source += " " + log.getSourceMethodName();
|
||||
}
|
||||
} else {
|
||||
source = log.getLoggerName();
|
||||
}
|
||||
String message = formatMessage(log);
|
||||
String throwable = "";
|
||||
if (log.getThrown() != null) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw) {
|
||||
@Override
|
||||
public void println() {
|
||||
super.print("\r\n");
|
||||
}
|
||||
};
|
||||
pw.println();
|
||||
log.getThrown().printStackTrace(pw);
|
||||
pw.close();
|
||||
throwable = sw.toString();
|
||||
}
|
||||
Object[] params = log.getParameters();
|
||||
if (params != null) {
|
||||
if (params.length == 1) {
|
||||
return String.format(
|
||||
FORMATTER_FORMAT2,
|
||||
log.getInstant().toEpochMilli(),
|
||||
source,
|
||||
log.getLoggerName(),
|
||||
log.getLevel().getName(),
|
||||
message,
|
||||
throwable,
|
||||
params[0]);
|
||||
} else if (params.length == 2) {
|
||||
return String.format(
|
||||
FORMATTER_FORMAT3,
|
||||
log.getInstant().toEpochMilli(),
|
||||
source,
|
||||
log.getLoggerName(),
|
||||
log.getLevel().getName(),
|
||||
message,
|
||||
throwable,
|
||||
params[0],
|
||||
params[1]);
|
||||
}
|
||||
}
|
||||
return String.format(
|
||||
FORMATTER_FORMAT,
|
||||
log.getInstant().toEpochMilli(),
|
||||
source,
|
||||
log.getLoggerName(),
|
||||
log.getLevel().getName(),
|
||||
message,
|
||||
throwable);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String format(LogRecord log) {
|
||||
if (log.getThrown() == null
|
||||
&& log.getMessage() != null
|
||||
&& log.getMessage().startsWith("------")) {
|
||||
return formatMessage(log) + "\r\n";
|
||||
}
|
||||
String source;
|
||||
if (log.getSourceClassName() != null) {
|
||||
source = log.getSourceClassName();
|
||||
if (log.getSourceMethodName() != null) {
|
||||
source += " " + log.getSourceMethodName();
|
||||
}
|
||||
} else {
|
||||
source = log.getLoggerName();
|
||||
}
|
||||
String message = formatMessage(log);
|
||||
String throwable = "";
|
||||
if (log.getThrown() != null) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw) {
|
||||
@Override
|
||||
public void println() {
|
||||
super.print("\r\n");
|
||||
}
|
||||
};
|
||||
pw.println();
|
||||
log.getThrown().printStackTrace(pw);
|
||||
pw.close();
|
||||
throwable = sw.toString();
|
||||
}
|
||||
Object[] params = log.getParameters();
|
||||
if (params != null) {
|
||||
if (params.length == 1) {
|
||||
return String.format(
|
||||
FORMATTER_FORMAT2,
|
||||
log.getInstant().toEpochMilli(),
|
||||
source,
|
||||
log.getLoggerName(),
|
||||
log.getLevel().getName(),
|
||||
message,
|
||||
throwable,
|
||||
params[0]);
|
||||
} else if (params.length == 2) {
|
||||
return String.format(
|
||||
FORMATTER_FORMAT3,
|
||||
log.getInstant().toEpochMilli(),
|
||||
source,
|
||||
log.getLoggerName(),
|
||||
log.getLevel().getName(),
|
||||
message,
|
||||
throwable,
|
||||
params[0],
|
||||
params[1]);
|
||||
}
|
||||
}
|
||||
return String.format(
|
||||
FORMATTER_FORMAT,
|
||||
log.getInstant().toEpochMilli(),
|
||||
source,
|
||||
log.getLoggerName(),
|
||||
log.getLevel().getName(),
|
||||
message,
|
||||
throwable);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void fillLogRecord(LogRecord log) {
|
||||
String traceid = null;
|
||||
if (traceEnable && Traces.enable()) {
|
||||
traceid = Traces.currentTraceid();
|
||||
if (traceid == null || traceid.isEmpty()) {
|
||||
traceid = "[TID:N/A] ";
|
||||
} else {
|
||||
traceid = "[TID:" + traceid + "] ";
|
||||
}
|
||||
}
|
||||
if (traceid == null) {
|
||||
log.setParameters(new String[] {Thread.currentThread().getName()});
|
||||
} else {
|
||||
log.setParameters(new String[] {Thread.currentThread().getName(), traceid});
|
||||
}
|
||||
}
|
||||
protected static void fillLogRecord(LogRecord log) {
|
||||
String traceid = null;
|
||||
if (traceEnable && Traces.enable()) {
|
||||
traceid = Traces.currentTraceid();
|
||||
if (traceid == null || traceid.isEmpty()) {
|
||||
traceid = "[TID:N/A] ";
|
||||
} else {
|
||||
traceid = "[TID:" + traceid + "] ";
|
||||
}
|
||||
}
|
||||
if (traceid == null) {
|
||||
log.setParameters(new String[] {Thread.currentThread().getName()});
|
||||
} else {
|
||||
log.setParameters(new String[] {Thread.currentThread().getName(), traceid});
|
||||
}
|
||||
}
|
||||
|
||||
public static void initDebugLogConfig() {
|
||||
try {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
final PrintStream ps = new PrintStream(out);
|
||||
final String handlerName =
|
||||
LoggingFileHandler.LoggingConsoleHandler.class.getName(); // java.util.logging.ConsoleHandler
|
||||
ps.println("handlers = " + handlerName);
|
||||
ps.println(".level = FINEST");
|
||||
ps.println("jdk.level = INFO");
|
||||
ps.println("sun.level = INFO");
|
||||
ps.println("javax.level = INFO");
|
||||
ps.println("com.sun.level = INFO");
|
||||
ps.println("io.level = INFO");
|
||||
ps.println("org.junit.level = INFO");
|
||||
ps.println(handlerName + ".level = FINEST");
|
||||
ps.println(handlerName + ".formatter = " + LoggingFormater.class.getName());
|
||||
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray()));
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
public static void initDebugLogConfig() {
|
||||
try {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
final PrintStream ps = new PrintStream(out);
|
||||
final String handlerName =
|
||||
LoggingFileHandler.LoggingConsoleHandler.class.getName(); // java.util.logging.ConsoleHandler
|
||||
ps.println("handlers = " + handlerName);
|
||||
ps.println(".level = FINEST");
|
||||
ps.println("jdk.level = INFO");
|
||||
ps.println("sun.level = INFO");
|
||||
ps.println("javax.level = INFO");
|
||||
ps.println("com.sun.level = INFO");
|
||||
ps.println("io.level = INFO");
|
||||
ps.println("org.junit.level = INFO");
|
||||
ps.println(handlerName + ".level = FINEST");
|
||||
ps.println(handlerName + ".formatter = " + LoggingFormater.class.getName());
|
||||
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray()));
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,378 +26,378 @@ import org.redkale.util.*;
|
||||
@SuppressWarnings("unchecked")
|
||||
public class LoggingFileHandler extends LoggingBaseHandler {
|
||||
|
||||
/** SNCP的日志输出Handler */
|
||||
public static class LoggingSncpFileHandler extends LoggingFileHandler {
|
||||
/** SNCP的日志输出Handler */
|
||||
public static class LoggingSncpFileHandler extends LoggingFileHandler {
|
||||
|
||||
@Override
|
||||
public String getPrefix() {
|
||||
return "sncp-";
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String getPrefix() {
|
||||
return "sncp-";
|
||||
}
|
||||
}
|
||||
|
||||
public static class LoggingConsoleHandler extends ConsoleHandler {
|
||||
public static class LoggingConsoleHandler extends ConsoleHandler {
|
||||
|
||||
private Pattern denyRegx;
|
||||
private Pattern denyRegx;
|
||||
|
||||
public LoggingConsoleHandler() {
|
||||
super();
|
||||
setFormatter(new LoggingFormater());
|
||||
configure();
|
||||
}
|
||||
public LoggingConsoleHandler() {
|
||||
super();
|
||||
setFormatter(new LoggingFormater());
|
||||
configure();
|
||||
}
|
||||
|
||||
private void configure() {
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
String denyregxstr = manager.getProperty(LoggingConsoleHandler.class.getName() + ".denyregx");
|
||||
if (denyregxstr == null) {
|
||||
denyregxstr = manager.getProperty("java.util.logging.ConsoleHandler.denyregx");
|
||||
}
|
||||
try {
|
||||
if (denyregxstr != null && !denyregxstr.trim().isEmpty()) {
|
||||
this.denyRegx = Pattern.compile(denyregxstr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
private void configure() {
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
String denyregxstr = manager.getProperty(LoggingConsoleHandler.class.getName() + ".denyregx");
|
||||
if (denyregxstr == null) {
|
||||
denyregxstr = manager.getProperty("java.util.logging.ConsoleHandler.denyregx");
|
||||
}
|
||||
try {
|
||||
if (denyregxstr != null && !denyregxstr.trim().isEmpty()) {
|
||||
this.denyRegx = Pattern.compile(denyregxstr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publish(LogRecord log) {
|
||||
if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) {
|
||||
return;
|
||||
}
|
||||
fillLogRecord(log);
|
||||
super.publish(log);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void publish(LogRecord log) {
|
||||
if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) {
|
||||
return;
|
||||
}
|
||||
fillLogRecord(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() {
|
||||
updateTomorrow();
|
||||
configure();
|
||||
open();
|
||||
}
|
||||
public LoggingFileHandler() {
|
||||
updateTomorrow();
|
||||
configure();
|
||||
open();
|
||||
}
|
||||
|
||||
private void updateTomorrow() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||
cal.set(Calendar.MINUTE, 0);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
cal.set(Calendar.MILLISECOND, 0);
|
||||
cal.add(Calendar.DAY_OF_YEAR, 1);
|
||||
long t = cal.getTimeInMillis();
|
||||
if (this.tomorrow != t) {
|
||||
logIndex.set(0);
|
||||
}
|
||||
this.tomorrow = t;
|
||||
}
|
||||
private void updateTomorrow() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||
cal.set(Calendar.MINUTE, 0);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
cal.set(Calendar.MILLISECOND, 0);
|
||||
cal.add(Calendar.DAY_OF_YEAR, 1);
|
||||
long t = cal.getTimeInMillis();
|
||||
if (this.tomorrow != t) {
|
||||
logIndex.set(0);
|
||||
}
|
||||
this.tomorrow = t;
|
||||
}
|
||||
|
||||
private void open() {
|
||||
final String name = "Redkale-Logging-" + getClass().getSimpleName().replace("Logging", "") + "-Thread";
|
||||
new Thread() {
|
||||
{
|
||||
setName(name);
|
||||
setDaemon(true);
|
||||
}
|
||||
private void open() {
|
||||
final String name = "Redkale-Logging-" + getClass().getSimpleName().replace("Logging", "") + "-Thread";
|
||||
new Thread() {
|
||||
{
|
||||
setName(name);
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
LogRecord log = logQueue.take();
|
||||
final boolean bigger = (limit > 0 && limit <= logLength.get());
|
||||
final boolean changeday = tomorrow <= log.getMillis();
|
||||
if (bigger || changeday) {
|
||||
updateTomorrow();
|
||||
if (logStream != null) {
|
||||
logStream.close();
|
||||
if (bigger) {
|
||||
for (int i = Math.min(count - 2, logIndex.get() - 1); i > 0; i--) {
|
||||
File greater = new File(logFile.getPath() + "." + i);
|
||||
if (greater.exists()) {
|
||||
Files.move(
|
||||
greater.toPath(),
|
||||
new File(logFile.getPath() + "." + (i + 1)).toPath(),
|
||||
REPLACE_EXISTING,
|
||||
ATOMIC_MOVE);
|
||||
}
|
||||
}
|
||||
Files.move(
|
||||
logFile.toPath(),
|
||||
new File(logFile.getPath() + ".1").toPath(),
|
||||
REPLACE_EXISTING,
|
||||
ATOMIC_MOVE);
|
||||
} else {
|
||||
if (logFile.exists() && logFile.length() < 1) {
|
||||
Files.delete(logFile.toPath());
|
||||
}
|
||||
}
|
||||
logStream = null;
|
||||
}
|
||||
}
|
||||
if (unusual != null && changeday && logUnusualStream != null) {
|
||||
logUnusualStream.close();
|
||||
if (limit > 0 && limit <= logUnusualLength.get()) {
|
||||
for (int i = Math.min(count - 2, logUnusualIndex.get() - 1); i > 0; i--) {
|
||||
File greater = new File(logUnusualFile.getPath() + "." + i);
|
||||
if (greater.exists()) {
|
||||
Files.move(
|
||||
greater.toPath(),
|
||||
new File(logUnusualFile.getPath() + "." + (i + 1)).toPath(),
|
||||
REPLACE_EXISTING,
|
||||
ATOMIC_MOVE);
|
||||
}
|
||||
}
|
||||
Files.move(
|
||||
logUnusualFile.toPath(),
|
||||
new File(logUnusualFile.getPath() + ".1").toPath(),
|
||||
REPLACE_EXISTING,
|
||||
ATOMIC_MOVE);
|
||||
} else {
|
||||
if (logUnusualFile.exists() && logUnusualFile.length() < 1) {
|
||||
Files.delete(logUnusualFile.toPath());
|
||||
}
|
||||
}
|
||||
logUnusualStream = null;
|
||||
}
|
||||
if (logStream == null) {
|
||||
logIndex.incrementAndGet();
|
||||
logFile = new File(
|
||||
patternDateFormat == null
|
||||
? pattern
|
||||
: Times.formatTime(patternDateFormat, -1, System.currentTimeMillis()));
|
||||
logFile.getParentFile().mkdirs();
|
||||
logLength.set(logFile.length());
|
||||
logStream = new FileOutputStream(logFile, append);
|
||||
}
|
||||
if (unusual != null && logUnusualStream == null) {
|
||||
logUnusualIndex.incrementAndGet();
|
||||
logUnusualFile = new File(
|
||||
unusualDateFormat == null
|
||||
? unusual
|
||||
: Times.formatTime(unusualDateFormat, -1, System.currentTimeMillis()));
|
||||
logUnusualFile.getParentFile().mkdirs();
|
||||
logUnusualLength.set(logUnusualFile.length());
|
||||
logUnusualStream = new FileOutputStream(logUnusualFile, append);
|
||||
}
|
||||
// ----------------------写日志-------------------------
|
||||
String message = getFormatter().format(log);
|
||||
String encoding = getEncoding();
|
||||
byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding);
|
||||
logStream.write(bytes);
|
||||
logLength.addAndGet(bytes.length);
|
||||
if (unusual != null && (log.getLevel() == Level.WARNING || log.getLevel() == Level.SEVERE)) {
|
||||
logUnusualStream.write(bytes);
|
||||
logUnusualLength.addAndGet(bytes.length);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorManager err = getErrorManager();
|
||||
if (err != null) {
|
||||
err.error(null, e, ErrorManager.WRITE_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
LogRecord log = logQueue.take();
|
||||
final boolean bigger = (limit > 0 && limit <= logLength.get());
|
||||
final boolean changeday = tomorrow <= log.getMillis();
|
||||
if (bigger || changeday) {
|
||||
updateTomorrow();
|
||||
if (logStream != null) {
|
||||
logStream.close();
|
||||
if (bigger) {
|
||||
for (int i = Math.min(count - 2, logIndex.get() - 1); i > 0; i--) {
|
||||
File greater = new File(logFile.getPath() + "." + i);
|
||||
if (greater.exists()) {
|
||||
Files.move(
|
||||
greater.toPath(),
|
||||
new File(logFile.getPath() + "." + (i + 1)).toPath(),
|
||||
REPLACE_EXISTING,
|
||||
ATOMIC_MOVE);
|
||||
}
|
||||
}
|
||||
Files.move(
|
||||
logFile.toPath(),
|
||||
new File(logFile.getPath() + ".1").toPath(),
|
||||
REPLACE_EXISTING,
|
||||
ATOMIC_MOVE);
|
||||
} else {
|
||||
if (logFile.exists() && logFile.length() < 1) {
|
||||
Files.delete(logFile.toPath());
|
||||
}
|
||||
}
|
||||
logStream = null;
|
||||
}
|
||||
}
|
||||
if (unusual != null && changeday && logUnusualStream != null) {
|
||||
logUnusualStream.close();
|
||||
if (limit > 0 && limit <= logUnusualLength.get()) {
|
||||
for (int i = Math.min(count - 2, logUnusualIndex.get() - 1); i > 0; i--) {
|
||||
File greater = new File(logUnusualFile.getPath() + "." + i);
|
||||
if (greater.exists()) {
|
||||
Files.move(
|
||||
greater.toPath(),
|
||||
new File(logUnusualFile.getPath() + "." + (i + 1)).toPath(),
|
||||
REPLACE_EXISTING,
|
||||
ATOMIC_MOVE);
|
||||
}
|
||||
}
|
||||
Files.move(
|
||||
logUnusualFile.toPath(),
|
||||
new File(logUnusualFile.getPath() + ".1").toPath(),
|
||||
REPLACE_EXISTING,
|
||||
ATOMIC_MOVE);
|
||||
} else {
|
||||
if (logUnusualFile.exists() && logUnusualFile.length() < 1) {
|
||||
Files.delete(logUnusualFile.toPath());
|
||||
}
|
||||
}
|
||||
logUnusualStream = null;
|
||||
}
|
||||
if (logStream == null) {
|
||||
logIndex.incrementAndGet();
|
||||
logFile = new File(
|
||||
patternDateFormat == null
|
||||
? pattern
|
||||
: Times.formatTime(patternDateFormat, -1, System.currentTimeMillis()));
|
||||
logFile.getParentFile().mkdirs();
|
||||
logLength.set(logFile.length());
|
||||
logStream = new FileOutputStream(logFile, append);
|
||||
}
|
||||
if (unusual != null && logUnusualStream == null) {
|
||||
logUnusualIndex.incrementAndGet();
|
||||
logUnusualFile = new File(
|
||||
unusualDateFormat == null
|
||||
? unusual
|
||||
: Times.formatTime(unusualDateFormat, -1, System.currentTimeMillis()));
|
||||
logUnusualFile.getParentFile().mkdirs();
|
||||
logUnusualLength.set(logUnusualFile.length());
|
||||
logUnusualStream = new FileOutputStream(logUnusualFile, append);
|
||||
}
|
||||
// ----------------------写日志-------------------------
|
||||
String message = getFormatter().format(log);
|
||||
String encoding = getEncoding();
|
||||
byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding);
|
||||
logStream.write(bytes);
|
||||
logLength.addAndGet(bytes.length);
|
||||
if (unusual != null && (log.getLevel() == Level.WARNING || log.getLevel() == Level.SEVERE)) {
|
||||
logUnusualStream.write(bytes);
|
||||
logUnusualLength.addAndGet(bytes.length);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorManager err = getErrorManager();
|
||||
if (err != null) {
|
||||
err.error(null, e, ErrorManager.WRITE_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return "";
|
||||
}
|
||||
public String getPrefix() {
|
||||
return "";
|
||||
}
|
||||
|
||||
private void configure() {
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
String cname = LoggingFileHandler.class.getName();
|
||||
this.pattern = manager.getProperty(cname + ".pattern");
|
||||
if (this.pattern == null) {
|
||||
this.pattern = "logs-%tm/" + getPrefix() + "log-%td.log";
|
||||
} else {
|
||||
int pos = this.pattern.lastIndexOf('/');
|
||||
if (pos > 0) {
|
||||
this.pattern = this.pattern.substring(0, pos + 1) + getPrefix() + this.pattern.substring(pos + 1);
|
||||
} else {
|
||||
this.pattern = getPrefix() + this.pattern;
|
||||
}
|
||||
}
|
||||
if (this.pattern != null && this.pattern.contains("%")) { // 需要时间格式化
|
||||
this.patternDateFormat = this.pattern;
|
||||
Times.formatTime(this.patternDateFormat, -1, System.currentTimeMillis()); // 测试时间格式是否正确
|
||||
}
|
||||
String unusualstr = manager.getProperty(cname + ".unusual");
|
||||
if (unusualstr != null) {
|
||||
int pos = unusualstr.lastIndexOf('/');
|
||||
if (pos > 0) {
|
||||
this.unusual = unusualstr.substring(0, pos + 1) + getPrefix() + unusualstr.substring(pos + 1);
|
||||
} else {
|
||||
this.unusual = getPrefix() + unusualstr;
|
||||
}
|
||||
}
|
||||
if (this.unusual != null && this.unusual.contains("%")) { // 需要时间格式化
|
||||
this.unusualDateFormat = this.unusual;
|
||||
Times.formatTime(this.unusualDateFormat, -1, System.currentTimeMillis()); // 测试时间格式是否正确
|
||||
}
|
||||
String limitstr = manager.getProperty(cname + ".limit");
|
||||
try {
|
||||
if (limitstr != null) {
|
||||
limitstr = limitstr.toUpperCase();
|
||||
boolean g = limitstr.indexOf('G') > 0;
|
||||
boolean m = limitstr.indexOf('M') > 0;
|
||||
boolean k = limitstr.indexOf('K') > 0;
|
||||
int ls = Math.abs(Integer.decode(limitstr.replace("G", "")
|
||||
.replace("M", "")
|
||||
.replace("K", "")
|
||||
.replace("B", "")));
|
||||
if (g) {
|
||||
ls *= 1024 * 1024 * 1024;
|
||||
} else if (m) {
|
||||
ls *= 1024 * 1024;
|
||||
} else if (k) {
|
||||
ls *= 1024;
|
||||
}
|
||||
this.limit = ls;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String countstr = manager.getProperty(cname + ".count");
|
||||
try {
|
||||
if (countstr != null) {
|
||||
this.count = Math.max(1, Math.abs(Integer.decode(countstr)));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String appendstr = manager.getProperty(cname + ".append");
|
||||
try {
|
||||
if (appendstr != null) {
|
||||
this.append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String levelstr = manager.getProperty(cname + ".level");
|
||||
try {
|
||||
if (levelstr != null) {
|
||||
Level l = Level.parse(levelstr);
|
||||
setLevel(l != null ? l : Level.ALL);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String filterstr = manager.getProperty(cname + ".filter");
|
||||
try {
|
||||
if (filterstr != null) {
|
||||
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterstr);
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
|
||||
setFilter((Filter) clz.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String formatterstr = manager.getProperty(cname + ".formatter");
|
||||
try {
|
||||
if (formatterstr != null) {
|
||||
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr);
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
|
||||
setFormatter((Formatter) clz.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
if (getFormatter() == null) {
|
||||
setFormatter(new SimpleFormatter());
|
||||
}
|
||||
private void configure() {
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
String cname = LoggingFileHandler.class.getName();
|
||||
this.pattern = manager.getProperty(cname + ".pattern");
|
||||
if (this.pattern == null) {
|
||||
this.pattern = "logs-%tm/" + getPrefix() + "log-%td.log";
|
||||
} else {
|
||||
int pos = this.pattern.lastIndexOf('/');
|
||||
if (pos > 0) {
|
||||
this.pattern = this.pattern.substring(0, pos + 1) + getPrefix() + this.pattern.substring(pos + 1);
|
||||
} else {
|
||||
this.pattern = getPrefix() + this.pattern;
|
||||
}
|
||||
}
|
||||
if (this.pattern != null && this.pattern.contains("%")) { // 需要时间格式化
|
||||
this.patternDateFormat = this.pattern;
|
||||
Times.formatTime(this.patternDateFormat, -1, System.currentTimeMillis()); // 测试时间格式是否正确
|
||||
}
|
||||
String unusualstr = manager.getProperty(cname + ".unusual");
|
||||
if (unusualstr != null) {
|
||||
int pos = unusualstr.lastIndexOf('/');
|
||||
if (pos > 0) {
|
||||
this.unusual = unusualstr.substring(0, pos + 1) + getPrefix() + unusualstr.substring(pos + 1);
|
||||
} else {
|
||||
this.unusual = getPrefix() + unusualstr;
|
||||
}
|
||||
}
|
||||
if (this.unusual != null && this.unusual.contains("%")) { // 需要时间格式化
|
||||
this.unusualDateFormat = this.unusual;
|
||||
Times.formatTime(this.unusualDateFormat, -1, System.currentTimeMillis()); // 测试时间格式是否正确
|
||||
}
|
||||
String limitstr = manager.getProperty(cname + ".limit");
|
||||
try {
|
||||
if (limitstr != null) {
|
||||
limitstr = limitstr.toUpperCase();
|
||||
boolean g = limitstr.indexOf('G') > 0;
|
||||
boolean m = limitstr.indexOf('M') > 0;
|
||||
boolean k = limitstr.indexOf('K') > 0;
|
||||
int ls = Math.abs(Integer.decode(limitstr.replace("G", "")
|
||||
.replace("M", "")
|
||||
.replace("K", "")
|
||||
.replace("B", "")));
|
||||
if (g) {
|
||||
ls *= 1024 * 1024 * 1024;
|
||||
} else if (m) {
|
||||
ls *= 1024 * 1024;
|
||||
} else if (k) {
|
||||
ls *= 1024;
|
||||
}
|
||||
this.limit = ls;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String countstr = manager.getProperty(cname + ".count");
|
||||
try {
|
||||
if (countstr != null) {
|
||||
this.count = Math.max(1, Math.abs(Integer.decode(countstr)));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String appendstr = manager.getProperty(cname + ".append");
|
||||
try {
|
||||
if (appendstr != null) {
|
||||
this.append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String levelstr = manager.getProperty(cname + ".level");
|
||||
try {
|
||||
if (levelstr != null) {
|
||||
Level l = Level.parse(levelstr);
|
||||
setLevel(l != null ? l : Level.ALL);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String filterstr = manager.getProperty(cname + ".filter");
|
||||
try {
|
||||
if (filterstr != null) {
|
||||
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterstr);
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
|
||||
setFilter((Filter) clz.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String formatterstr = manager.getProperty(cname + ".formatter");
|
||||
try {
|
||||
if (formatterstr != null) {
|
||||
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr);
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
|
||||
setFormatter((Formatter) clz.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
if (getFormatter() == null) {
|
||||
setFormatter(new SimpleFormatter());
|
||||
}
|
||||
|
||||
String encodingstr = manager.getProperty(cname + ".encoding");
|
||||
try {
|
||||
if (encodingstr != null) {
|
||||
setEncoding(encodingstr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String encodingstr = manager.getProperty(cname + ".encoding");
|
||||
try {
|
||||
if (encodingstr != null) {
|
||||
setEncoding(encodingstr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
String denyregxstr = manager.getProperty(cname + ".denyregx");
|
||||
try {
|
||||
if (denyregxstr != null && !denyregxstr.trim().isEmpty()) {
|
||||
denyRegx = Pattern.compile(denyregxstr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
String denyregxstr = manager.getProperty(cname + ".denyregx");
|
||||
try {
|
||||
if (denyregxstr != null && !denyregxstr.trim().isEmpty()) {
|
||||
denyRegx = Pattern.compile(denyregxstr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publish(LogRecord log) {
|
||||
if (!isLoggable(log)) {
|
||||
return;
|
||||
}
|
||||
if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) {
|
||||
return;
|
||||
}
|
||||
fillLogRecord(log);
|
||||
logQueue.offer(log);
|
||||
}
|
||||
@Override
|
||||
public void publish(LogRecord log) {
|
||||
if (!isLoggable(log)) {
|
||||
return;
|
||||
}
|
||||
if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) {
|
||||
return;
|
||||
}
|
||||
fillLogRecord(log);
|
||||
logQueue.offer(log);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
try {
|
||||
if (logStream != null) {
|
||||
logStream.flush();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorManager err = getErrorManager();
|
||||
if (err != null) {
|
||||
err.error(null, e, ErrorManager.FLUSH_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void flush() {
|
||||
try {
|
||||
if (logStream != null) {
|
||||
logStream.flush();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorManager err = getErrorManager();
|
||||
if (err != null) {
|
||||
err.error(null, e, ErrorManager.FLUSH_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws SecurityException {
|
||||
try {
|
||||
if (logStream != null) {
|
||||
logStream.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorManager err = getErrorManager();
|
||||
if (err != null) {
|
||||
err.error(null, e, ErrorManager.CLOSE_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void close() throws SecurityException {
|
||||
try {
|
||||
if (logStream != null) {
|
||||
logStream.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorManager err = getErrorManager();
|
||||
if (err != null) {
|
||||
err.error(null, e, ErrorManager.CLOSE_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,162 +31,162 @@ import org.redkale.util.Environment;
|
||||
*/
|
||||
class LoggingModule extends BootModule {
|
||||
|
||||
// 日志配置资源
|
||||
private final Properties loggingProperties = new Properties();
|
||||
// 日志配置资源
|
||||
private final Properties loggingProperties = new Properties();
|
||||
|
||||
LoggingModule(Application application) {
|
||||
super(application);
|
||||
}
|
||||
LoggingModule(Application application) {
|
||||
super(application);
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置变更
|
||||
*
|
||||
* @param events 变更项
|
||||
*/
|
||||
public void onEnvironmentUpdated(List<ResourceEvent> events) {
|
||||
Set<String> loggingRemovedKeys = new HashSet<>();
|
||||
Properties loggingChangedProps = new Properties();
|
||||
for (ResourceEvent event : events) {
|
||||
if (event.newValue() == null) {
|
||||
if (loggingProperties.containsKey(event.name())) {
|
||||
loggingRemovedKeys.add(event.name());
|
||||
}
|
||||
} else {
|
||||
loggingChangedProps.put(event.name(), event.newValue());
|
||||
}
|
||||
}
|
||||
if (!loggingRemovedKeys.isEmpty() || !loggingChangedProps.isEmpty()) {
|
||||
Properties newProps = new Properties(this.loggingProperties);
|
||||
loggingRemovedKeys.forEach(newProps::remove);
|
||||
newProps.putAll(loggingChangedProps);
|
||||
reconfigLogging(false, newProps);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 配置变更
|
||||
*
|
||||
* @param events 变更项
|
||||
*/
|
||||
public void onEnvironmentUpdated(List<ResourceEvent> events) {
|
||||
Set<String> loggingRemovedKeys = new HashSet<>();
|
||||
Properties loggingChangedProps = new Properties();
|
||||
for (ResourceEvent event : events) {
|
||||
if (event.newValue() == null) {
|
||||
if (loggingProperties.containsKey(event.name())) {
|
||||
loggingRemovedKeys.add(event.name());
|
||||
}
|
||||
} else {
|
||||
loggingChangedProps.put(event.name(), event.newValue());
|
||||
}
|
||||
}
|
||||
if (!loggingRemovedKeys.isEmpty() || !loggingChangedProps.isEmpty()) {
|
||||
Properties newProps = new Properties(this.loggingProperties);
|
||||
loggingRemovedKeys.forEach(newProps::remove);
|
||||
newProps.putAll(loggingChangedProps);
|
||||
reconfigLogging(false, newProps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置日志策略
|
||||
*
|
||||
* @param first 是否首次设置
|
||||
* @param allProps 配置项全量
|
||||
*/
|
||||
public void reconfigLogging(boolean first, Properties allProps) {
|
||||
String searchRawHandler = "java.util.logging.SearchHandler";
|
||||
String searchReadHandler = LoggingSearchHandler.class.getName();
|
||||
Properties onlyLogProps = new Properties();
|
||||
Environment envs = this.environment;
|
||||
allProps.entrySet().forEach(x -> {
|
||||
String key = x.getKey().toString();
|
||||
if (key.startsWith("java.util.logging.") || key.contains(".level") || key.equals("handlers")) {
|
||||
String val = envs.getPropertyValue(x.getValue()
|
||||
.toString()
|
||||
.replace("%m", "%tY%tm")
|
||||
.replace("%d", "%tY%tm%td") // 兼容旧时间格式
|
||||
.replace(searchRawHandler, searchReadHandler));
|
||||
onlyLogProps.put(key.replace(searchRawHandler, searchReadHandler), val);
|
||||
}
|
||||
});
|
||||
if (onlyLogProps.getProperty("java.util.logging.FileHandler.formatter") == null) {
|
||||
if (application.isCompileMode()) {
|
||||
onlyLogProps.setProperty("java.util.logging.FileHandler.formatter", SimpleFormatter.class.getName());
|
||||
if (onlyLogProps.getProperty("java.util.logging.SimpleFormatter.format") == null) {
|
||||
onlyLogProps.setProperty(
|
||||
"java.util.logging.SimpleFormatter.format",
|
||||
LoggingFileHandler.FORMATTER_FORMAT.replaceAll("\r\n", "%n"));
|
||||
}
|
||||
} else {
|
||||
onlyLogProps.setProperty(
|
||||
"java.util.logging.FileHandler.formatter", LoggingFileHandler.LoggingFormater.class.getName());
|
||||
}
|
||||
}
|
||||
if (onlyLogProps.getProperty("java.util.logging.ConsoleHandler.formatter") == null) {
|
||||
if (application.isCompileMode()) {
|
||||
onlyLogProps.setProperty("java.util.logging.ConsoleHandler.formatter", SimpleFormatter.class.getName());
|
||||
if (onlyLogProps.getProperty("java.util.logging.SimpleFormatter.format") == null) {
|
||||
onlyLogProps.setProperty(
|
||||
"java.util.logging.SimpleFormatter.format",
|
||||
LoggingFileHandler.FORMATTER_FORMAT.replaceAll("\r\n", "%n"));
|
||||
}
|
||||
} else {
|
||||
onlyLogProps.setProperty(
|
||||
"java.util.logging.ConsoleHandler.formatter",
|
||||
LoggingFileHandler.LoggingFormater.class.getName());
|
||||
}
|
||||
}
|
||||
if (!application.isCompileMode()) { // ConsoleHandler替换成LoggingConsoleHandler
|
||||
final String handlers = onlyLogProps.getProperty("handlers");
|
||||
if (handlers != null && handlers.contains("java.util.logging.ConsoleHandler")) {
|
||||
final String consoleHandlerClass = LoggingFileHandler.LoggingConsoleHandler.class.getName();
|
||||
onlyLogProps.setProperty(
|
||||
"handlers", handlers.replace("java.util.logging.ConsoleHandler", consoleHandlerClass));
|
||||
Properties prop = new Properties();
|
||||
String prefix = consoleHandlerClass + ".";
|
||||
onlyLogProps.entrySet().forEach(x -> {
|
||||
if (x.getKey().toString().startsWith("java.util.logging.ConsoleHandler.")) {
|
||||
prop.put(
|
||||
x.getKey().toString().replace("java.util.logging.ConsoleHandler.", prefix),
|
||||
x.getValue());
|
||||
}
|
||||
});
|
||||
prop.entrySet().forEach(x -> {
|
||||
onlyLogProps.put(x.getKey(), x.getValue());
|
||||
});
|
||||
}
|
||||
}
|
||||
String fileHandlerPattern = onlyLogProps.getProperty("java.util.logging.FileHandler.pattern");
|
||||
if (fileHandlerPattern != null && fileHandlerPattern.contains("%")) { // 带日期格式
|
||||
final String fileHandlerClass = LoggingFileHandler.class.getName();
|
||||
Properties prop = new Properties();
|
||||
final String handlers = onlyLogProps.getProperty("handlers");
|
||||
if (handlers != null && handlers.contains("java.util.logging.FileHandler")) {
|
||||
// singletonrun模式下不输出文件日志
|
||||
prop.setProperty(
|
||||
"handlers",
|
||||
handlers.replace(
|
||||
"java.util.logging.FileHandler",
|
||||
application.isSingletonMode() || application.isCompileMode() ? "" : fileHandlerClass));
|
||||
}
|
||||
if (!prop.isEmpty()) {
|
||||
String prefix = fileHandlerClass + ".";
|
||||
onlyLogProps.entrySet().forEach(x -> {
|
||||
if (x.getKey().toString().startsWith("java.util.logging.FileHandler.")) {
|
||||
prop.put(x.getKey().toString().replace("java.util.logging.FileHandler.", prefix), x.getValue());
|
||||
}
|
||||
});
|
||||
prop.entrySet().forEach(x -> onlyLogProps.put(x.getKey(), x.getValue()));
|
||||
}
|
||||
if (!application.isCompileMode()) {
|
||||
onlyLogProps.put(
|
||||
SncpClient.class.getSimpleName() + ".handlers",
|
||||
LoggingFileHandler.LoggingSncpFileHandler.class.getName());
|
||||
}
|
||||
}
|
||||
if (application.isCompileMode()) {
|
||||
onlyLogProps.put("handlers", "java.util.logging.ConsoleHandler");
|
||||
Map newprop = new HashMap(onlyLogProps);
|
||||
newprop.forEach((k, v) -> {
|
||||
if (k.toString().startsWith("java.util.logging.FileHandler.")) {
|
||||
onlyLogProps.remove(k);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 设置日志策略
|
||||
*
|
||||
* @param first 是否首次设置
|
||||
* @param allProps 配置项全量
|
||||
*/
|
||||
public void reconfigLogging(boolean first, Properties allProps) {
|
||||
String searchRawHandler = "java.util.logging.SearchHandler";
|
||||
String searchReadHandler = LoggingSearchHandler.class.getName();
|
||||
Properties onlyLogProps = new Properties();
|
||||
Environment envs = this.environment;
|
||||
allProps.entrySet().forEach(x -> {
|
||||
String key = x.getKey().toString();
|
||||
if (key.startsWith("java.util.logging.") || key.contains(".level") || key.equals("handlers")) {
|
||||
String val = envs.getPropertyValue(x.getValue()
|
||||
.toString()
|
||||
.replace("%m", "%tY%tm")
|
||||
.replace("%d", "%tY%tm%td") // 兼容旧时间格式
|
||||
.replace(searchRawHandler, searchReadHandler));
|
||||
onlyLogProps.put(key.replace(searchRawHandler, searchReadHandler), val);
|
||||
}
|
||||
});
|
||||
if (onlyLogProps.getProperty("java.util.logging.FileHandler.formatter") == null) {
|
||||
if (application.isCompileMode()) {
|
||||
onlyLogProps.setProperty("java.util.logging.FileHandler.formatter", SimpleFormatter.class.getName());
|
||||
if (onlyLogProps.getProperty("java.util.logging.SimpleFormatter.format") == null) {
|
||||
onlyLogProps.setProperty(
|
||||
"java.util.logging.SimpleFormatter.format",
|
||||
LoggingFileHandler.FORMATTER_FORMAT.replaceAll("\r\n", "%n"));
|
||||
}
|
||||
} else {
|
||||
onlyLogProps.setProperty(
|
||||
"java.util.logging.FileHandler.formatter", LoggingFileHandler.LoggingFormater.class.getName());
|
||||
}
|
||||
}
|
||||
if (onlyLogProps.getProperty("java.util.logging.ConsoleHandler.formatter") == null) {
|
||||
if (application.isCompileMode()) {
|
||||
onlyLogProps.setProperty("java.util.logging.ConsoleHandler.formatter", SimpleFormatter.class.getName());
|
||||
if (onlyLogProps.getProperty("java.util.logging.SimpleFormatter.format") == null) {
|
||||
onlyLogProps.setProperty(
|
||||
"java.util.logging.SimpleFormatter.format",
|
||||
LoggingFileHandler.FORMATTER_FORMAT.replaceAll("\r\n", "%n"));
|
||||
}
|
||||
} else {
|
||||
onlyLogProps.setProperty(
|
||||
"java.util.logging.ConsoleHandler.formatter",
|
||||
LoggingFileHandler.LoggingFormater.class.getName());
|
||||
}
|
||||
}
|
||||
if (!application.isCompileMode()) { // ConsoleHandler替换成LoggingConsoleHandler
|
||||
final String handlers = onlyLogProps.getProperty("handlers");
|
||||
if (handlers != null && handlers.contains("java.util.logging.ConsoleHandler")) {
|
||||
final String consoleHandlerClass = LoggingFileHandler.LoggingConsoleHandler.class.getName();
|
||||
onlyLogProps.setProperty(
|
||||
"handlers", handlers.replace("java.util.logging.ConsoleHandler", consoleHandlerClass));
|
||||
Properties prop = new Properties();
|
||||
String prefix = consoleHandlerClass + ".";
|
||||
onlyLogProps.entrySet().forEach(x -> {
|
||||
if (x.getKey().toString().startsWith("java.util.logging.ConsoleHandler.")) {
|
||||
prop.put(
|
||||
x.getKey().toString().replace("java.util.logging.ConsoleHandler.", prefix),
|
||||
x.getValue());
|
||||
}
|
||||
});
|
||||
prop.entrySet().forEach(x -> {
|
||||
onlyLogProps.put(x.getKey(), x.getValue());
|
||||
});
|
||||
}
|
||||
}
|
||||
String fileHandlerPattern = onlyLogProps.getProperty("java.util.logging.FileHandler.pattern");
|
||||
if (fileHandlerPattern != null && fileHandlerPattern.contains("%")) { // 带日期格式
|
||||
final String fileHandlerClass = LoggingFileHandler.class.getName();
|
||||
Properties prop = new Properties();
|
||||
final String handlers = onlyLogProps.getProperty("handlers");
|
||||
if (handlers != null && handlers.contains("java.util.logging.FileHandler")) {
|
||||
// singletonrun模式下不输出文件日志
|
||||
prop.setProperty(
|
||||
"handlers",
|
||||
handlers.replace(
|
||||
"java.util.logging.FileHandler",
|
||||
application.isSingletonMode() || application.isCompileMode() ? "" : fileHandlerClass));
|
||||
}
|
||||
if (!prop.isEmpty()) {
|
||||
String prefix = fileHandlerClass + ".";
|
||||
onlyLogProps.entrySet().forEach(x -> {
|
||||
if (x.getKey().toString().startsWith("java.util.logging.FileHandler.")) {
|
||||
prop.put(x.getKey().toString().replace("java.util.logging.FileHandler.", prefix), x.getValue());
|
||||
}
|
||||
});
|
||||
prop.entrySet().forEach(x -> onlyLogProps.put(x.getKey(), x.getValue()));
|
||||
}
|
||||
if (!application.isCompileMode()) {
|
||||
onlyLogProps.put(
|
||||
SncpClient.class.getSimpleName() + ".handlers",
|
||||
LoggingFileHandler.LoggingSncpFileHandler.class.getName());
|
||||
}
|
||||
}
|
||||
if (application.isCompileMode()) {
|
||||
onlyLogProps.put("handlers", "java.util.logging.ConsoleHandler");
|
||||
Map newprop = new HashMap(onlyLogProps);
|
||||
newprop.forEach((k, v) -> {
|
||||
if (k.toString().startsWith("java.util.logging.FileHandler.")) {
|
||||
onlyLogProps.remove(k);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
final PrintStream ps = new PrintStream(out);
|
||||
onlyLogProps.forEach((x, y) -> ps.println(x + "=" + y));
|
||||
try {
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
manager.readConfiguration(new ByteArrayInputStream(out.toByteArray()));
|
||||
this.loggingProperties.clear();
|
||||
this.loggingProperties.putAll(onlyLogProps);
|
||||
Enumeration<String> en = manager.getLoggerNames();
|
||||
while (en.hasMoreElements()) {
|
||||
for (Handler handler : manager.getLogger(en.nextElement()).getHandlers()) {
|
||||
if (handler instanceof LoggingSearchHandler) {
|
||||
((LoggingSearchHandler) handler).application = application;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) { // 不会发生
|
||||
}
|
||||
}
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
final PrintStream ps = new PrintStream(out);
|
||||
onlyLogProps.forEach((x, y) -> ps.println(x + "=" + y));
|
||||
try {
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
manager.readConfiguration(new ByteArrayInputStream(out.toByteArray()));
|
||||
this.loggingProperties.clear();
|
||||
this.loggingProperties.putAll(onlyLogProps);
|
||||
Enumeration<String> en = manager.getLoggerNames();
|
||||
while (en.hasMoreElements()) {
|
||||
for (Handler handler : manager.getLogger(en.nextElement()).getHandlers()) {
|
||||
if (handler instanceof LoggingSearchHandler) {
|
||||
((LoggingSearchHandler) handler).application = application;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) { // 不会发生
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,325 +29,325 @@ import org.redkale.util.*;
|
||||
*/
|
||||
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
|
||||
protected Application application;
|
||||
// 在LogManager.getLogManager().readConfiguration执行完后,通过反射注入Application
|
||||
protected Application application;
|
||||
|
||||
public LoggingSearchHandler() {
|
||||
configure();
|
||||
open();
|
||||
}
|
||||
public LoggingSearchHandler() {
|
||||
configure();
|
||||
open();
|
||||
}
|
||||
|
||||
private void open() {
|
||||
final String name = "Redkale-Logging-" + getClass().getSimpleName().replace("Logging", "") + "-Thread";
|
||||
final int batchSize = 100; // 批量最多100条
|
||||
final List<SearchLogRecord> logList = new ArrayList<>();
|
||||
final Formatter formatter = new LoggingBaseHandler.LoggingFormater();
|
||||
final PrintStream outStream = System.out;
|
||||
new Thread() {
|
||||
{
|
||||
setName(name);
|
||||
setDaemon(true);
|
||||
}
|
||||
private void open() {
|
||||
final String name = "Redkale-Logging-" + getClass().getSimpleName().replace("Logging", "") + "-Thread";
|
||||
final int batchSize = 100; // 批量最多100条
|
||||
final List<SearchLogRecord> logList = new ArrayList<>();
|
||||
final Formatter formatter = new LoggingBaseHandler.LoggingFormater();
|
||||
final PrintStream outStream = System.out;
|
||||
new Thread() {
|
||||
{
|
||||
setName(name);
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
SearchLogRecord log = logqueue.take();
|
||||
while (source == null && retryCount.get() > 0) initSource();
|
||||
// ----------------------写日志-------------------------
|
||||
if (source == null) { // source加载失败
|
||||
outStream.print(formatter.format(log.rawLog));
|
||||
} else {
|
||||
logList.add(log);
|
||||
int size = batchSize;
|
||||
while (--size > 0) {
|
||||
log = logqueue.poll();
|
||||
if (log == null) {
|
||||
break;
|
||||
}
|
||||
logList.add(log);
|
||||
}
|
||||
source.insert(logList);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorManager err = getErrorManager();
|
||||
if (err != null) {
|
||||
err.error(null, e, ErrorManager.WRITE_FAILURE);
|
||||
}
|
||||
} finally {
|
||||
logList.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
SearchLogRecord log = logqueue.take();
|
||||
while (source == null && retryCount.get() > 0) initSource();
|
||||
// ----------------------写日志-------------------------
|
||||
if (source == null) { // source加载失败
|
||||
outStream.print(formatter.format(log.rawLog));
|
||||
} else {
|
||||
logList.add(log);
|
||||
int size = batchSize;
|
||||
while (--size > 0) {
|
||||
log = logqueue.poll();
|
||||
if (log == null) {
|
||||
break;
|
||||
}
|
||||
logList.add(log);
|
||||
}
|
||||
source.insert(logList);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorManager err = getErrorManager();
|
||||
if (err != null) {
|
||||
err.error(null, e, ErrorManager.WRITE_FAILURE);
|
||||
}
|
||||
} finally {
|
||||
logList.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
private void initSource() {
|
||||
if (retryCount.get() < 1) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Utility.sleep(3000); // 如果SearchSource自身在打印日志,需要停顿一点时间让SearchSource初始化完成
|
||||
if (application == null) {
|
||||
Utility.sleep(3000);
|
||||
}
|
||||
if (application == null) {
|
||||
return;
|
||||
}
|
||||
this.source = application.getResourceFactory().find(sourceResourceName, SearchSource.class);
|
||||
if (retryCount.get() == 1 && this.source == null) {
|
||||
System.err.println("ERROR: not load logging.source(" + sourceResourceName + ")");
|
||||
}
|
||||
} catch (Exception t) {
|
||||
ErrorManager err = getErrorManager();
|
||||
if (err != null) {
|
||||
err.error(null, t, ErrorManager.WRITE_FAILURE);
|
||||
}
|
||||
} finally {
|
||||
retryCount.decrementAndGet();
|
||||
}
|
||||
}
|
||||
private void initSource() {
|
||||
if (retryCount.get() < 1) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Utility.sleep(3000); // 如果SearchSource自身在打印日志,需要停顿一点时间让SearchSource初始化完成
|
||||
if (application == null) {
|
||||
Utility.sleep(3000);
|
||||
}
|
||||
if (application == null) {
|
||||
return;
|
||||
}
|
||||
this.source = application.getResourceFactory().find(sourceResourceName, SearchSource.class);
|
||||
if (retryCount.get() == 1 && this.source == null) {
|
||||
System.err.println("ERROR: not load logging.source(" + sourceResourceName + ")");
|
||||
}
|
||||
} catch (Exception t) {
|
||||
ErrorManager err = getErrorManager();
|
||||
if (err != null) {
|
||||
err.error(null, t, ErrorManager.WRITE_FAILURE);
|
||||
}
|
||||
} finally {
|
||||
retryCount.decrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkTagName(String name) { // 只能是字母、数字、短横、点、%、$和下划线
|
||||
if (name.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (char ch : name.toCharArray()) {
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
continue;
|
||||
}
|
||||
if (ch >= 'a' && ch <= 'z') {
|
||||
continue;
|
||||
}
|
||||
if (ch >= 'A' && ch <= 'Z') {
|
||||
continue;
|
||||
}
|
||||
if (ch == '_' || ch == '-' || ch == '%' || ch == '$' || ch == '.') {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private static boolean checkTagName(String name) { // 只能是字母、数字、短横、点、%、$和下划线
|
||||
if (name.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (char ch : name.toCharArray()) {
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
continue;
|
||||
}
|
||||
if (ch >= 'a' && ch <= 'z') {
|
||||
continue;
|
||||
}
|
||||
if (ch >= 'A' && ch <= 'Z') {
|
||||
continue;
|
||||
}
|
||||
if (ch == '_' || ch == '-' || ch == '%' || ch == '$' || ch == '.') {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void configure() {
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
String cname = getClass().getName();
|
||||
this.sourceResourceName = manager.getProperty(cname + ".source");
|
||||
if (this.sourceResourceName == null || this.sourceResourceName.isEmpty()) {
|
||||
throw new RedkaleException("not found logging.property " + cname + ".source");
|
||||
}
|
||||
String tagStr = manager.getProperty(cname + ".tag");
|
||||
if (tagStr != null && !tagStr.isEmpty()) {
|
||||
if (!checkTagName(tagStr.replaceAll("\\$\\{.+\\}", ""))) {
|
||||
throw new RedkaleException("found illegal logging.property " + cname + ".tag = " + tagStr);
|
||||
}
|
||||
this.tag = tagStr.replace("${" + RESNAME_APP_NAME + "}", System.getProperty(SYSNAME_APP_NAME, ""));
|
||||
if (this.tag.contains("%")) {
|
||||
this.tagDateFormat = this.tag;
|
||||
Times.formatTime(this.tagDateFormat, -1, System.currentTimeMillis()); // 测试时间格式是否正确
|
||||
}
|
||||
}
|
||||
private void configure() {
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
String cname = getClass().getName();
|
||||
this.sourceResourceName = manager.getProperty(cname + ".source");
|
||||
if (this.sourceResourceName == null || this.sourceResourceName.isEmpty()) {
|
||||
throw new RedkaleException("not found logging.property " + cname + ".source");
|
||||
}
|
||||
String tagStr = manager.getProperty(cname + ".tag");
|
||||
if (tagStr != null && !tagStr.isEmpty()) {
|
||||
if (!checkTagName(tagStr.replaceAll("\\$\\{.+\\}", ""))) {
|
||||
throw new RedkaleException("found illegal logging.property " + cname + ".tag = " + tagStr);
|
||||
}
|
||||
this.tag = tagStr.replace("${" + RESNAME_APP_NAME + "}", System.getProperty(SYSNAME_APP_NAME, ""));
|
||||
if (this.tag.contains("%")) {
|
||||
this.tagDateFormat = this.tag;
|
||||
Times.formatTime(this.tagDateFormat, -1, System.currentTimeMillis()); // 测试时间格式是否正确
|
||||
}
|
||||
}
|
||||
|
||||
String levelStr = manager.getProperty(cname + ".level");
|
||||
try {
|
||||
if (levelStr != null) {
|
||||
Level l = Level.parse(levelStr);
|
||||
setLevel(l != null ? l : Level.ALL);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String filterStr = manager.getProperty(cname + ".filter");
|
||||
try {
|
||||
if (filterStr != null) {
|
||||
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterStr);
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
|
||||
setFilter((Filter) clz.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String formatterStr = manager.getProperty(cname + ".formatter");
|
||||
try {
|
||||
if (formatterStr != null) {
|
||||
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterStr);
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
|
||||
setFormatter((Formatter) clz.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
if (getFormatter() == null) {
|
||||
setFormatter(new SimpleFormatter());
|
||||
}
|
||||
String levelStr = manager.getProperty(cname + ".level");
|
||||
try {
|
||||
if (levelStr != null) {
|
||||
Level l = Level.parse(levelStr);
|
||||
setLevel(l != null ? l : Level.ALL);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String filterStr = manager.getProperty(cname + ".filter");
|
||||
try {
|
||||
if (filterStr != null) {
|
||||
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterStr);
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
|
||||
setFilter((Filter) clz.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String formatterStr = manager.getProperty(cname + ".formatter");
|
||||
try {
|
||||
if (formatterStr != null) {
|
||||
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterStr);
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
|
||||
setFormatter((Formatter) clz.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
if (getFormatter() == null) {
|
||||
setFormatter(new SimpleFormatter());
|
||||
}
|
||||
|
||||
String encodingStr = manager.getProperty(cname + ".encoding");
|
||||
try {
|
||||
if (encodingStr != null) {
|
||||
setEncoding(encodingStr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
String encodingStr = manager.getProperty(cname + ".encoding");
|
||||
try {
|
||||
if (encodingStr != null) {
|
||||
setEncoding(encodingStr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
String denyRegxStr = manager.getProperty(cname + ".denyregx");
|
||||
try {
|
||||
if (denyRegxStr != null && !denyRegxStr.trim().isEmpty()) {
|
||||
denyRegx = Pattern.compile(denyRegxStr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
String denyRegxStr = manager.getProperty(cname + ".denyregx");
|
||||
try {
|
||||
if (denyRegxStr != null && !denyRegxStr.trim().isEmpty()) {
|
||||
denyRegx = Pattern.compile(denyRegxStr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publish(LogRecord log) {
|
||||
if (!isLoggable(log)) {
|
||||
return;
|
||||
}
|
||||
if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) {
|
||||
return;
|
||||
}
|
||||
if (log.getSourceClassName() != null) {
|
||||
StackTraceElement[] ses = new Throwable().getStackTrace();
|
||||
for (int i = 2; i < ses.length; i++) {
|
||||
if (ses[i].getClassName().startsWith("java.util.logging")) {
|
||||
continue;
|
||||
}
|
||||
log.setSourceClassName(ses[i].getClassName());
|
||||
log.setSourceMethodName(ses[i].getMethodName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
String rawTag = tagDateFormat == null
|
||||
? tag
|
||||
: Times.formatTime(tagDateFormat, -1, log.getInstant().toEpochMilli());
|
||||
fillLogRecord(log);
|
||||
logqueue.offer(new SearchLogRecord(rawTag, log));
|
||||
}
|
||||
@Override
|
||||
public void publish(LogRecord log) {
|
||||
if (!isLoggable(log)) {
|
||||
return;
|
||||
}
|
||||
if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) {
|
||||
return;
|
||||
}
|
||||
if (log.getSourceClassName() != null) {
|
||||
StackTraceElement[] ses = new Throwable().getStackTrace();
|
||||
for (int i = 2; i < ses.length; i++) {
|
||||
if (ses[i].getClassName().startsWith("java.util.logging")) {
|
||||
continue;
|
||||
}
|
||||
log.setSourceClassName(ses[i].getClassName());
|
||||
log.setSourceMethodName(ses[i].getMethodName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
String rawTag = tagDateFormat == null
|
||||
? tag
|
||||
: Times.formatTime(tagDateFormat, -1, log.getInstant().toEpochMilli());
|
||||
fillLogRecord(log);
|
||||
logqueue.offer(new SearchLogRecord(rawTag, log));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
// do nothing
|
||||
}
|
||||
@Override
|
||||
public void flush() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws SecurityException {
|
||||
// do nothing
|
||||
}
|
||||
@Override
|
||||
public void close() throws SecurityException {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = DEFAULT_TABLE_NAME)
|
||||
@DistributeTable(strategy = SearchLogRecord.TableStrategy.class)
|
||||
public static class SearchLogRecord {
|
||||
@Entity
|
||||
@Table(name = DEFAULT_TABLE_NAME)
|
||||
@DistributeTable(strategy = SearchLogRecord.TableStrategy.class)
|
||||
public static class SearchLogRecord {
|
||||
|
||||
@Id
|
||||
@ConvertColumn(index = 1)
|
||||
@SearchColumn(options = "false")
|
||||
public String logid;
|
||||
@Id
|
||||
@ConvertColumn(index = 1)
|
||||
@SearchColumn(options = "false")
|
||||
public String logid;
|
||||
|
||||
@ConvertColumn(index = 2)
|
||||
@SearchColumn(options = "false")
|
||||
public String level;
|
||||
@ConvertColumn(index = 2)
|
||||
@SearchColumn(options = "false")
|
||||
public String level;
|
||||
|
||||
@ConvertColumn(index = 3)
|
||||
@SearchColumn(date = true)
|
||||
public long timestamp;
|
||||
@ConvertColumn(index = 3)
|
||||
@SearchColumn(date = true)
|
||||
public long timestamp;
|
||||
|
||||
@ConvertColumn(index = 4)
|
||||
@SearchColumn(options = "false")
|
||||
public String traceid;
|
||||
@ConvertColumn(index = 4)
|
||||
@SearchColumn(options = "false")
|
||||
public String traceid;
|
||||
|
||||
@ConvertColumn(index = 5)
|
||||
public String threadName;
|
||||
@ConvertColumn(index = 5)
|
||||
public String threadName;
|
||||
|
||||
@ConvertColumn(index = 6)
|
||||
@SearchColumn(text = true, options = "offsets")
|
||||
public String loggerName;
|
||||
@ConvertColumn(index = 6)
|
||||
@SearchColumn(text = true, options = "offsets")
|
||||
public String loggerName;
|
||||
|
||||
@ConvertColumn(index = 7)
|
||||
@SearchColumn(text = true, options = "offsets")
|
||||
public String methodName;
|
||||
@ConvertColumn(index = 7)
|
||||
@SearchColumn(text = true, options = "offsets")
|
||||
public String methodName;
|
||||
|
||||
@ConvertColumn(index = 8)
|
||||
@SearchColumn(text = true, options = "offsets") // , analyzer = "ik_max_word"
|
||||
public String message; // log.message +"\r\n"+ log.thrown
|
||||
@ConvertColumn(index = 8)
|
||||
@SearchColumn(text = true, options = "offsets") // , analyzer = "ik_max_word"
|
||||
public String message; // log.message +"\r\n"+ log.thrown
|
||||
|
||||
@Transient
|
||||
@ConvertDisabled
|
||||
LogRecord rawLog;
|
||||
@Transient
|
||||
@ConvertDisabled
|
||||
LogRecord rawLog;
|
||||
|
||||
@Transient
|
||||
@ConvertDisabled
|
||||
String rawTag;
|
||||
@Transient
|
||||
@ConvertDisabled
|
||||
String rawTag;
|
||||
|
||||
public SearchLogRecord() {}
|
||||
public SearchLogRecord() {}
|
||||
|
||||
protected SearchLogRecord(String tag, LogRecord log) {
|
||||
this.rawLog = log;
|
||||
this.rawTag = tag;
|
||||
this.threadName = Thread.currentThread().getName();
|
||||
this.traceid = LoggingBaseHandler.traceEnable && Traces.enable() ? Traces.currentTraceid() : null;
|
||||
String msg = log.getMessage();
|
||||
if (log.getThrown() != null) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
pw.println();
|
||||
log.getThrown().printStackTrace(pw);
|
||||
pw.close();
|
||||
String throwable = sw.toString();
|
||||
this.message = (msg != null && !msg.isEmpty()) ? (msg + "\r\n" + throwable) : throwable;
|
||||
} else {
|
||||
this.message = msg;
|
||||
}
|
||||
this.level = log.getLevel().toString();
|
||||
this.loggerName = log.getLoggerName();
|
||||
this.methodName = log.getSourceClassName() + " " + log.getSourceMethodName();
|
||||
this.timestamp = log.getInstant().toEpochMilli();
|
||||
this.logid = Times.format36time(timestamp) + "_" + Utility.uuid();
|
||||
}
|
||||
protected SearchLogRecord(String tag, LogRecord log) {
|
||||
this.rawLog = log;
|
||||
this.rawTag = tag;
|
||||
this.threadName = Thread.currentThread().getName();
|
||||
this.traceid = LoggingBaseHandler.traceEnable && Traces.enable() ? Traces.currentTraceid() : null;
|
||||
String msg = log.getMessage();
|
||||
if (log.getThrown() != null) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
pw.println();
|
||||
log.getThrown().printStackTrace(pw);
|
||||
pw.close();
|
||||
String throwable = sw.toString();
|
||||
this.message = (msg != null && !msg.isEmpty()) ? (msg + "\r\n" + throwable) : throwable;
|
||||
} else {
|
||||
this.message = msg;
|
||||
}
|
||||
this.level = log.getLevel().toString();
|
||||
this.loggerName = log.getLoggerName();
|
||||
this.methodName = log.getSourceClassName() + " " + log.getSourceMethodName();
|
||||
this.timestamp = log.getInstant().toEpochMilli();
|
||||
this.logid = Times.format36time(timestamp) + "_" + Utility.uuid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
|
||||
public static class TableStrategy implements DistributeTableStrategy<SearchLogRecord> {
|
||||
public static class TableStrategy implements DistributeTableStrategy<SearchLogRecord> {
|
||||
|
||||
@Override
|
||||
public String getTable(String table, SearchLogRecord bean) {
|
||||
return bean.rawTag;
|
||||
}
|
||||
@Override
|
||||
public String getTable(String table, SearchLogRecord bean) {
|
||||
return bean.rawTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTable(String table, Serializable primary) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
@Override
|
||||
public String getTable(String table, Serializable primary) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTables(String table, FilterNode node) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String[] getTables(String table, FilterNode node) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,156 +24,156 @@ import org.redkale.util.Environment;
|
||||
*/
|
||||
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) {
|
||||
this.application = application;
|
||||
this.resourceFactory = Objects.requireNonNull(application.resourceFactory);
|
||||
this.environment = Objects.requireNonNull(application.getEnvironment());
|
||||
}
|
||||
public ModuleEngine(Application application) {
|
||||
this.application = application;
|
||||
this.resourceFactory = Objects.requireNonNull(application.resourceFactory);
|
||||
this.environment = Objects.requireNonNull(application.getEnvironment());
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
|
||||
*
|
||||
* @param path 配置项路径
|
||||
* @param key 配置项名称
|
||||
* @param val1 配置项原值
|
||||
* @param val2 配置项新值
|
||||
* @return MergeEnum
|
||||
*/
|
||||
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
|
||||
*
|
||||
* @param path 配置项路径
|
||||
* @param key 配置项名称
|
||||
* @param val1 配置项原值
|
||||
* @param val2 配置项新值
|
||||
* @return MergeEnum
|
||||
*/
|
||||
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态扩展类的方法
|
||||
*
|
||||
* @param remote 是否远程模式
|
||||
* @param serviceClass 类
|
||||
* @return 方法动态扩展器
|
||||
*/
|
||||
public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 动态扩展类的方法
|
||||
*
|
||||
* @param remote 是否远程模式
|
||||
* @param serviceClass 类
|
||||
* @return 方法动态扩展器
|
||||
*/
|
||||
public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 进入Application.init方法时被调用 此时状态: 1、远程配置项未获取 2、WorkExecutor未初始化 */
|
||||
public void onAppPreInit() {
|
||||
// do nothing
|
||||
}
|
||||
/** 进入Application.init方法时被调用 此时状态: 1、远程配置项未获取 2、WorkExecutor未初始化 */
|
||||
public void onAppPreInit() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/** 结束Application.init方法前被调用 */
|
||||
public void onAppPostInit() {
|
||||
// do nothing
|
||||
}
|
||||
/** 结束Application.init方法前被调用 */
|
||||
public void onAppPostInit() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/** 进入Application.start方法被调用 */
|
||||
public void onAppPreStart() {
|
||||
// do nothing
|
||||
}
|
||||
/** 进入Application.start方法被调用 */
|
||||
public void onAppPreStart() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/** 结束Application.start方法前被调用 */
|
||||
public void onAppPostStart() {
|
||||
// do nothing
|
||||
}
|
||||
/** 结束Application.start方法前被调用 */
|
||||
public void onAppPostStart() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置项加载后被调用
|
||||
*
|
||||
* @param allProps 配置项全量
|
||||
*/
|
||||
public void onEnvironmentLoaded(Properties allProps) {
|
||||
// do nothing
|
||||
}
|
||||
/**
|
||||
* 配置项加载后被调用
|
||||
*
|
||||
* @param allProps 配置项全量
|
||||
*/
|
||||
public void onEnvironmentLoaded(Properties allProps) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置项变更时被调用
|
||||
*
|
||||
* @param namespace 命名空间
|
||||
* @param events 变更项
|
||||
*/
|
||||
public void onEnvironmentChanged(String namespace, List<ResourceEvent> events) {
|
||||
// do nothing
|
||||
}
|
||||
/**
|
||||
* 配置项变更时被调用
|
||||
*
|
||||
* @param namespace 命名空间
|
||||
* @param events 变更项
|
||||
*/
|
||||
public void onEnvironmentChanged(String namespace, List<ResourceEvent> events) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/** Application 在运行Compile前调用 */
|
||||
public void onPreCompile() {
|
||||
// do nothing
|
||||
}
|
||||
/** Application 在运行Compile前调用 */
|
||||
public void onPreCompile() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/** Application 在运行Compile后调用 */
|
||||
public void onPostCompile() {
|
||||
// do nothing
|
||||
}
|
||||
/** Application 在运行Compile后调用 */
|
||||
public void onPostCompile() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/** 服务全部启动前被调用 */
|
||||
public void onServersPreStart() {
|
||||
// do nothing
|
||||
}
|
||||
/** 服务全部启动前被调用 */
|
||||
public void onServersPreStart() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/** 服务全部启动后被调用 */
|
||||
public void onServersPostStart() {
|
||||
// do nothing
|
||||
}
|
||||
/** 服务全部启动后被调用 */
|
||||
public void onServersPostStart() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行Service.init方法前被调用
|
||||
*
|
||||
* @param service Service
|
||||
*/
|
||||
public void onServicePreInit(Service service) {
|
||||
// do nothing
|
||||
}
|
||||
/**
|
||||
* 执行Service.init方法前被调用
|
||||
*
|
||||
* @param service Service
|
||||
*/
|
||||
public void onServicePreInit(Service service) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行Service.init方法后被调用
|
||||
*
|
||||
* @param service Service
|
||||
*/
|
||||
public void onServicePostInit(Service service) {
|
||||
// do nothing
|
||||
}
|
||||
/**
|
||||
* 执行Service.init方法后被调用
|
||||
*
|
||||
* @param service Service
|
||||
*/
|
||||
public void onServicePostInit(Service service) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行Service.destroy方法前被调用
|
||||
*
|
||||
* @param service Service
|
||||
*/
|
||||
public void onServicePreDestroy(Service service) {
|
||||
// do nothing
|
||||
}
|
||||
/**
|
||||
* 执行Service.destroy方法前被调用
|
||||
*
|
||||
* @param service Service
|
||||
*/
|
||||
public void onServicePreDestroy(Service service) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行Service.destroy方法后被调用
|
||||
*
|
||||
* @param service Service
|
||||
*/
|
||||
public void onServicePostDestroy(Service service) {
|
||||
// do nothing
|
||||
}
|
||||
/**
|
||||
* 执行Service.destroy方法后被调用
|
||||
*
|
||||
* @param service Service
|
||||
*/
|
||||
public void onServicePostDestroy(Service service) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/** 服务全部停掉前被调用 */
|
||||
public void onServersPreStop() {
|
||||
// do nothing
|
||||
}
|
||||
/** 服务全部停掉前被调用 */
|
||||
public void onServersPreStop() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/** 服务全部停掉后被调用 */
|
||||
public void onServersPostStop() {
|
||||
// do nothing
|
||||
}
|
||||
/** 服务全部停掉后被调用 */
|
||||
public void onServersPostStop() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/** 进入Application.shutdown方法被调用 */
|
||||
public void onAppPreShutdown() {
|
||||
// do nothing
|
||||
}
|
||||
/** 进入Application.shutdown方法被调用 */
|
||||
public void onAppPreShutdown() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/** 结束Application.shutdown方法前被调用 */
|
||||
public void onAppPostShutdown() {
|
||||
// do nothing
|
||||
}
|
||||
/** 结束Application.shutdown方法前被调用 */
|
||||
public void onAppPostShutdown() {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,23 +14,23 @@ package org.redkale.boot;
|
||||
*/
|
||||
public class NodeInterceptor {
|
||||
|
||||
/**
|
||||
* * Server.start之前调用 <br>
|
||||
* NodeServer.start的部署是先执行NodeInterceptor.preStart,再执行 Server.start 方法
|
||||
*
|
||||
* @param server NodeServer
|
||||
*/
|
||||
public void preStart(NodeServer server) {
|
||||
// do nothing
|
||||
}
|
||||
/**
|
||||
* * Server.start之前调用 <br>
|
||||
* NodeServer.start的部署是先执行NodeInterceptor.preStart,再执行 Server.start 方法
|
||||
*
|
||||
* @param server NodeServer
|
||||
*/
|
||||
public void preStart(NodeServer server) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Server.shutdown之前调用 <br>
|
||||
* NodeServer.shutdown的部署是先执行NodeInterceptor.preShutdown,再执行 Server.shutdown 方法
|
||||
*
|
||||
* @param server NodeServer
|
||||
*/
|
||||
public void preShutdown(NodeServer server) {
|
||||
// do nothing
|
||||
}
|
||||
/**
|
||||
* Server.shutdown之前调用 <br>
|
||||
* NodeServer.shutdown的部署是先执行NodeInterceptor.preShutdown,再执行 Server.shutdown 方法
|
||||
*
|
||||
* @param server NodeServer
|
||||
*/
|
||||
public void preShutdown(NodeServer server) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,5 +19,5 @@ import java.lang.annotation.*;
|
||||
@Documented
|
||||
public @interface NodeProtocol {
|
||||
|
||||
String value();
|
||||
String value();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,159 +25,159 @@ import org.redkale.util.*;
|
||||
@NodeProtocol("SNCP")
|
||||
public class NodeSncpServer extends NodeServer {
|
||||
|
||||
protected final SncpServer sncpServer;
|
||||
protected final SncpServer sncpServer;
|
||||
|
||||
private NodeSncpServer(Application application, AnyValue serconf) {
|
||||
super(application, createServer(application, serconf));
|
||||
this.sncpServer = (SncpServer) this.server;
|
||||
}
|
||||
private NodeSncpServer(Application application, AnyValue serconf) {
|
||||
super(application, createServer(application, serconf));
|
||||
this.sncpServer = (SncpServer) this.server;
|
||||
}
|
||||
|
||||
public static NodeServer createNodeServer(Application application, AnyValue serconf) {
|
||||
return new NodeSncpServer(application, serconf);
|
||||
}
|
||||
public static NodeServer createNodeServer(Application application, AnyValue serconf) {
|
||||
return new NodeSncpServer(application, serconf);
|
||||
}
|
||||
|
||||
private static Server createServer(Application application, AnyValue serconf) {
|
||||
return new SncpServer(
|
||||
application,
|
||||
application.getStartTime(),
|
||||
serconf,
|
||||
application.getResourceFactory().createChild());
|
||||
}
|
||||
private static Server createServer(Application application, AnyValue serconf) {
|
||||
return new SncpServer(
|
||||
application,
|
||||
application.getStartTime(),
|
||||
serconf,
|
||||
application.getResourceFactory().createChild());
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getSocketAddress() {
|
||||
return sncpServer == null ? null : sncpServer.getSocketAddress();
|
||||
}
|
||||
@Override
|
||||
public InetSocketAddress getSocketAddress() {
|
||||
return sncpServer == null ? null : sncpServer.getSocketAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(AnyValue config) throws Exception {
|
||||
super.init(config);
|
||||
// -------------------------------------------------------------------
|
||||
if (sncpServer == null) {
|
||||
return; // 调试时server才可能为null
|
||||
}
|
||||
final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null;
|
||||
List<SncpServlet> servlets = sncpServer.getSncpServlets();
|
||||
Collections.sort(servlets);
|
||||
@Override
|
||||
public void init(AnyValue config) throws Exception {
|
||||
super.init(config);
|
||||
// -------------------------------------------------------------------
|
||||
if (sncpServer == null) {
|
||||
return; // 调试时server才可能为null
|
||||
}
|
||||
final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null;
|
||||
List<SncpServlet> servlets = sncpServer.getSncpServlets();
|
||||
Collections.sort(servlets);
|
||||
|
||||
int maxTypeLength = 0;
|
||||
int maxNameLength = 0;
|
||||
for (SncpServlet en : servlets) {
|
||||
maxNameLength = Math.max(maxNameLength, en.getResourceName().length() + 1);
|
||||
maxTypeLength =
|
||||
Math.max(maxTypeLength, en.getResourceType().getName().length());
|
||||
}
|
||||
for (SncpServlet en : servlets) {
|
||||
if (sb != null) {
|
||||
sb.append("Load ")
|
||||
.append(toSimpleString(en, maxTypeLength, maxNameLength))
|
||||
.append(LINE_SEPARATOR);
|
||||
}
|
||||
}
|
||||
if (sb != null && sb.length() > 0) {
|
||||
logger.log(Level.FINE, sb.toString());
|
||||
}
|
||||
}
|
||||
int maxTypeLength = 0;
|
||||
int maxNameLength = 0;
|
||||
for (SncpServlet en : servlets) {
|
||||
maxNameLength = Math.max(maxNameLength, en.getResourceName().length() + 1);
|
||||
maxTypeLength =
|
||||
Math.max(maxTypeLength, en.getResourceType().getName().length());
|
||||
}
|
||||
for (SncpServlet en : servlets) {
|
||||
if (sb != null) {
|
||||
sb.append("Load ")
|
||||
.append(toSimpleString(en, maxTypeLength, maxNameLength))
|
||||
.append(LINE_SEPARATOR);
|
||||
}
|
||||
}
|
||||
if (sb != null && sb.length() > 0) {
|
||||
logger.log(Level.FINE, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private StringBuilder toSimpleString(SncpServlet servlet, int maxTypeLength, int maxNameLength) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Class serviceType = servlet.getResourceType();
|
||||
String serviceName = servlet.getResourceName();
|
||||
int size = servlet.getActionSize();
|
||||
sb.append(SncpServlet.class.getSimpleName()).append(" (type=").append(serviceType.getName());
|
||||
int len = maxTypeLength - serviceType.getName().length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(", serviceid=")
|
||||
.append(servlet.getServiceid())
|
||||
.append(", name='")
|
||||
.append(serviceName)
|
||||
.append("'");
|
||||
for (int i = 0; i < maxNameLength - serviceName.length(); i++) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(", actions.size=").append(size > 9 ? "" : " ").append(size).append(")");
|
||||
return sb;
|
||||
}
|
||||
private StringBuilder toSimpleString(SncpServlet servlet, int maxTypeLength, int maxNameLength) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Class serviceType = servlet.getResourceType();
|
||||
String serviceName = servlet.getResourceName();
|
||||
int size = servlet.getActionSize();
|
||||
sb.append(SncpServlet.class.getSimpleName()).append(" (type=").append(serviceType.getName());
|
||||
int len = maxTypeLength - serviceType.getName().length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(", serviceid=")
|
||||
.append(servlet.getServiceid())
|
||||
.append(", name='")
|
||||
.append(serviceName)
|
||||
.append("'");
|
||||
for (int i = 0; i < maxNameLength - serviceName.length(); i++) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(", actions.size=").append(size > 9 ? "" : " ").append(size).append(")");
|
||||
return sb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSNCP() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean isSNCP() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public SncpServer getSncpServer() {
|
||||
return sncpServer;
|
||||
}
|
||||
public SncpServer getSncpServer() {
|
||||
return sncpServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadFilter(ClassFilter<? extends Filter> filterFilter) throws Exception {
|
||||
if (sncpServer != null) {
|
||||
loadSncpFilter(this.serverConf.getAnyValue("fliters"), filterFilter);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void loadFilter(ClassFilter<? extends Filter> filterFilter) throws Exception {
|
||||
if (sncpServer != null) {
|
||||
loadSncpFilter(this.serverConf.getAnyValue("fliters"), filterFilter);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void loadSncpFilter(final AnyValue servletsConf, final ClassFilter<? extends Filter> classFilter)
|
||||
throws Exception {
|
||||
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
|
||||
for (FilterEntry<? extends Filter> entry : list) {
|
||||
Class<SncpFilter> clazz = (Class<SncpFilter>) entry.getType();
|
||||
if (Utility.isAbstractOrInterface(clazz)) {
|
||||
continue;
|
||||
}
|
||||
if (entry.isExpect()) { // 跳过不自动加载的Filter
|
||||
continue;
|
||||
}
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
|
||||
final SncpFilter filter = clazz.getDeclaredConstructor().newInstance();
|
||||
resourceFactory.inject(filter, this);
|
||||
AnyValueWriter filterConf = (AnyValueWriter) entry.getProperty();
|
||||
this.sncpServer.addSncpFilter(filter, filterConf);
|
||||
if (sb != null) {
|
||||
sb.append("Load ").append(clazz.getName()).append(LINE_SEPARATOR);
|
||||
}
|
||||
}
|
||||
if (sb != null && sb.length() > 0) {
|
||||
logger.log(Level.INFO, sb.toString());
|
||||
}
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void loadSncpFilter(final AnyValue servletsConf, final ClassFilter<? extends Filter> classFilter)
|
||||
throws Exception {
|
||||
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
|
||||
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
|
||||
for (FilterEntry<? extends Filter> entry : list) {
|
||||
Class<SncpFilter> clazz = (Class<SncpFilter>) entry.getType();
|
||||
if (Utility.isAbstractOrInterface(clazz)) {
|
||||
continue;
|
||||
}
|
||||
if (entry.isExpect()) { // 跳过不自动加载的Filter
|
||||
continue;
|
||||
}
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
|
||||
final SncpFilter filter = clazz.getDeclaredConstructor().newInstance();
|
||||
resourceFactory.inject(filter, this);
|
||||
AnyValueWriter filterConf = (AnyValueWriter) entry.getProperty();
|
||||
this.sncpServer.addSncpFilter(filter, filterConf);
|
||||
if (sb != null) {
|
||||
sb.append("Load ").append(clazz.getName()).append(LINE_SEPARATOR);
|
||||
}
|
||||
}
|
||||
if (sb != null && sb.length() > 0) {
|
||||
logger.log(Level.INFO, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception {
|
||||
RedkaleClassLoader.putReflectionPublicClasses(SncpServlet.class.getName());
|
||||
if (!application.isSingletonMode()) {
|
||||
this.servletServices.stream()
|
||||
.filter(x -> x.getClass().getAnnotation(Local.class) == null) // Local模式的Service不生成SncpServlet
|
||||
.forEach(x -> {
|
||||
SncpServlet servlet = sncpServer.addSncpServlet(x);
|
||||
dynServletMap.put(x, servlet);
|
||||
String mq = Sncp.getResourceMQ(x);
|
||||
if (mq != null) {
|
||||
MessageAgent agent =
|
||||
application.getResourceFactory().find(mq, MessageAgent.class);
|
||||
agent.putService(this, x, servlet);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception {
|
||||
RedkaleClassLoader.putReflectionPublicClasses(SncpServlet.class.getName());
|
||||
if (!application.isSingletonMode()) {
|
||||
this.servletServices.stream()
|
||||
.filter(x -> x.getClass().getAnnotation(Local.class) == null) // Local模式的Service不生成SncpServlet
|
||||
.forEach(x -> {
|
||||
SncpServlet servlet = sncpServer.addSncpServlet(x);
|
||||
dynServletMap.put(x, servlet);
|
||||
String mq = Sncp.getResourceMQ(x);
|
||||
if (mq != null) {
|
||||
MessageAgent agent =
|
||||
application.getResourceFactory().find(mq, MessageAgent.class);
|
||||
agent.putService(this, x, servlet);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ClassFilter<Filter> createFilterClassFilter() {
|
||||
return createClassFilter(
|
||||
null,
|
||||
null,
|
||||
SncpFilter.class,
|
||||
new Class[] {org.redkale.watch.WatchFilter.class},
|
||||
null,
|
||||
"filters",
|
||||
"filter");
|
||||
}
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ClassFilter<Filter> createFilterClassFilter() {
|
||||
return createClassFilter(
|
||||
null,
|
||||
null,
|
||||
SncpFilter.class,
|
||||
new Class[] {org.redkale.watch.WatchFilter.class},
|
||||
null,
|
||||
"filters",
|
||||
"filter");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassFilter<Servlet> createServletClassFilter() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
protected ClassFilter<Servlet> createServletClassFilter() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,36 +17,36 @@ import org.redkale.watch.*;
|
||||
@NodeProtocol("WATCH")
|
||||
public class NodeWatchServer extends NodeHttpServer {
|
||||
|
||||
public NodeWatchServer(Application application, AnyValue serconf) {
|
||||
super(application, serconf);
|
||||
}
|
||||
public NodeWatchServer(Application application, AnyValue serconf) {
|
||||
super(application, serconf);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ClassFilter<Service> createServiceClassFilter() {
|
||||
return createClassFilter(
|
||||
this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service");
|
||||
}
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ClassFilter<Service> createServiceClassFilter() {
|
||||
return createClassFilter(
|
||||
this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ClassFilter<Filter> createFilterClassFilter() {
|
||||
return createClassFilter(null, null, WatchFilter.class, null, null, "filters", "filter");
|
||||
}
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ClassFilter<Filter> createFilterClassFilter() {
|
||||
return createClassFilter(null, null, WatchFilter.class, null, null, "filters", "filter");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ClassFilter<Servlet> createServletClassFilter() {
|
||||
return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet");
|
||||
}
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ClassFilter<Servlet> createServletClassFilter() {
|
||||
return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ClassFilter> createOtherClassFilters() {
|
||||
return null; // 不调用 super.createOtherClassFilters()
|
||||
}
|
||||
@Override
|
||||
protected List<ClassFilter> createOtherClassFilters() {
|
||||
return null; // 不调用 super.createOtherClassFilters()
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWATCH() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean isWATCH() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,123 +23,123 @@ import org.redkale.util.Utility;
|
||||
*/
|
||||
public class PrepareCompiler {
|
||||
|
||||
// public static void main(String[] args) throws Exception {
|
||||
// new PrepareCompiler().run();
|
||||
// }
|
||||
public Application run() throws Exception {
|
||||
// 必须设置redkale.resource.skip.check=true
|
||||
// 因redkale-maven-plugin的maven-core依赖jsr250,会覆盖redkale的javax.annotation.Resource导致无法识别Resource.required方法
|
||||
System.setProperty("redkale.resource.skip.check", "true");
|
||||
final Application application = new Application(AppConfig.create(false, true));
|
||||
application.init();
|
||||
application.onPreCompile();
|
||||
application.start();
|
||||
final boolean hasSncp = application.getNodeServers().stream()
|
||||
.filter(NodeSncpServer.class::isInstance)
|
||||
.findFirst()
|
||||
.isPresent();
|
||||
// public static void main(String[] args) throws Exception {
|
||||
// new PrepareCompiler().run();
|
||||
// }
|
||||
public Application run() throws Exception {
|
||||
// 必须设置redkale.resource.skip.check=true
|
||||
// 因redkale-maven-plugin的maven-core依赖jsr250,会覆盖redkale的javax.annotation.Resource导致无法识别Resource.required方法
|
||||
System.setProperty("redkale.resource.skip.check", "true");
|
||||
final Application application = new Application(AppConfig.create(false, true));
|
||||
application.init();
|
||||
application.onPreCompile();
|
||||
application.start();
|
||||
final boolean hasSncp = application.getNodeServers().stream()
|
||||
.filter(NodeSncpServer.class::isInstance)
|
||||
.findFirst()
|
||||
.isPresent();
|
||||
|
||||
final ClassFilter<?> entityFilter = new ClassFilter(application.getClassLoader(), Entity.class, Object.class);
|
||||
final ClassFilter<?> entityFilter2 =
|
||||
new ClassFilter(application.getClassLoader(), javax.persistence.Entity.class, Object.class);
|
||||
final ClassFilter<?> beanFilter = new ClassFilter(application.getClassLoader(), Bean.class, Object.class);
|
||||
final ClassFilter<?> beanFilter2 =
|
||||
new ClassFilter(application.getClassLoader(), org.redkale.util.Bean.class, Object.class);
|
||||
final ClassFilter<?> filterFilter = new ClassFilter(application.getClassLoader(), null, FilterBean.class);
|
||||
final ClassFilter<?> entityFilter = new ClassFilter(application.getClassLoader(), Entity.class, Object.class);
|
||||
final ClassFilter<?> entityFilter2 =
|
||||
new ClassFilter(application.getClassLoader(), javax.persistence.Entity.class, Object.class);
|
||||
final ClassFilter<?> beanFilter = new ClassFilter(application.getClassLoader(), Bean.class, Object.class);
|
||||
final ClassFilter<?> beanFilter2 =
|
||||
new ClassFilter(application.getClassLoader(), org.redkale.util.Bean.class, Object.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()) {
|
||||
Class clz = en.getType();
|
||||
if (Utility.isAbstractOrInterface(clz)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
List<DataSource> dataSources = application.getResourceFactory().query(DataSource.class);
|
||||
dataSources.forEach(source -> source.compile(clz));
|
||||
// application.dataSources.forEach(source -> source.compile(clz));
|
||||
JsonFactory.root().loadEncoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadEncoder(clz);
|
||||
}
|
||||
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadDecoder(clz);
|
||||
}
|
||||
decoder.convertFrom(new JsonReader("{}"));
|
||||
} catch (Exception e) { // JsonFactory.loadDecoder可能会失败,因为class可能包含抽象类字段,如ColumnValue.value字段
|
||||
}
|
||||
}
|
||||
for (FilterEntry en : entityFilter2.getFilterEntrys()) {
|
||||
Class clz = en.getType();
|
||||
if (Utility.isAbstractOrInterface(clz)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
List<DataSource> dataSources = application.getResourceFactory().query(DataSource.class);
|
||||
dataSources.forEach(source -> source.compile(clz));
|
||||
// application.dataSources.forEach(source -> source.compile(clz));
|
||||
JsonFactory.root().loadEncoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadEncoder(clz);
|
||||
}
|
||||
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadDecoder(clz);
|
||||
}
|
||||
decoder.convertFrom(new JsonReader("{}"));
|
||||
} catch (Exception e) { // JsonFactory.loadDecoder可能会失败,因为class可能包含抽象类字段,如ColumnValue.value字段
|
||||
}
|
||||
}
|
||||
for (FilterEntry en : beanFilter.getFilterEntrys()) {
|
||||
Class clz = en.getType();
|
||||
if (Utility.isAbstractOrInterface(clz)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
JsonFactory.root().loadEncoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadEncoder(clz);
|
||||
}
|
||||
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadDecoder(clz);
|
||||
}
|
||||
decoder.convertFrom(new JsonReader("{}"));
|
||||
} catch (Exception e) { // JsonFactory.loadDecoder可能会失败,因为class可能包含抽象类字段,如ColumnValue.value字段
|
||||
}
|
||||
}
|
||||
for (FilterEntry en : beanFilter2.getFilterEntrys()) {
|
||||
Class clz = en.getType();
|
||||
if (Utility.isAbstractOrInterface(clz)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
JsonFactory.root().loadEncoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadEncoder(clz);
|
||||
}
|
||||
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadDecoder(clz);
|
||||
}
|
||||
decoder.convertFrom(new JsonReader("{}"));
|
||||
} catch (Exception e) { // JsonFactory.loadDecoder可能会失败,因为class可能包含抽象类字段,如ColumnValue.value字段
|
||||
}
|
||||
}
|
||||
for (FilterEntry en : filterFilter.getFilterEntrys()) {
|
||||
Class clz = en.getType();
|
||||
if (Utility.isAbstractOrInterface(clz)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
FilterNodeBean.load(clz);
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
application.onPostCompile();
|
||||
application.shutdown();
|
||||
return application;
|
||||
}
|
||||
for (FilterEntry en : entityFilter.getFilterEntrys()) {
|
||||
Class clz = en.getType();
|
||||
if (Utility.isAbstractOrInterface(clz)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
List<DataSource> dataSources = application.getResourceFactory().query(DataSource.class);
|
||||
dataSources.forEach(source -> source.compile(clz));
|
||||
// application.dataSources.forEach(source -> source.compile(clz));
|
||||
JsonFactory.root().loadEncoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadEncoder(clz);
|
||||
}
|
||||
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadDecoder(clz);
|
||||
}
|
||||
decoder.convertFrom(new JsonReader("{}"));
|
||||
} catch (Exception e) { // JsonFactory.loadDecoder可能会失败,因为class可能包含抽象类字段,如ColumnValue.value字段
|
||||
}
|
||||
}
|
||||
for (FilterEntry en : entityFilter2.getFilterEntrys()) {
|
||||
Class clz = en.getType();
|
||||
if (Utility.isAbstractOrInterface(clz)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
List<DataSource> dataSources = application.getResourceFactory().query(DataSource.class);
|
||||
dataSources.forEach(source -> source.compile(clz));
|
||||
// application.dataSources.forEach(source -> source.compile(clz));
|
||||
JsonFactory.root().loadEncoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadEncoder(clz);
|
||||
}
|
||||
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadDecoder(clz);
|
||||
}
|
||||
decoder.convertFrom(new JsonReader("{}"));
|
||||
} catch (Exception e) { // JsonFactory.loadDecoder可能会失败,因为class可能包含抽象类字段,如ColumnValue.value字段
|
||||
}
|
||||
}
|
||||
for (FilterEntry en : beanFilter.getFilterEntrys()) {
|
||||
Class clz = en.getType();
|
||||
if (Utility.isAbstractOrInterface(clz)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
JsonFactory.root().loadEncoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadEncoder(clz);
|
||||
}
|
||||
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadDecoder(clz);
|
||||
}
|
||||
decoder.convertFrom(new JsonReader("{}"));
|
||||
} catch (Exception e) { // JsonFactory.loadDecoder可能会失败,因为class可能包含抽象类字段,如ColumnValue.value字段
|
||||
}
|
||||
}
|
||||
for (FilterEntry en : beanFilter2.getFilterEntrys()) {
|
||||
Class clz = en.getType();
|
||||
if (Utility.isAbstractOrInterface(clz)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
JsonFactory.root().loadEncoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadEncoder(clz);
|
||||
}
|
||||
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
|
||||
if (hasSncp) {
|
||||
BsonFactory.root().loadDecoder(clz);
|
||||
}
|
||||
decoder.convertFrom(new JsonReader("{}"));
|
||||
} catch (Exception e) { // JsonFactory.loadDecoder可能会失败,因为class可能包含抽象类字段,如ColumnValue.value字段
|
||||
}
|
||||
}
|
||||
for (FilterEntry en : filterFilter.getFilterEntrys()) {
|
||||
Class clz = en.getType();
|
||||
if (Utility.isAbstractOrInterface(clz)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
FilterNodeBean.load(clz);
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
application.onPostCompile();
|
||||
application.shutdown();
|
||||
return application;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ import org.redkale.watch.WatchService;
|
||||
/** @author zhangjx */
|
||||
public abstract class AbstractWatchService extends AbstractService implements WatchService {
|
||||
|
||||
/** 缺少参数 */
|
||||
@Comment("缺少参数")
|
||||
public static final int RET_WATCH_PARAMS_ILLEGAL = 1600_0001;
|
||||
/** 缺少参数 */
|
||||
@Comment("缺少参数")
|
||||
public static final int RET_WATCH_PARAMS_ILLEGAL = 1600_0001;
|
||||
|
||||
/** 执行异常 */
|
||||
@Comment("执行异常")
|
||||
public static final int RET_WATCH_RUN_EXCEPTION = 1600_0002;
|
||||
/** 执行异常 */
|
||||
@Comment("执行异常")
|
||||
public static final int RET_WATCH_RUN_EXCEPTION = 1600_0002;
|
||||
}
|
||||
|
||||
@@ -16,69 +16,69 @@ import org.redkale.service.RetResult;
|
||||
@RestService(name = "filter", catalog = "watch", repair = false)
|
||||
public class FilterWatchService extends AbstractWatchService {
|
||||
|
||||
@Comment("Filter类名不存在")
|
||||
public static final int RET_FILTER_TYPE_NOT_EXISTS = 1601_0002;
|
||||
@Comment("Filter类名不存在")
|
||||
public static final int RET_FILTER_TYPE_NOT_EXISTS = 1601_0002;
|
||||
|
||||
@Comment("Filter类名不合法")
|
||||
public static final int RET_FILTER_TYPE_ILLEGAL = 1601_0003;
|
||||
@Comment("Filter类名不合法")
|
||||
public static final int RET_FILTER_TYPE_ILLEGAL = 1601_0003;
|
||||
|
||||
@Comment("Filter类名已存在")
|
||||
public static final int RET_FILTER_EXISTS = 1601_0004;
|
||||
@Comment("Filter类名已存在")
|
||||
public static final int RET_FILTER_EXISTS = 1601_0004;
|
||||
|
||||
@Comment("Filter的JAR包不存在")
|
||||
public static final int RET_FILTER_JAR_ILLEGAL = 1601_0005;
|
||||
@Comment("Filter的JAR包不存在")
|
||||
public static final int RET_FILTER_JAR_ILLEGAL = 1601_0005;
|
||||
|
||||
@Resource
|
||||
protected Application application;
|
||||
@Resource
|
||||
protected Application application;
|
||||
|
||||
@RestMapping(name = "addFilter", auth = false, comment = "动态增加Filter")
|
||||
public RetResult addFilter(
|
||||
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameRegx = "\\.jar$") byte[] jar,
|
||||
@RestParam(name = "server", comment = "Server节点名") final String serverName,
|
||||
@RestParam(name = "type", comment = "Filter类名") final String filterType)
|
||||
throws IOException {
|
||||
if (filterType == null) {
|
||||
return new RetResult(RET_FILTER_TYPE_NOT_EXISTS, "Not found Filter Type (" + filterType + ")");
|
||||
}
|
||||
if (jar == null) {
|
||||
return new RetResult(RET_FILTER_JAR_ILLEGAL, "Not found jar file");
|
||||
}
|
||||
List<NodeServer> nodes = application.getNodeServers();
|
||||
for (NodeServer node : nodes) {
|
||||
if (node.getServer().containsFilter(filterType)) {
|
||||
return new RetResult(RET_FILTER_EXISTS, "Filter(" + filterType + ") exists");
|
||||
}
|
||||
}
|
||||
return RetResult.success();
|
||||
}
|
||||
@RestMapping(name = "addFilter", auth = false, comment = "动态增加Filter")
|
||||
public RetResult addFilter(
|
||||
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameRegx = "\\.jar$") byte[] jar,
|
||||
@RestParam(name = "server", comment = "Server节点名") final String serverName,
|
||||
@RestParam(name = "type", comment = "Filter类名") final String filterType)
|
||||
throws IOException {
|
||||
if (filterType == null) {
|
||||
return new RetResult(RET_FILTER_TYPE_NOT_EXISTS, "Not found Filter Type (" + filterType + ")");
|
||||
}
|
||||
if (jar == null) {
|
||||
return new RetResult(RET_FILTER_JAR_ILLEGAL, "Not found jar file");
|
||||
}
|
||||
List<NodeServer> nodes = application.getNodeServers();
|
||||
for (NodeServer node : nodes) {
|
||||
if (node.getServer().containsFilter(filterType)) {
|
||||
return new RetResult(RET_FILTER_EXISTS, "Filter(" + filterType + ") exists");
|
||||
}
|
||||
}
|
||||
return RetResult.success();
|
||||
}
|
||||
|
||||
@RestMapping(name = "test1", auth = false, comment = "预留")
|
||||
public RetResult test1() {
|
||||
return RetResult.success();
|
||||
}
|
||||
@RestMapping(name = "test1", auth = false, comment = "预留")
|
||||
public RetResult test1() {
|
||||
return RetResult.success();
|
||||
}
|
||||
|
||||
@RestMapping(name = "test2", auth = false, comment = "预留")
|
||||
public RetResult test2() {
|
||||
return RetResult.success();
|
||||
}
|
||||
@RestMapping(name = "test2", auth = false, comment = "预留")
|
||||
public RetResult test2() {
|
||||
return RetResult.success();
|
||||
}
|
||||
|
||||
@RestMapping(name = "test3", auth = false, comment = "预留")
|
||||
public RetResult test3() {
|
||||
return RetResult.success();
|
||||
}
|
||||
@RestMapping(name = "test3", auth = false, comment = "预留")
|
||||
public RetResult test3() {
|
||||
return RetResult.success();
|
||||
}
|
||||
|
||||
@RestMapping(name = "test4", auth = false, comment = "预留")
|
||||
public RetResult test4() {
|
||||
return RetResult.success();
|
||||
}
|
||||
@RestMapping(name = "test4", auth = false, comment = "预留")
|
||||
public RetResult test4() {
|
||||
return RetResult.success();
|
||||
}
|
||||
|
||||
@RestMapping(name = "test5", auth = false, comment = "预留")
|
||||
public RetResult test5() {
|
||||
return RetResult.success();
|
||||
}
|
||||
@RestMapping(name = "test5", auth = false, comment = "预留")
|
||||
public RetResult test5() {
|
||||
return RetResult.success();
|
||||
}
|
||||
|
||||
@RestMapping(name = "test6", auth = false, comment = "预留")
|
||||
public RetResult test6() {
|
||||
return RetResult.success();
|
||||
}
|
||||
@RestMapping(name = "test6", auth = false, comment = "预留")
|
||||
public RetResult test6() {
|
||||
return RetResult.success();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,99 +19,99 @@ import org.redkale.service.RetResult;
|
||||
@RestService(name = "server", catalog = "watch", repair = false)
|
||||
public class ServerWatchService extends AbstractWatchService {
|
||||
|
||||
@Comment("不存在的Server节点")
|
||||
public static final int RET_SERVER_NOT_EXISTS = 1602_0001;
|
||||
@Comment("不存在的Server节点")
|
||||
public static final int RET_SERVER_NOT_EXISTS = 1602_0001;
|
||||
|
||||
@Comment("更改Server监听地址端口失败")
|
||||
public static final int RET_SERVER_CHANGEPORT_ERROR = 1602_0002;
|
||||
@Comment("更改Server监听地址端口失败")
|
||||
public static final int RET_SERVER_CHANGEPORT_ERROR = 1602_0002;
|
||||
|
||||
@Resource
|
||||
protected Application application;
|
||||
@Resource
|
||||
protected Application application;
|
||||
|
||||
@RestMapping(name = "info", comment = "单个Server信息查询")
|
||||
public RetResult info(@RestParam(name = "#port:") final int port) {
|
||||
Stream<NodeServer> stream = application.getNodeServers().stream();
|
||||
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == port)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (node == null) {
|
||||
return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found");
|
||||
}
|
||||
return new RetResult(formatToMap(node));
|
||||
}
|
||||
@RestMapping(name = "info", comment = "单个Server信息查询")
|
||||
public RetResult info(@RestParam(name = "#port:") final int port) {
|
||||
Stream<NodeServer> stream = application.getNodeServers().stream();
|
||||
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == port)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (node == null) {
|
||||
return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found");
|
||||
}
|
||||
return new RetResult(formatToMap(node));
|
||||
}
|
||||
|
||||
@RestMapping(name = "infos", comment = "Server信息查询")
|
||||
public RetResult infos() {
|
||||
Map<String, Object> rs = new LinkedHashMap<>();
|
||||
for (NodeServer ns : application.getNodeServers()) {
|
||||
Server server = ns.getServer();
|
||||
rs.put("" + server.getSocketAddress().getPort(), formatToMap(ns));
|
||||
}
|
||||
return new RetResult(rs);
|
||||
}
|
||||
@RestMapping(name = "infos", comment = "Server信息查询")
|
||||
public RetResult infos() {
|
||||
Map<String, Object> rs = new LinkedHashMap<>();
|
||||
for (NodeServer ns : application.getNodeServers()) {
|
||||
Server server = ns.getServer();
|
||||
rs.put("" + server.getSocketAddress().getPort(), formatToMap(ns));
|
||||
}
|
||||
return new RetResult(rs);
|
||||
}
|
||||
|
||||
@RestMapping(name = "changeAddress", comment = "更改Server的监听地址和端口")
|
||||
public RetResult changeAddress(
|
||||
@RestParam(name = "#port:") final int oldport,
|
||||
@RestParam(name = "#newhost:") final String newhost,
|
||||
@RestParam(name = "#newport:") final int newport) {
|
||||
if (oldport < 1) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`");
|
||||
}
|
||||
if (newport < 1) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `newport`");
|
||||
}
|
||||
Stream<NodeServer> stream = application.getNodeServers().stream();
|
||||
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == oldport)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (node == null) {
|
||||
return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + oldport + ") not found");
|
||||
}
|
||||
final Server server = node.getServer();
|
||||
InetSocketAddress newAddr = new InetSocketAddress(
|
||||
newhost == null || newhost.isEmpty() ? server.getSocketAddress().getHostString() : newhost, newport);
|
||||
try {
|
||||
server.changeAddress(application, newAddr);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return new RetResult(RET_SERVER_CHANGEPORT_ERROR, "changeAddress error");
|
||||
}
|
||||
return RetResult.success();
|
||||
}
|
||||
@RestMapping(name = "changeAddress", comment = "更改Server的监听地址和端口")
|
||||
public RetResult changeAddress(
|
||||
@RestParam(name = "#port:") final int oldport,
|
||||
@RestParam(name = "#newhost:") final String newhost,
|
||||
@RestParam(name = "#newport:") final int newport) {
|
||||
if (oldport < 1) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`");
|
||||
}
|
||||
if (newport < 1) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `newport`");
|
||||
}
|
||||
Stream<NodeServer> stream = application.getNodeServers().stream();
|
||||
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == oldport)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (node == null) {
|
||||
return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + oldport + ") not found");
|
||||
}
|
||||
final Server server = node.getServer();
|
||||
InetSocketAddress newAddr = new InetSocketAddress(
|
||||
newhost == null || newhost.isEmpty() ? server.getSocketAddress().getHostString() : newhost, newport);
|
||||
try {
|
||||
server.changeAddress(application, newAddr);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return new RetResult(RET_SERVER_CHANGEPORT_ERROR, "changeAddress error");
|
||||
}
|
||||
return RetResult.success();
|
||||
}
|
||||
|
||||
private Map<String, Object> formatToMap(NodeServer node) {
|
||||
Server server = node.getServer();
|
||||
Map<String, Object> rs = new LinkedHashMap<>();
|
||||
String protocol = server.getNetprotocol();
|
||||
if (node instanceof NodeSncpServer) {
|
||||
protocol += "/SNCP";
|
||||
} else if (node instanceof NodeWatchServer) {
|
||||
protocol += "/WATCH";
|
||||
} else if (node instanceof NodeHttpServer) {
|
||||
protocol += "/HTTP";
|
||||
} else {
|
||||
NodeProtocol np = node.getClass().getAnnotation(NodeProtocol.class);
|
||||
protocol += "/" + np.value();
|
||||
}
|
||||
rs.put("name", server.getName());
|
||||
rs.put("protocol", protocol);
|
||||
rs.put("address", server.getSocketAddress());
|
||||
rs.put("backlog", server.getBacklog());
|
||||
rs.put("bufferCapacity", server.getBufferCapacity());
|
||||
rs.put("bufferPoolSize", server.getBufferPoolSize());
|
||||
rs.put(
|
||||
"charset",
|
||||
server.getCharset() == null ? "UTF-8" : server.getCharset().name());
|
||||
rs.put("maxbody", server.getMaxBody());
|
||||
rs.put("maxconns", server.getMaxConns());
|
||||
rs.put("serverStartTime", server.getServerStartTime());
|
||||
rs.put("responsePoolSize", server.getResponsePoolSize());
|
||||
rs.put("readTimeoutSeconds", server.getReadTimeoutSeconds());
|
||||
rs.put("writeTimeoutSeconds", server.getWriteTimeoutSeconds());
|
||||
rs.put("createConnectionCount", server.getCreateConnectionCount());
|
||||
rs.put("livingConnectionCount", server.getLivingConnectionCount());
|
||||
rs.put("closedConnectionCount", server.getClosedConnectionCount());
|
||||
return rs;
|
||||
}
|
||||
private Map<String, Object> formatToMap(NodeServer node) {
|
||||
Server server = node.getServer();
|
||||
Map<String, Object> rs = new LinkedHashMap<>();
|
||||
String protocol = server.getNetprotocol();
|
||||
if (node instanceof NodeSncpServer) {
|
||||
protocol += "/SNCP";
|
||||
} else if (node instanceof NodeWatchServer) {
|
||||
protocol += "/WATCH";
|
||||
} else if (node instanceof NodeHttpServer) {
|
||||
protocol += "/HTTP";
|
||||
} else {
|
||||
NodeProtocol np = node.getClass().getAnnotation(NodeProtocol.class);
|
||||
protocol += "/" + np.value();
|
||||
}
|
||||
rs.put("name", server.getName());
|
||||
rs.put("protocol", protocol);
|
||||
rs.put("address", server.getSocketAddress());
|
||||
rs.put("backlog", server.getBacklog());
|
||||
rs.put("bufferCapacity", server.getBufferCapacity());
|
||||
rs.put("bufferPoolSize", server.getBufferPoolSize());
|
||||
rs.put(
|
||||
"charset",
|
||||
server.getCharset() == null ? "UTF-8" : server.getCharset().name());
|
||||
rs.put("maxbody", server.getMaxBody());
|
||||
rs.put("maxconns", server.getMaxConns());
|
||||
rs.put("serverStartTime", server.getServerStartTime());
|
||||
rs.put("responsePoolSize", server.getResponsePoolSize());
|
||||
rs.put("readTimeoutSeconds", server.getReadTimeoutSeconds());
|
||||
rs.put("writeTimeoutSeconds", server.getWriteTimeoutSeconds());
|
||||
rs.put("createConnectionCount", server.getCreateConnectionCount());
|
||||
rs.put("livingConnectionCount", server.getLivingConnectionCount());
|
||||
rs.put("closedConnectionCount", server.getClosedConnectionCount());
|
||||
return rs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,241 +22,241 @@ import org.redkale.service.RetResult;
|
||||
@RestService(name = "service", catalog = "watch", repair = false)
|
||||
public class ServiceWatchService extends AbstractWatchService {
|
||||
|
||||
@Comment("没有找到目标Service")
|
||||
public static final int RET_SERVICE_DEST_NOT_EXISTS = 1603_0001;
|
||||
@Comment("没有找到目标Service")
|
||||
public static final int RET_SERVICE_DEST_NOT_EXISTS = 1603_0001;
|
||||
|
||||
@Resource
|
||||
protected Application application;
|
||||
@Resource
|
||||
protected Application application;
|
||||
|
||||
@RestConvert(type = void.class)
|
||||
@RestMapping(name = "setField", auth = false, comment = "设置Service中指定字段的内容")
|
||||
public RetResult setField(
|
||||
@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||
@RestParam(name = "field", comment = "字段名") String field,
|
||||
@RestParam(name = "value", comment = "字段值") String value) {
|
||||
if (name == null) {
|
||||
name = "";
|
||||
}
|
||||
if (type == null) {
|
||||
type = "";
|
||||
}
|
||||
if (field == null) {
|
||||
field = "";
|
||||
}
|
||||
type = type.trim();
|
||||
field = field.trim();
|
||||
if (type.isEmpty()) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
|
||||
}
|
||||
if (field.isEmpty()) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
|
||||
}
|
||||
Object dest = findService(name, type);
|
||||
Class clazz = dest.getClass();
|
||||
Throwable t = null;
|
||||
try {
|
||||
Field fieldObj = null;
|
||||
do {
|
||||
try {
|
||||
fieldObj = clazz.getDeclaredField(field);
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
if (t == null) {
|
||||
t = e;
|
||||
}
|
||||
}
|
||||
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
||||
if (fieldObj == null) {
|
||||
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t + ")");
|
||||
}
|
||||
fieldObj.setAccessible(true);
|
||||
fieldObj.set(dest, JsonConvert.root().convertFrom(fieldObj.getGenericType(), value));
|
||||
return RetResult.success();
|
||||
} catch (Throwable t2) {
|
||||
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
|
||||
}
|
||||
}
|
||||
@RestConvert(type = void.class)
|
||||
@RestMapping(name = "setField", auth = false, comment = "设置Service中指定字段的内容")
|
||||
public RetResult setField(
|
||||
@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||
@RestParam(name = "field", comment = "字段名") String field,
|
||||
@RestParam(name = "value", comment = "字段值") String value) {
|
||||
if (name == null) {
|
||||
name = "";
|
||||
}
|
||||
if (type == null) {
|
||||
type = "";
|
||||
}
|
||||
if (field == null) {
|
||||
field = "";
|
||||
}
|
||||
type = type.trim();
|
||||
field = field.trim();
|
||||
if (type.isEmpty()) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
|
||||
}
|
||||
if (field.isEmpty()) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
|
||||
}
|
||||
Object dest = findService(name, type);
|
||||
Class clazz = dest.getClass();
|
||||
Throwable t = null;
|
||||
try {
|
||||
Field fieldObj = null;
|
||||
do {
|
||||
try {
|
||||
fieldObj = clazz.getDeclaredField(field);
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
if (t == null) {
|
||||
t = e;
|
||||
}
|
||||
}
|
||||
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
||||
if (fieldObj == null) {
|
||||
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t + ")");
|
||||
}
|
||||
fieldObj.setAccessible(true);
|
||||
fieldObj.set(dest, JsonConvert.root().convertFrom(fieldObj.getGenericType(), value));
|
||||
return RetResult.success();
|
||||
} catch (Throwable t2) {
|
||||
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@RestConvert(type = void.class)
|
||||
@RestMapping(name = "getField", auth = false, comment = "查询Service中指定字段的内容")
|
||||
public RetResult getField(
|
||||
@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||
@RestParam(name = "field", comment = "字段名") String field) {
|
||||
if (name == null) {
|
||||
name = "";
|
||||
}
|
||||
if (type == null) {
|
||||
type = "";
|
||||
}
|
||||
if (field == null) {
|
||||
field = "";
|
||||
}
|
||||
type = type.trim();
|
||||
field = field.trim();
|
||||
if (type.isEmpty()) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
|
||||
}
|
||||
if (field.isEmpty()) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
|
||||
}
|
||||
Object dest = findService(name, type);
|
||||
Class clazz = dest.getClass();
|
||||
Throwable t = null;
|
||||
try {
|
||||
Field fieldObj = null;
|
||||
do {
|
||||
try {
|
||||
fieldObj = clazz.getDeclaredField(field);
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
if (t == null) {
|
||||
t = e;
|
||||
}
|
||||
}
|
||||
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
||||
if (fieldObj == null) {
|
||||
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t + ")");
|
||||
}
|
||||
fieldObj.setAccessible(true);
|
||||
return new RetResult(fieldObj.get(dest));
|
||||
} catch (Throwable t2) {
|
||||
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
|
||||
}
|
||||
}
|
||||
@RestConvert(type = void.class)
|
||||
@RestMapping(name = "getField", auth = false, comment = "查询Service中指定字段的内容")
|
||||
public RetResult getField(
|
||||
@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||
@RestParam(name = "field", comment = "字段名") String field) {
|
||||
if (name == null) {
|
||||
name = "";
|
||||
}
|
||||
if (type == null) {
|
||||
type = "";
|
||||
}
|
||||
if (field == null) {
|
||||
field = "";
|
||||
}
|
||||
type = type.trim();
|
||||
field = field.trim();
|
||||
if (type.isEmpty()) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
|
||||
}
|
||||
if (field.isEmpty()) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
|
||||
}
|
||||
Object dest = findService(name, type);
|
||||
Class clazz = dest.getClass();
|
||||
Throwable t = null;
|
||||
try {
|
||||
Field fieldObj = null;
|
||||
do {
|
||||
try {
|
||||
fieldObj = clazz.getDeclaredField(field);
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
if (t == null) {
|
||||
t = e;
|
||||
}
|
||||
}
|
||||
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
||||
if (fieldObj == null) {
|
||||
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t + ")");
|
||||
}
|
||||
fieldObj.setAccessible(true);
|
||||
return new RetResult(fieldObj.get(dest));
|
||||
} catch (Throwable t2) {
|
||||
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@RestConvert(type = void.class)
|
||||
@RestMapping(name = "runMethod", auth = false, comment = "调用Service中指定方法")
|
||||
public RetResult runMethod(
|
||||
@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||
@RestParam(name = "method", comment = "Service的方法名") String method,
|
||||
@RestParam(name = "params", comment = "方法的参数值") List<String> params,
|
||||
@RestParam(name = "paramtypes", comment = "方法的参数数据类型") List<String> paramtypes) {
|
||||
if (name == null) {
|
||||
name = "";
|
||||
}
|
||||
if (type == null) {
|
||||
type = "";
|
||||
}
|
||||
if (method == null) {
|
||||
method = "";
|
||||
}
|
||||
type = type.trim();
|
||||
method = method.trim();
|
||||
if (type.isEmpty()) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
|
||||
}
|
||||
if (method.isEmpty()) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `method`");
|
||||
}
|
||||
Object dest = findService(name, type);
|
||||
Class clazz = dest.getClass();
|
||||
Throwable t = null;
|
||||
final int paramcount = params == null ? 0 : params.size();
|
||||
if (paramtypes != null && paramcount != paramtypes.size()) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "params.size not equals to paramtypes.size");
|
||||
}
|
||||
try {
|
||||
Method methodObj = null;
|
||||
do {
|
||||
try {
|
||||
for (Method m : clazz.getDeclaredMethods()) {
|
||||
if (m.getName().equals(method) && m.getParameterCount() == paramcount) {
|
||||
boolean flag = true;
|
||||
if (paramtypes != null) {
|
||||
Class[] pts = m.getParameterTypes();
|
||||
for (int i = 0; i < pts.length; i++) {
|
||||
if (!pts[i].getName().endsWith(paramtypes.get(i))) {
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
methodObj = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (methodObj != null) {
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (t == null) {
|
||||
t = e;
|
||||
}
|
||||
}
|
||||
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
||||
if (methodObj == null) {
|
||||
return new RetResult(
|
||||
RET_WATCH_RUN_EXCEPTION,
|
||||
"run exception (" + (t == null ? ("not found method(" + method + ")") : String.valueOf(t))
|
||||
+ ")");
|
||||
}
|
||||
methodObj.setAccessible(true);
|
||||
if (paramcount < 1) {
|
||||
return new RetResult(methodObj.invoke(dest));
|
||||
}
|
||||
Object[] paramObjs = new Object[paramcount];
|
||||
Type[] pts = methodObj.getGenericParameterTypes();
|
||||
for (int i = 0; i < paramObjs.length; i++) {
|
||||
paramObjs[i] = JsonConvert.root().convertFrom(pts[i], params.get(i));
|
||||
}
|
||||
return new RetResult(methodObj.invoke(dest, paramObjs));
|
||||
} catch (Throwable t2) {
|
||||
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
|
||||
}
|
||||
}
|
||||
@RestConvert(type = void.class)
|
||||
@RestMapping(name = "runMethod", auth = false, comment = "调用Service中指定方法")
|
||||
public RetResult runMethod(
|
||||
@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||
@RestParam(name = "method", comment = "Service的方法名") String method,
|
||||
@RestParam(name = "params", comment = "方法的参数值") List<String> params,
|
||||
@RestParam(name = "paramtypes", comment = "方法的参数数据类型") List<String> paramtypes) {
|
||||
if (name == null) {
|
||||
name = "";
|
||||
}
|
||||
if (type == null) {
|
||||
type = "";
|
||||
}
|
||||
if (method == null) {
|
||||
method = "";
|
||||
}
|
||||
type = type.trim();
|
||||
method = method.trim();
|
||||
if (type.isEmpty()) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
|
||||
}
|
||||
if (method.isEmpty()) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `method`");
|
||||
}
|
||||
Object dest = findService(name, type);
|
||||
Class clazz = dest.getClass();
|
||||
Throwable t = null;
|
||||
final int paramcount = params == null ? 0 : params.size();
|
||||
if (paramtypes != null && paramcount != paramtypes.size()) {
|
||||
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "params.size not equals to paramtypes.size");
|
||||
}
|
||||
try {
|
||||
Method methodObj = null;
|
||||
do {
|
||||
try {
|
||||
for (Method m : clazz.getDeclaredMethods()) {
|
||||
if (m.getName().equals(method) && m.getParameterCount() == paramcount) {
|
||||
boolean flag = true;
|
||||
if (paramtypes != null) {
|
||||
Class[] pts = m.getParameterTypes();
|
||||
for (int i = 0; i < pts.length; i++) {
|
||||
if (!pts[i].getName().endsWith(paramtypes.get(i))) {
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
methodObj = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (methodObj != null) {
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (t == null) {
|
||||
t = e;
|
||||
}
|
||||
}
|
||||
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
||||
if (methodObj == null) {
|
||||
return new RetResult(
|
||||
RET_WATCH_RUN_EXCEPTION,
|
||||
"run exception (" + (t == null ? ("not found method(" + method + ")") : String.valueOf(t))
|
||||
+ ")");
|
||||
}
|
||||
methodObj.setAccessible(true);
|
||||
if (paramcount < 1) {
|
||||
return new RetResult(methodObj.invoke(dest));
|
||||
}
|
||||
Object[] paramObjs = new Object[paramcount];
|
||||
Type[] pts = methodObj.getGenericParameterTypes();
|
||||
for (int i = 0; i < paramObjs.length; i++) {
|
||||
paramObjs[i] = JsonConvert.root().convertFrom(pts[i], params.get(i));
|
||||
}
|
||||
return new RetResult(methodObj.invoke(dest, paramObjs));
|
||||
} catch (Throwable t2) {
|
||||
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
protected Object findService(String name, String type) {
|
||||
Object dest = null;
|
||||
for (NodeServer ns : application.getNodeServers()) {
|
||||
ResourceFactory resFactory = ns.getResourceFactory();
|
||||
List list = resFactory.query((n, s) ->
|
||||
name.equals(n) && s != null && s.getClass().getName().endsWith(type));
|
||||
if (list == null || list.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
dest = list.get(0);
|
||||
}
|
||||
if (dest == null) {
|
||||
return new RetResult(
|
||||
RET_SERVICE_DEST_NOT_EXISTS, "not found servie (name=" + name + ", type=" + type + ")");
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
protected Object findService(String name, String type) {
|
||||
Object dest = null;
|
||||
for (NodeServer ns : application.getNodeServers()) {
|
||||
ResourceFactory resFactory = ns.getResourceFactory();
|
||||
List list = resFactory.query((n, s) ->
|
||||
name.equals(n) && s != null && s.getClass().getName().endsWith(type));
|
||||
if (list == null || list.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
dest = list.get(0);
|
||||
}
|
||||
if (dest == null) {
|
||||
return new RetResult(
|
||||
RET_SERVICE_DEST_NOT_EXISTS, "not found servie (name=" + name + ", type=" + type + ")");
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
@RestMapping(name = "loadService", auth = false, comment = "动态增加Service")
|
||||
public RetResult loadService(
|
||||
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameRegx = "\\.jar$") byte[] jar) {
|
||||
// 待开发
|
||||
return RetResult.success();
|
||||
}
|
||||
@RestMapping(name = "loadService", auth = false, comment = "动态增加Service")
|
||||
public RetResult loadService(
|
||||
@RestParam(name = "type", comment = "Service的类名") String type,
|
||||
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameRegx = "\\.jar$") byte[] jar) {
|
||||
// 待开发
|
||||
return RetResult.success();
|
||||
}
|
||||
|
||||
@RestMapping(name = "reloadService", auth = false, comment = "重新加载Service")
|
||||
public RetResult reloadService(
|
||||
@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||
// 待开发
|
||||
return RetResult.success();
|
||||
}
|
||||
@RestMapping(name = "reloadService", auth = false, comment = "重新加载Service")
|
||||
public RetResult reloadService(
|
||||
@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||
// 待开发
|
||||
return RetResult.success();
|
||||
}
|
||||
|
||||
@RestMapping(name = "stopService", auth = false, comment = "动态停止Service")
|
||||
public RetResult stopService(
|
||||
@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||
// 待开发
|
||||
return RetResult.success();
|
||||
}
|
||||
@RestMapping(name = "stopService", auth = false, comment = "动态停止Service")
|
||||
public RetResult stopService(
|
||||
@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||
// 待开发
|
||||
return RetResult.success();
|
||||
}
|
||||
|
||||
@RestMapping(name = "findService", auth = false, comment = "查找Service")
|
||||
public RetResult find(
|
||||
@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||
// 待开发
|
||||
return RetResult.success();
|
||||
}
|
||||
@RestMapping(name = "findService", auth = false, comment = "查找Service")
|
||||
public RetResult find(
|
||||
@RestParam(name = "name", comment = "Service的资源名") String name,
|
||||
@RestParam(name = "type", comment = "Service的类名") String type) {
|
||||
// 待开发
|
||||
return RetResult.success();
|
||||
}
|
||||
}
|
||||
|
||||
1518
src/main/java/org/redkale/cache/CacheManager.java
vendored
1518
src/main/java/org/redkale/cache/CacheManager.java
vendored
File diff suppressed because it is too large
Load Diff
104
src/main/java/org/redkale/cache/Cached.java
vendored
104
src/main/java/org/redkale/cache/Cached.java
vendored
@@ -23,63 +23,63 @@ import org.redkale.service.LoadMode;
|
||||
@Retention(RUNTIME)
|
||||
public @interface Cached {
|
||||
|
||||
/**
|
||||
* 缓存的key,支持参数动态组合,比如"key_#{id}"
|
||||
*
|
||||
* @return 键
|
||||
*/
|
||||
String key();
|
||||
/**
|
||||
* 缓存的key,支持参数动态组合,比如"key_#{id}"
|
||||
*
|
||||
* @return 键
|
||||
*/
|
||||
String key();
|
||||
|
||||
/**
|
||||
* 缓存的hash, 不能含有':'、'#'、'@'字符
|
||||
*
|
||||
* @return hash
|
||||
*/
|
||||
String hash() default CacheManager.DEFAULT_HASH;
|
||||
/**
|
||||
* 缓存的hash, 不能含有':'、'#'、'@'字符
|
||||
*
|
||||
* @return hash
|
||||
*/
|
||||
String hash() default CacheManager.DEFAULT_HASH;
|
||||
|
||||
/**
|
||||
* 本地缓存过期时长, 0表示永不过期, -1表示不作本地缓存。<br>
|
||||
* 参数值支持方式:<br>
|
||||
* 100: 设置数值 ${env.cache.expires}: 读取系统配置项
|
||||
*
|
||||
* @return 过期时长
|
||||
*/
|
||||
String localExpire() default "-1";
|
||||
/**
|
||||
* 本地缓存过期时长, 0表示永不过期, -1表示不作本地缓存。<br>
|
||||
* 参数值支持方式:<br>
|
||||
* 100: 设置数值 ${env.cache.expires}: 读取系统配置项
|
||||
*
|
||||
* @return 过期时长
|
||||
*/
|
||||
String localExpire() default "-1";
|
||||
|
||||
/**
|
||||
* 远程缓存过期时长, 0表示永不过期, -1表示不作远程缓存。<br>
|
||||
* 参数值支持方式:<br>
|
||||
* 100: 设置数值 ${env.cache.expires}: 读取系统配置项
|
||||
*
|
||||
* @return 过期时长
|
||||
*/
|
||||
String remoteExpire() default "-1";
|
||||
/**
|
||||
* 远程缓存过期时长, 0表示永不过期, -1表示不作远程缓存。<br>
|
||||
* 参数值支持方式:<br>
|
||||
* 100: 设置数值 ${env.cache.expires}: 读取系统配置项
|
||||
*
|
||||
* @return 过期时长
|
||||
*/
|
||||
String remoteExpire() default "-1";
|
||||
|
||||
/**
|
||||
* 是否可以缓存null值
|
||||
*
|
||||
* @return 是否可以缓存null
|
||||
*/
|
||||
boolean nullable() default false;
|
||||
/**
|
||||
* 是否可以缓存null值
|
||||
*
|
||||
* @return 是否可以缓存null
|
||||
*/
|
||||
boolean nullable() default false;
|
||||
|
||||
/**
|
||||
* 过期时长的时间单位
|
||||
*
|
||||
* @return 时间单位
|
||||
*/
|
||||
TimeUnit timeUnit() default TimeUnit.SECONDS;
|
||||
/**
|
||||
* 过期时长的时间单位
|
||||
*
|
||||
* @return 时间单位
|
||||
*/
|
||||
TimeUnit timeUnit() default TimeUnit.SECONDS;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*
|
||||
* @return 备注
|
||||
*/
|
||||
String comment() default "";
|
||||
/**
|
||||
* 备注
|
||||
*
|
||||
* @return 备注
|
||||
*/
|
||||
String comment() default "";
|
||||
|
||||
/**
|
||||
* Service加载模式
|
||||
*
|
||||
* @return 模式
|
||||
*/
|
||||
LoadMode mode() default LoadMode.ANY;
|
||||
/**
|
||||
* Service加载模式
|
||||
*
|
||||
* @return 模式
|
||||
*/
|
||||
LoadMode mode() default LoadMode.ANY;
|
||||
}
|
||||
|
||||
210
src/main/java/org/redkale/cache/spi/CacheAction.java
vendored
210
src/main/java/org/redkale/cache/spi/CacheAction.java
vendored
@@ -29,128 +29,128 @@ import org.redkale.util.TypeToken;
|
||||
@ClassDepends
|
||||
public class CacheAction {
|
||||
|
||||
@Resource
|
||||
private Environment environment;
|
||||
@Resource
|
||||
private Environment environment;
|
||||
|
||||
@Resource
|
||||
private CacheManager manager;
|
||||
@Resource
|
||||
private CacheManager manager;
|
||||
|
||||
private final CacheEntry cached;
|
||||
private final CacheEntry cached;
|
||||
|
||||
// Supplier对象的类型
|
||||
private final Type resultType;
|
||||
// Supplier对象的类型
|
||||
private final Type resultType;
|
||||
|
||||
// 缓存方法是否异步
|
||||
private final boolean async;
|
||||
// 缓存方法是否异步
|
||||
private final boolean async;
|
||||
|
||||
// 是否可以缓存null
|
||||
private final boolean nullable;
|
||||
// 是否可以缓存null
|
||||
private final boolean nullable;
|
||||
|
||||
// 宿主对象的类
|
||||
private final Class serviceClass;
|
||||
// 宿主对象的类
|
||||
private final Class serviceClass;
|
||||
|
||||
// 无法获取动态的Method,只能存方法名
|
||||
private final String methodName;
|
||||
// 无法获取动态的Method,只能存方法名
|
||||
private final String methodName;
|
||||
|
||||
// 获取动态的字段名
|
||||
private final String fieldName;
|
||||
// 获取动态的字段名
|
||||
private final String fieldName;
|
||||
|
||||
// 方法参数类型
|
||||
@Nullable
|
||||
private final Class[] paramTypes;
|
||||
// 方法参数类型
|
||||
@Nullable
|
||||
private final Class[] paramTypes;
|
||||
|
||||
// 方法参数名
|
||||
@Nullable
|
||||
private final String[] paramNames;
|
||||
// 方法参数名
|
||||
@Nullable
|
||||
private final String[] paramNames;
|
||||
|
||||
// 缓存的hash
|
||||
private String hash;
|
||||
// 缓存的hash
|
||||
private String hash;
|
||||
|
||||
// 缓存的key
|
||||
private MultiHashKey dynKey;
|
||||
// 缓存的key
|
||||
private MultiHashKey dynKey;
|
||||
|
||||
// 本地缓存过期时长,Duration.ZERO为永不过期,为null表示不本地缓存
|
||||
private Duration localExpire;
|
||||
// 本地缓存过期时长,Duration.ZERO为永不过期,为null表示不本地缓存
|
||||
private Duration localExpire;
|
||||
|
||||
// 远程缓存过期时长,Duration.ZERO为永不过期,为null表示不远程缓存
|
||||
private Duration remoteExpire;
|
||||
// 远程缓存过期时长,Duration.ZERO为永不过期,为null表示不远程缓存
|
||||
private Duration remoteExpire;
|
||||
|
||||
CacheAction(
|
||||
CacheEntry cached,
|
||||
Type returnType,
|
||||
Class serviceClass,
|
||||
Class[] paramTypes,
|
||||
String[] paramNames,
|
||||
String methodName,
|
||||
String fieldName) {
|
||||
this.cached = cached;
|
||||
this.nullable = cached.isNullable();
|
||||
this.serviceClass = Objects.requireNonNull(serviceClass);
|
||||
this.paramTypes = paramTypes;
|
||||
this.paramNames = paramNames;
|
||||
this.methodName = Objects.requireNonNull(methodName);
|
||||
this.fieldName = Objects.requireNonNull(fieldName);
|
||||
this.async = CompletableFuture.class.isAssignableFrom(TypeToken.typeToClass(returnType));
|
||||
this.resultType = this.async ? ((ParameterizedType) returnType).getActualTypeArguments()[0] : returnType;
|
||||
}
|
||||
CacheAction(
|
||||
CacheEntry cached,
|
||||
Type returnType,
|
||||
Class serviceClass,
|
||||
Class[] paramTypes,
|
||||
String[] paramNames,
|
||||
String methodName,
|
||||
String fieldName) {
|
||||
this.cached = cached;
|
||||
this.nullable = cached.isNullable();
|
||||
this.serviceClass = Objects.requireNonNull(serviceClass);
|
||||
this.paramTypes = paramTypes;
|
||||
this.paramNames = paramNames;
|
||||
this.methodName = Objects.requireNonNull(methodName);
|
||||
this.fieldName = Objects.requireNonNull(fieldName);
|
||||
this.async = CompletableFuture.class.isAssignableFrom(TypeToken.typeToClass(returnType));
|
||||
this.resultType = this.async ? ((ParameterizedType) returnType).getActualTypeArguments()[0] : returnType;
|
||||
}
|
||||
|
||||
void init() {
|
||||
this.hash = cached.getHash().trim().isEmpty() || CacheManager.DEFAULT_HASH.equals(cached.getHash())
|
||||
? CacheManager.DEFAULT_HASH
|
||||
: environment.getPropertyValue(cached.getHash());
|
||||
String key = environment.getPropertyValue(cached.getKey());
|
||||
this.dynKey = MultiHashKey.create(paramNames, key);
|
||||
this.localExpire = createDuration(cached.getLocalExpire());
|
||||
this.remoteExpire = createDuration(cached.getRemoteExpire());
|
||||
}
|
||||
void init() {
|
||||
this.hash = cached.getHash().trim().isEmpty() || CacheManager.DEFAULT_HASH.equals(cached.getHash())
|
||||
? CacheManager.DEFAULT_HASH
|
||||
: environment.getPropertyValue(cached.getHash());
|
||||
String key = environment.getPropertyValue(cached.getKey());
|
||||
this.dynKey = MultiHashKey.create(paramNames, key);
|
||||
this.localExpire = createDuration(cached.getLocalExpire());
|
||||
this.remoteExpire = createDuration(cached.getRemoteExpire());
|
||||
}
|
||||
|
||||
@ClassDepends
|
||||
public <T> T get(ThrowSupplier<T> supplier, Object... args) {
|
||||
if (async) {
|
||||
ThrowSupplier supplier0 = supplier;
|
||||
return (T) manager.bothGetSetAsync(
|
||||
hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier0);
|
||||
} else {
|
||||
return manager.bothGetSet(
|
||||
hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier);
|
||||
}
|
||||
}
|
||||
@ClassDepends
|
||||
public <T> T get(ThrowSupplier<T> supplier, Object... args) {
|
||||
if (async) {
|
||||
ThrowSupplier supplier0 = supplier;
|
||||
return (T) manager.bothGetSetAsync(
|
||||
hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier0);
|
||||
} else {
|
||||
return manager.bothGetSet(
|
||||
hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier);
|
||||
}
|
||||
}
|
||||
|
||||
private Duration createDuration(String val) {
|
||||
String str = environment.getPropertyValue(val);
|
||||
if ("-1".equals(str) || "null".equalsIgnoreCase(str)) {
|
||||
return null;
|
||||
} else if ("0".equals(str)) {
|
||||
return Duration.ZERO;
|
||||
} else if (str.indexOf('*') > -1) {
|
||||
long rs = 1;
|
||||
for (String v : str.split("\\*")) {
|
||||
if (!v.trim().isEmpty()) {
|
||||
rs *= Long.parseLong(v.trim());
|
||||
}
|
||||
}
|
||||
if (rs < 0) {
|
||||
return null;
|
||||
} else if (rs == 0) {
|
||||
return Duration.ZERO;
|
||||
} else {
|
||||
return Duration.ofMillis(cached.getTimeUnit().toMillis(rs));
|
||||
}
|
||||
} else {
|
||||
return Duration.ofMillis(cached.getTimeUnit().toMillis(Long.parseLong(str)));
|
||||
}
|
||||
}
|
||||
private Duration createDuration(String val) {
|
||||
String str = environment.getPropertyValue(val);
|
||||
if ("-1".equals(str) || "null".equalsIgnoreCase(str)) {
|
||||
return null;
|
||||
} else if ("0".equals(str)) {
|
||||
return Duration.ZERO;
|
||||
} else if (str.indexOf('*') > -1) {
|
||||
long rs = 1;
|
||||
for (String v : str.split("\\*")) {
|
||||
if (!v.trim().isEmpty()) {
|
||||
rs *= Long.parseLong(v.trim());
|
||||
}
|
||||
}
|
||||
if (rs < 0) {
|
||||
return null;
|
||||
} else if (rs == 0) {
|
||||
return Duration.ZERO;
|
||||
} else {
|
||||
return Duration.ofMillis(cached.getTimeUnit().toMillis(rs));
|
||||
}
|
||||
} else {
|
||||
return Duration.ofMillis(cached.getTimeUnit().toMillis(Long.parseLong(str)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{"
|
||||
+ "\"serviceClass\":" + serviceClass.getName()
|
||||
+ ",\"methodName\":\"" + methodName + "\""
|
||||
+ ",\"fieldName\":\"" + fieldName + "\""
|
||||
+ ",\"paramTypes\":" + JsonConvert.root().convertTo(paramTypes)
|
||||
+ ",\"paramNames\":" + JsonConvert.root().convertTo(paramNames)
|
||||
+ ",\"resultType\":\"" + resultType + "\""
|
||||
+ ",\"cache\":" + cached
|
||||
+ "}";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{"
|
||||
+ "\"serviceClass\":" + serviceClass.getName()
|
||||
+ ",\"methodName\":\"" + methodName + "\""
|
||||
+ ",\"fieldName\":\"" + fieldName + "\""
|
||||
+ ",\"paramTypes\":" + JsonConvert.root().convertTo(paramTypes)
|
||||
+ ",\"paramNames\":" + JsonConvert.root().convertTo(paramNames)
|
||||
+ ",\"resultType\":\"" + resultType + "\""
|
||||
+ ",\"cache\":" + cached
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,214 +35,214 @@ import org.redkale.util.TypeToken;
|
||||
/** @author zhangjx */
|
||||
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) {
|
||||
super(remote, serviceType);
|
||||
}
|
||||
public CacheAsmMethodBoost(boolean remote, Class serviceType) {
|
||||
super(remote, serviceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Annotation>> filterMethodAnnotations(Method method) {
|
||||
return FILTER_ANN;
|
||||
}
|
||||
@Override
|
||||
public List<Class<? extends Annotation>> filterMethodAnnotations(Method method) {
|
||||
return FILTER_ANN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String doMethod(
|
||||
ClassLoader classLoader,
|
||||
ClassWriter cw,
|
||||
String newDynName,
|
||||
String fieldPrefix,
|
||||
List filterAnns,
|
||||
Method method,
|
||||
final String newMethodName) {
|
||||
Map<String, CacheAction> actions = this.actionMap;
|
||||
if (actions == null) {
|
||||
actions = new LinkedHashMap<>();
|
||||
this.actionMap = actions;
|
||||
}
|
||||
Cached cached = method.getAnnotation(Cached.class);
|
||||
if (cached == null) {
|
||||
return newMethodName;
|
||||
}
|
||||
if (!LoadMode.matches(remote, cached.mode())) {
|
||||
return newMethodName;
|
||||
}
|
||||
if (method.getAnnotation(DynForCache.class) != null) {
|
||||
return newMethodName;
|
||||
}
|
||||
if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) {
|
||||
throw new RedkaleException(
|
||||
"@" + Cached.class.getSimpleName() + " cannot on final or static method, but on " + method);
|
||||
}
|
||||
if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) {
|
||||
throw new RedkaleException(
|
||||
"@" + Cached.class.getSimpleName() + " must on protected or public method, but on " + method);
|
||||
}
|
||||
if (method.getReturnType() == void.class || FUTURE_VOID.equals(method.getGenericReturnType())) {
|
||||
throw new RedkaleException("@" + Cached.class.getSimpleName() + " cannot on void method, but on " + method);
|
||||
}
|
||||
final int actionIndex = fieldIndex.incrementAndGet();
|
||||
final String rsMethodName = method.getName() + "_afterCache";
|
||||
final String dynFieldName = fieldPrefix + "_" + method.getName() + "CacheAction" + actionIndex;
|
||||
final AsmMethodBean methodBean = getMethodBean(method);
|
||||
{ // 定义一个新方法调用 this.rsMethodName
|
||||
final String cacheDynDesc = Type.getDescriptor(DynForCache.class);
|
||||
final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean);
|
||||
// mv.setDebug(true);
|
||||
AnnotationVisitor av = mv.visitAnnotation(cacheDynDesc, true);
|
||||
av.visit("dynField", dynFieldName);
|
||||
Asms.visitAnnotation(av, cached);
|
||||
visitRawAnnotation(method, newMethodName, mv, Cached.class, filterAnns);
|
||||
@Override
|
||||
public String doMethod(
|
||||
ClassLoader classLoader,
|
||||
ClassWriter cw,
|
||||
String newDynName,
|
||||
String fieldPrefix,
|
||||
List filterAnns,
|
||||
Method method,
|
||||
final String newMethodName) {
|
||||
Map<String, CacheAction> actions = this.actionMap;
|
||||
if (actions == null) {
|
||||
actions = new LinkedHashMap<>();
|
||||
this.actionMap = actions;
|
||||
}
|
||||
Cached cached = method.getAnnotation(Cached.class);
|
||||
if (cached == null) {
|
||||
return newMethodName;
|
||||
}
|
||||
if (!LoadMode.matches(remote, cached.mode())) {
|
||||
return newMethodName;
|
||||
}
|
||||
if (method.getAnnotation(DynForCache.class) != null) {
|
||||
return newMethodName;
|
||||
}
|
||||
if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) {
|
||||
throw new RedkaleException(
|
||||
"@" + Cached.class.getSimpleName() + " cannot on final or static method, but on " + method);
|
||||
}
|
||||
if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) {
|
||||
throw new RedkaleException(
|
||||
"@" + Cached.class.getSimpleName() + " must on protected or public method, but on " + method);
|
||||
}
|
||||
if (method.getReturnType() == void.class || FUTURE_VOID.equals(method.getGenericReturnType())) {
|
||||
throw new RedkaleException("@" + Cached.class.getSimpleName() + " cannot on void method, but on " + method);
|
||||
}
|
||||
final int actionIndex = fieldIndex.incrementAndGet();
|
||||
final String rsMethodName = method.getName() + "_afterCache";
|
||||
final String dynFieldName = fieldPrefix + "_" + method.getName() + "CacheAction" + actionIndex;
|
||||
final AsmMethodBean methodBean = getMethodBean(method);
|
||||
{ // 定义一个新方法调用 this.rsMethodName
|
||||
final String cacheDynDesc = Type.getDescriptor(DynForCache.class);
|
||||
final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean);
|
||||
// mv.setDebug(true);
|
||||
AnnotationVisitor av = mv.visitAnnotation(cacheDynDesc, true);
|
||||
av.visit("dynField", dynFieldName);
|
||||
Asms.visitAnnotation(av, cached);
|
||||
visitRawAnnotation(method, newMethodName, mv, Cached.class, filterAnns);
|
||||
|
||||
Label l0 = new Label();
|
||||
mv.visitLabel(l0);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
List<Integer> insns = visitVarInsnParamTypes(mv, method, 0);
|
||||
String dynDesc = methodBean.getDesc();
|
||||
dynDesc = "(L" + newDynName + ";" + dynDesc.substring(1, dynDesc.lastIndexOf(')') + 1)
|
||||
+ Type.getDescriptor(ThrowSupplier.class);
|
||||
mv.visitInvokeDynamicInsn("get", dynDesc, Asms.createLambdaMetaHandle(), new Object[] {
|
||||
org.redkale.asm.Type.getType("()Ljava/lang/Object;"),
|
||||
new Handle(Opcodes.H_INVOKESPECIAL, newDynName, "lambda$" + actionIndex, methodBean.getDesc(), false),
|
||||
org.redkale.asm.Type.getType("()" + Type.getDescriptor(method.getReturnType()))
|
||||
});
|
||||
mv.visitVarInsn(ASTORE, 1 + method.getParameterCount());
|
||||
Label l1 = new Label();
|
||||
mv.visitLabel(l1);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, dynFieldName, Type.getDescriptor(CacheAction.class));
|
||||
Label l0 = new Label();
|
||||
mv.visitLabel(l0);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
List<Integer> insns = visitVarInsnParamTypes(mv, method, 0);
|
||||
String dynDesc = methodBean.getDesc();
|
||||
dynDesc = "(L" + newDynName + ";" + dynDesc.substring(1, dynDesc.lastIndexOf(')') + 1)
|
||||
+ Type.getDescriptor(ThrowSupplier.class);
|
||||
mv.visitInvokeDynamicInsn("get", dynDesc, Asms.createLambdaMetaHandle(), new Object[] {
|
||||
org.redkale.asm.Type.getType("()Ljava/lang/Object;"),
|
||||
new Handle(Opcodes.H_INVOKESPECIAL, newDynName, "lambda$" + actionIndex, methodBean.getDesc(), false),
|
||||
org.redkale.asm.Type.getType("()" + Type.getDescriptor(method.getReturnType()))
|
||||
});
|
||||
mv.visitVarInsn(ASTORE, 1 + method.getParameterCount());
|
||||
Label l1 = new Label();
|
||||
mv.visitLabel(l1);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, dynFieldName, Type.getDescriptor(CacheAction.class));
|
||||
|
||||
mv.visitVarInsn(ALOAD, 1 + method.getParameterCount());
|
||||
Asms.visitInsn(mv, method.getParameterCount());
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
|
||||
int insn = 0;
|
||||
Class[] paramtypes = method.getParameterTypes();
|
||||
for (int j = 0; j < paramtypes.length; j++) {
|
||||
final Class pt = paramtypes[j];
|
||||
mv.visitInsn(DUP);
|
||||
insn++;
|
||||
Asms.visitInsn(mv, j);
|
||||
if (pt.isPrimitive()) {
|
||||
if (pt == long.class) {
|
||||
mv.visitVarInsn(LLOAD, insn++);
|
||||
} else if (pt == float.class) {
|
||||
mv.visitVarInsn(FLOAD, insn++);
|
||||
} else if (pt == double.class) {
|
||||
mv.visitVarInsn(DLOAD, insn++);
|
||||
} else {
|
||||
mv.visitVarInsn(ILOAD, insn);
|
||||
}
|
||||
Class bigclaz = TypeToken.primitiveToWrapper(pt);
|
||||
mv.visitMethodInsn(
|
||||
INVOKESTATIC,
|
||||
bigclaz.getName().replace('.', '/'),
|
||||
"valueOf",
|
||||
"(" + Type.getDescriptor((Class) pt) + ")" + Type.getDescriptor(bigclaz),
|
||||
false);
|
||||
} else {
|
||||
mv.visitVarInsn(ALOAD, insn);
|
||||
}
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
String throwFuncDesc = Type.getDescriptor(ThrowSupplier.class);
|
||||
mv.visitMethodInsn(
|
||||
INVOKEVIRTUAL,
|
||||
CacheAction.class.getName().replace('.', '/'),
|
||||
"get",
|
||||
"(" + throwFuncDesc + "[Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
false);
|
||||
mv.visitTypeInsn(CHECKCAST, method.getReturnType().getName().replace('.', '/'));
|
||||
mv.visitInsn(ARETURN);
|
||||
Label l2 = new Label();
|
||||
mv.visitLabel(l2);
|
||||
mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l2, 0);
|
||||
visitParamTypesLocalVariable(mv, method, l0, l2, insns, methodBean);
|
||||
mv.visitLocalVariable("_redkale_supplier", Type.getDescriptor(ThrowSupplier.class), null, l1, l2, ++insn);
|
||||
mv.visitVarInsn(ALOAD, 1 + method.getParameterCount());
|
||||
Asms.visitInsn(mv, method.getParameterCount());
|
||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
|
||||
int insn = 0;
|
||||
Class[] paramtypes = method.getParameterTypes();
|
||||
for (int j = 0; j < paramtypes.length; j++) {
|
||||
final Class pt = paramtypes[j];
|
||||
mv.visitInsn(DUP);
|
||||
insn++;
|
||||
Asms.visitInsn(mv, j);
|
||||
if (pt.isPrimitive()) {
|
||||
if (pt == long.class) {
|
||||
mv.visitVarInsn(LLOAD, insn++);
|
||||
} else if (pt == float.class) {
|
||||
mv.visitVarInsn(FLOAD, insn++);
|
||||
} else if (pt == double.class) {
|
||||
mv.visitVarInsn(DLOAD, insn++);
|
||||
} else {
|
||||
mv.visitVarInsn(ILOAD, insn);
|
||||
}
|
||||
Class bigclaz = TypeToken.primitiveToWrapper(pt);
|
||||
mv.visitMethodInsn(
|
||||
INVOKESTATIC,
|
||||
bigclaz.getName().replace('.', '/'),
|
||||
"valueOf",
|
||||
"(" + Type.getDescriptor((Class) pt) + ")" + Type.getDescriptor(bigclaz),
|
||||
false);
|
||||
} else {
|
||||
mv.visitVarInsn(ALOAD, insn);
|
||||
}
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
String throwFuncDesc = Type.getDescriptor(ThrowSupplier.class);
|
||||
mv.visitMethodInsn(
|
||||
INVOKEVIRTUAL,
|
||||
CacheAction.class.getName().replace('.', '/'),
|
||||
"get",
|
||||
"(" + throwFuncDesc + "[Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
false);
|
||||
mv.visitTypeInsn(CHECKCAST, method.getReturnType().getName().replace('.', '/'));
|
||||
mv.visitInsn(ARETURN);
|
||||
Label l2 = new Label();
|
||||
mv.visitLabel(l2);
|
||||
mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l2, 0);
|
||||
visitParamTypesLocalVariable(mv, method, l0, l2, insns, methodBean);
|
||||
mv.visitLocalVariable("_redkale_supplier", Type.getDescriptor(ThrowSupplier.class), null, l1, l2, ++insn);
|
||||
|
||||
mv.visitMaxs(20, 20);
|
||||
mv.visitEnd();
|
||||
CacheAction action = new CacheAction(
|
||||
new CacheEntry(cached),
|
||||
method.getGenericReturnType(),
|
||||
serviceType,
|
||||
method.getParameterTypes(),
|
||||
methodBean.fieldNameArray(),
|
||||
method.getName(),
|
||||
dynFieldName);
|
||||
actions.put(dynFieldName, action);
|
||||
}
|
||||
{ // ThrowSupplier
|
||||
final MethodVisitor mv = cw.visitMethod(
|
||||
ACC_PRIVATE + ACC_SYNTHETIC, "lambda$" + actionIndex, methodBean.getDesc(), null, new String[] {
|
||||
"java/lang/Throwable"
|
||||
});
|
||||
// mv.setDebug(true);
|
||||
Label l0 = new Label();
|
||||
mv.visitLabel(l0);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
visitVarInsnParamTypes(mv, method, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, methodBean.getDesc(), false);
|
||||
mv.visitInsn(ARETURN);
|
||||
Label l1 = new Label();
|
||||
mv.visitLabel(l1);
|
||||
mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l1, 0);
|
||||
mv.visitMaxs(5, 5);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{ // 定义字段
|
||||
FieldVisitor fv =
|
||||
cw.visitField(ACC_PRIVATE, dynFieldName, Type.getDescriptor(CacheAction.class), null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
if (actions.size() == 1) {
|
||||
cw.visitInnerClass(
|
||||
"java/lang/invoke/MethodHandles$Lookup",
|
||||
"java/lang/invoke/MethodHandles",
|
||||
"Lookup",
|
||||
ACC_PUBLIC + ACC_FINAL + ACC_STATIC);
|
||||
}
|
||||
return rsMethodName;
|
||||
}
|
||||
mv.visitMaxs(20, 20);
|
||||
mv.visitEnd();
|
||||
CacheAction action = new CacheAction(
|
||||
new CacheEntry(cached),
|
||||
method.getGenericReturnType(),
|
||||
serviceType,
|
||||
method.getParameterTypes(),
|
||||
methodBean.fieldNameArray(),
|
||||
method.getName(),
|
||||
dynFieldName);
|
||||
actions.put(dynFieldName, action);
|
||||
}
|
||||
{ // ThrowSupplier
|
||||
final MethodVisitor mv = cw.visitMethod(
|
||||
ACC_PRIVATE + ACC_SYNTHETIC, "lambda$" + actionIndex, methodBean.getDesc(), null, new String[] {
|
||||
"java/lang/Throwable"
|
||||
});
|
||||
// mv.setDebug(true);
|
||||
Label l0 = new Label();
|
||||
mv.visitLabel(l0);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
visitVarInsnParamTypes(mv, method, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, methodBean.getDesc(), false);
|
||||
mv.visitInsn(ARETURN);
|
||||
Label l1 = new Label();
|
||||
mv.visitLabel(l1);
|
||||
mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l1, 0);
|
||||
mv.visitMaxs(5, 5);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{ // 定义字段
|
||||
FieldVisitor fv =
|
||||
cw.visitField(ACC_PRIVATE, dynFieldName, Type.getDescriptor(CacheAction.class), null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
if (actions.size() == 1) {
|
||||
cw.visitInnerClass(
|
||||
"java/lang/invoke/MethodHandles$Lookup",
|
||||
"java/lang/invoke/MethodHandles",
|
||||
"Lookup",
|
||||
ACC_PUBLIC + ACC_FINAL + ACC_STATIC);
|
||||
}
|
||||
return rsMethodName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doInstance(ResourceFactory resourceFactory, Object service) {
|
||||
Class clazz = service.getClass();
|
||||
if (actionMap == null) { // 为null表示没有调用过doMethod, 动态类在编译是已经生成好了
|
||||
actionMap = new LinkedHashMap<>();
|
||||
Map<String, AsmMethodBean> methodBeans = AsmMethodBoost.getMethodBeans(clazz);
|
||||
for (final Method method : clazz.getDeclaredMethods()) {
|
||||
DynForCache cached = method.getAnnotation(DynForCache.class);
|
||||
if (cached != null) {
|
||||
String dynFieldName = cached.dynField();
|
||||
AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method);
|
||||
CacheAction action = new CacheAction(
|
||||
new CacheEntry(cached),
|
||||
method.getGenericReturnType(),
|
||||
serviceType,
|
||||
method.getParameterTypes(),
|
||||
methodBean.fieldNameArray(),
|
||||
method.getName(),
|
||||
dynFieldName);
|
||||
actionMap.put(dynFieldName, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
actionMap.forEach((field, action) -> {
|
||||
try {
|
||||
Field c = clazz.getDeclaredField(field);
|
||||
c.setAccessible(true);
|
||||
resourceFactory.inject(action);
|
||||
action.init();
|
||||
c.set(service, action);
|
||||
RedkaleClassLoader.putReflectionField(clazz.getName(), c);
|
||||
} catch (Exception e) {
|
||||
throw new RedkaleException("field (" + field + ") in " + clazz.getName() + " set error", e);
|
||||
}
|
||||
});
|
||||
// do nothing
|
||||
}
|
||||
@Override
|
||||
public void doInstance(ResourceFactory resourceFactory, Object service) {
|
||||
Class clazz = service.getClass();
|
||||
if (actionMap == null) { // 为null表示没有调用过doMethod, 动态类在编译是已经生成好了
|
||||
actionMap = new LinkedHashMap<>();
|
||||
Map<String, AsmMethodBean> methodBeans = AsmMethodBoost.getMethodBeans(clazz);
|
||||
for (final Method method : clazz.getDeclaredMethods()) {
|
||||
DynForCache cached = method.getAnnotation(DynForCache.class);
|
||||
if (cached != null) {
|
||||
String dynFieldName = cached.dynField();
|
||||
AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method);
|
||||
CacheAction action = new CacheAction(
|
||||
new CacheEntry(cached),
|
||||
method.getGenericReturnType(),
|
||||
serviceType,
|
||||
method.getParameterTypes(),
|
||||
methodBean.fieldNameArray(),
|
||||
method.getName(),
|
||||
dynFieldName);
|
||||
actionMap.put(dynFieldName, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
actionMap.forEach((field, action) -> {
|
||||
try {
|
||||
Field c = clazz.getDeclaredField(field);
|
||||
c.setAccessible(true);
|
||||
resourceFactory.inject(action);
|
||||
action.init();
|
||||
c.set(service, action);
|
||||
RedkaleClassLoader.putReflectionField(clazz.getName(), c);
|
||||
} catch (Exception e) {
|
||||
throw new RedkaleException("field (" + field + ") in " + clazz.getName() + " set error", e);
|
||||
}
|
||||
});
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
126
src/main/java/org/redkale/cache/spi/CacheEntry.java
vendored
126
src/main/java/org/redkale/cache/spi/CacheEntry.java
vendored
@@ -10,88 +10,88 @@ import org.redkale.convert.json.JsonConvert;
|
||||
/** @author zhangjx */
|
||||
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) {
|
||||
this.key = cached.key();
|
||||
this.hash = cached.hash();
|
||||
this.localExpire = cached.localExpire();
|
||||
this.remoteExpire = cached.remoteExpire();
|
||||
this.timeUnit = cached.timeUnit();
|
||||
this.nullable = cached.nullable();
|
||||
}
|
||||
public CacheEntry(DynForCache cached) {
|
||||
this.key = cached.key();
|
||||
this.hash = cached.hash();
|
||||
this.localExpire = cached.localExpire();
|
||||
this.remoteExpire = cached.remoteExpire();
|
||||
this.timeUnit = cached.timeUnit();
|
||||
this.nullable = cached.nullable();
|
||||
}
|
||||
|
||||
public CacheEntry(Cached cached) {
|
||||
this.key = cached.key();
|
||||
this.hash = cached.hash();
|
||||
this.localExpire = cached.localExpire();
|
||||
this.remoteExpire = cached.remoteExpire();
|
||||
this.timeUnit = cached.timeUnit();
|
||||
this.nullable = cached.nullable();
|
||||
}
|
||||
public CacheEntry(Cached cached) {
|
||||
this.key = cached.key();
|
||||
this.hash = cached.hash();
|
||||
this.localExpire = cached.localExpire();
|
||||
this.remoteExpire = cached.remoteExpire();
|
||||
this.timeUnit = cached.timeUnit();
|
||||
this.nullable = cached.nullable();
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getHash() {
|
||||
return hash;
|
||||
}
|
||||
public String getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
public void setHash(String hash) {
|
||||
this.hash = hash;
|
||||
}
|
||||
public void setHash(String hash) {
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
public String getLocalExpire() {
|
||||
return localExpire;
|
||||
}
|
||||
public String getLocalExpire() {
|
||||
return localExpire;
|
||||
}
|
||||
|
||||
public void setLocalExpire(String localExpire) {
|
||||
this.localExpire = localExpire;
|
||||
}
|
||||
public void setLocalExpire(String localExpire) {
|
||||
this.localExpire = localExpire;
|
||||
}
|
||||
|
||||
public String getRemoteExpire() {
|
||||
return remoteExpire;
|
||||
}
|
||||
public String getRemoteExpire() {
|
||||
return remoteExpire;
|
||||
}
|
||||
|
||||
public void setRemoteExpire(String remoteExpire) {
|
||||
this.remoteExpire = remoteExpire;
|
||||
}
|
||||
public void setRemoteExpire(String remoteExpire) {
|
||||
this.remoteExpire = remoteExpire;
|
||||
}
|
||||
|
||||
public TimeUnit getTimeUnit() {
|
||||
return timeUnit;
|
||||
}
|
||||
public TimeUnit getTimeUnit() {
|
||||
return timeUnit;
|
||||
}
|
||||
|
||||
public void setTimeUnit(TimeUnit timeUnit) {
|
||||
this.timeUnit = timeUnit;
|
||||
}
|
||||
public void setTimeUnit(TimeUnit timeUnit) {
|
||||
this.timeUnit = timeUnit;
|
||||
}
|
||||
|
||||
public boolean isNullable() {
|
||||
return nullable;
|
||||
}
|
||||
public boolean isNullable() {
|
||||
return nullable;
|
||||
}
|
||||
|
||||
public void setNullable(boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
}
|
||||
public void setNullable(boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,83 +19,83 @@ import org.redkale.util.RedkaleClassLoader;
|
||||
/** @author zhangjx */
|
||||
public class CacheModuleEngine extends ModuleEngine {
|
||||
|
||||
// 全局缓存管理器
|
||||
private CacheManager cacheManager;
|
||||
// 全局缓存管理器
|
||||
private CacheManager cacheManager;
|
||||
|
||||
private AnyValue config;
|
||||
private AnyValue config;
|
||||
|
||||
public CacheModuleEngine(Application application) {
|
||||
super(application);
|
||||
}
|
||||
public CacheModuleEngine(Application application) {
|
||||
super(application);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
|
||||
*
|
||||
* @param path 配置项路径
|
||||
* @param key 配置项名称
|
||||
* @param val1 配置项原值
|
||||
* @param val2 配置项新值
|
||||
* @return MergeEnum
|
||||
*/
|
||||
@Override
|
||||
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
|
||||
if ("".equals(path) && "cache".equals(key)) {
|
||||
return AnyValue.MergeEnum.REPLACE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
|
||||
*
|
||||
* @param path 配置项路径
|
||||
* @param key 配置项名称
|
||||
* @param val1 配置项原值
|
||||
* @param val2 配置项新值
|
||||
* @return MergeEnum
|
||||
*/
|
||||
@Override
|
||||
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
|
||||
if ("".equals(path) && "cache".equals(key)) {
|
||||
return AnyValue.MergeEnum.REPLACE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态扩展类的方法
|
||||
*
|
||||
* @param remote 是否远程模式
|
||||
* @param serviceClass 类
|
||||
* @return 方法动态扩展器
|
||||
*/
|
||||
@Override
|
||||
public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) {
|
||||
return new CacheAsmMethodBoost(remote, serviceClass);
|
||||
}
|
||||
/**
|
||||
* 动态扩展类的方法
|
||||
*
|
||||
* @param remote 是否远程模式
|
||||
* @param serviceClass 类
|
||||
* @return 方法动态扩展器
|
||||
*/
|
||||
@Override
|
||||
public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) {
|
||||
return new CacheAsmMethodBoost(remote, serviceClass);
|
||||
}
|
||||
|
||||
/** 结束Application.init方法前被调用 */
|
||||
@Override
|
||||
public void onAppPostInit() {
|
||||
// 设置缓存管理器
|
||||
this.config = application.getAppConfig().getAnyValue("cache");
|
||||
this.cacheManager = createManager(this.config);
|
||||
if (!application.isCompileMode()) {
|
||||
this.resourceFactory.inject(this.cacheManager);
|
||||
if (this.cacheManager instanceof Service) {
|
||||
((Service) this.cacheManager).init(this.config);
|
||||
}
|
||||
}
|
||||
this.resourceFactory.register("", CacheManager.class, this.cacheManager);
|
||||
}
|
||||
/** 结束Application.init方法前被调用 */
|
||||
@Override
|
||||
public void onAppPostInit() {
|
||||
// 设置缓存管理器
|
||||
this.config = application.getAppConfig().getAnyValue("cache");
|
||||
this.cacheManager = createManager(this.config);
|
||||
if (!application.isCompileMode()) {
|
||||
this.resourceFactory.inject(this.cacheManager);
|
||||
if (this.cacheManager instanceof Service) {
|
||||
((Service) this.cacheManager).init(this.config);
|
||||
}
|
||||
}
|
||||
this.resourceFactory.register("", CacheManager.class, this.cacheManager);
|
||||
}
|
||||
|
||||
/** 进入Application.shutdown方法被调用 */
|
||||
@Override
|
||||
public void onAppPreShutdown() {
|
||||
if (!application.isCompileMode() && this.cacheManager instanceof Service) {
|
||||
((Service) this.cacheManager).destroy(this.config);
|
||||
}
|
||||
}
|
||||
/** 进入Application.shutdown方法被调用 */
|
||||
@Override
|
||||
public void onAppPreShutdown() {
|
||||
if (!application.isCompileMode() && this.cacheManager instanceof Service) {
|
||||
((Service) this.cacheManager).destroy(this.config);
|
||||
}
|
||||
}
|
||||
|
||||
private CacheManager createManager(AnyValue conf) {
|
||||
Iterator<CacheManagerProvider> it = ServiceLoader.load(CacheManagerProvider.class, application.getClassLoader())
|
||||
.iterator();
|
||||
RedkaleClassLoader.putServiceLoader(CacheManagerProvider.class);
|
||||
List<CacheManagerProvider> providers = new ArrayList<>();
|
||||
while (it.hasNext()) {
|
||||
CacheManagerProvider provider = it.next();
|
||||
if (provider != null && provider.acceptsConf(conf)) {
|
||||
RedkaleClassLoader.putReflectionPublicConstructors(
|
||||
provider.getClass(), provider.getClass().getName());
|
||||
providers.add(provider);
|
||||
}
|
||||
}
|
||||
for (CacheManagerProvider provider : InstanceProvider.sort(providers)) {
|
||||
return provider.createInstance();
|
||||
}
|
||||
return CacheManagerService.create(null).enabled(false);
|
||||
}
|
||||
private CacheManager createManager(AnyValue conf) {
|
||||
Iterator<CacheManagerProvider> it = ServiceLoader.load(CacheManagerProvider.class, application.getClassLoader())
|
||||
.iterator();
|
||||
RedkaleClassLoader.putServiceLoader(CacheManagerProvider.class);
|
||||
List<CacheManagerProvider> providers = new ArrayList<>();
|
||||
while (it.hasNext()) {
|
||||
CacheManagerProvider provider = it.next();
|
||||
if (provider != null && provider.acceptsConf(conf)) {
|
||||
RedkaleClassLoader.putReflectionPublicConstructors(
|
||||
provider.getClass(), provider.getClass().getName());
|
||||
providers.add(provider);
|
||||
}
|
||||
}
|
||||
for (CacheManagerProvider provider : InstanceProvider.sort(providers)) {
|
||||
return provider.createInstance();
|
||||
}
|
||||
return CacheManagerService.create(null).enabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,37 +17,37 @@ import org.redkale.convert.json.JsonConvert;
|
||||
*/
|
||||
public class CacheValue<T> {
|
||||
|
||||
@ConvertColumn(index = 1)
|
||||
private T val;
|
||||
@ConvertColumn(index = 1)
|
||||
private T val;
|
||||
|
||||
public CacheValue() {}
|
||||
public CacheValue() {}
|
||||
|
||||
protected CacheValue(T value) {
|
||||
this.val = value;
|
||||
}
|
||||
protected CacheValue(T value) {
|
||||
this.val = value;
|
||||
}
|
||||
|
||||
public static <T> CacheValue<T> create(T value) {
|
||||
return new CacheValue(value);
|
||||
}
|
||||
public static <T> CacheValue<T> create(T value) {
|
||||
return new CacheValue(value);
|
||||
}
|
||||
|
||||
public static boolean isValid(CacheValue val) {
|
||||
return val != null;
|
||||
}
|
||||
public static boolean isValid(CacheValue val) {
|
||||
return val != null;
|
||||
}
|
||||
|
||||
public static <T> T get(CacheValue val) {
|
||||
return isValid(val) ? (T) val.getVal() : null;
|
||||
}
|
||||
public static <T> T get(CacheValue val) {
|
||||
return isValid(val) ? (T) val.getVal() : null;
|
||||
}
|
||||
|
||||
public T getVal() {
|
||||
return val;
|
||||
}
|
||||
public T getVal() {
|
||||
return val;
|
||||
}
|
||||
|
||||
public void setVal(T val) {
|
||||
this.val = val;
|
||||
}
|
||||
public void setVal(T val) {
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,19 +23,19 @@ import org.redkale.service.LoadMode;
|
||||
@Retention(RUNTIME)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -17,19 +17,19 @@ import java.util.concurrent.CompletableFuture;
|
||||
*/
|
||||
public interface ClusterRpcClient<R, P> {
|
||||
|
||||
/**
|
||||
* 发送消息,需要响应
|
||||
*
|
||||
* @param message 消息体
|
||||
* @return 应答消息
|
||||
*/
|
||||
public CompletableFuture<P> sendMessage(final R message);
|
||||
/**
|
||||
* 发送消息,需要响应
|
||||
*
|
||||
* @param message 消息体
|
||||
* @return 应答消息
|
||||
*/
|
||||
public CompletableFuture<P> sendMessage(final R message);
|
||||
|
||||
/**
|
||||
* 发送消息,无需响应
|
||||
*
|
||||
* @param message 消息体
|
||||
* @return 应答
|
||||
*/
|
||||
public CompletableFuture<Void> produceMessage(R message);
|
||||
/**
|
||||
* 发送消息,无需响应
|
||||
*
|
||||
* @param message 消息体
|
||||
* @return 应答
|
||||
*/
|
||||
public CompletableFuture<Void> produceMessage(R message);
|
||||
}
|
||||
|
||||
@@ -22,106 +22,106 @@ import org.redkale.util.RedkaleException;
|
||||
*/
|
||||
public abstract class HttpRpcClient implements ClusterRpcClient<WebRequest, HttpResult<byte[]>> {
|
||||
|
||||
@Override
|
||||
public final CompletableFuture<Void> produceMessage(WebRequest request) {
|
||||
return produceMessage(generateHttpReqTopic(request, null), 0, null, request);
|
||||
}
|
||||
@Override
|
||||
public final CompletableFuture<Void> produceMessage(WebRequest request) {
|
||||
return produceMessage(generateHttpReqTopic(request, null), 0, null, request);
|
||||
}
|
||||
|
||||
public final CompletableFuture<Void> produceMessage(Serializable userid, WebRequest request) {
|
||||
return produceMessage(generateHttpReqTopic(request, null), userid, null, request);
|
||||
}
|
||||
public final CompletableFuture<Void> produceMessage(Serializable userid, WebRequest request) {
|
||||
return produceMessage(generateHttpReqTopic(request, null), userid, null, request);
|
||||
}
|
||||
|
||||
public final CompletableFuture<Void> produceMessage(Serializable userid, String groupid, WebRequest request) {
|
||||
return produceMessage(generateHttpReqTopic(request, null), userid, groupid, request);
|
||||
}
|
||||
public final CompletableFuture<Void> produceMessage(Serializable userid, String groupid, WebRequest request) {
|
||||
return produceMessage(generateHttpReqTopic(request, null), userid, groupid, request);
|
||||
}
|
||||
|
||||
public final CompletableFuture<Void> produceMessage(String topic, WebRequest request) {
|
||||
return produceMessage(topic, 0, null, request);
|
||||
}
|
||||
public final CompletableFuture<Void> produceMessage(String topic, WebRequest request) {
|
||||
return produceMessage(topic, 0, null, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CompletableFuture<HttpResult<byte[]>> sendMessage(WebRequest request) {
|
||||
return sendMessage(generateHttpReqTopic(request, null), 0, null, request);
|
||||
}
|
||||
@Override
|
||||
public final CompletableFuture<HttpResult<byte[]>> sendMessage(WebRequest request) {
|
||||
return sendMessage(generateHttpReqTopic(request, null), 0, null, request);
|
||||
}
|
||||
|
||||
public final CompletableFuture<HttpResult<byte[]>> sendMessage(Serializable userid, WebRequest request) {
|
||||
return sendMessage(generateHttpReqTopic(request, null), userid, null, request);
|
||||
}
|
||||
public final CompletableFuture<HttpResult<byte[]>> sendMessage(Serializable userid, WebRequest request) {
|
||||
return sendMessage(generateHttpReqTopic(request, null), userid, null, request);
|
||||
}
|
||||
|
||||
public final CompletableFuture<HttpResult<byte[]>> sendMessage(
|
||||
Serializable userid, String groupid, WebRequest request) {
|
||||
return sendMessage(generateHttpReqTopic(request, null), userid, groupid, request);
|
||||
}
|
||||
public final CompletableFuture<HttpResult<byte[]>> sendMessage(
|
||||
Serializable userid, String groupid, WebRequest request) {
|
||||
return sendMessage(generateHttpReqTopic(request, null), userid, groupid, request);
|
||||
}
|
||||
|
||||
public final CompletableFuture<HttpResult<byte[]>> sendMessage(String topic, WebRequest request) {
|
||||
return sendMessage(topic, 0, null, request);
|
||||
}
|
||||
public final CompletableFuture<HttpResult<byte[]>> sendMessage(String topic, WebRequest request) {
|
||||
return sendMessage(topic, 0, null, request);
|
||||
}
|
||||
|
||||
public <T> CompletableFuture<T> sendMessage(WebRequest request, Type type) {
|
||||
return sendMessage(generateHttpReqTopic(request, null), 0, null, request)
|
||||
.thenApply((HttpResult<byte[]> httbs) -> {
|
||||
if (!httbs.isSuccess()) {
|
||||
throw new RedkaleException(httbs.getHeader("retinfo", "Internal Server Error"));
|
||||
}
|
||||
if (httbs.getResult() == null) {
|
||||
return null;
|
||||
}
|
||||
return JsonConvert.root().convertFrom(type, httbs.getResult());
|
||||
});
|
||||
}
|
||||
public <T> CompletableFuture<T> sendMessage(WebRequest request, Type type) {
|
||||
return sendMessage(generateHttpReqTopic(request, null), 0, null, request)
|
||||
.thenApply((HttpResult<byte[]> httbs) -> {
|
||||
if (!httbs.isSuccess()) {
|
||||
throw new RedkaleException(httbs.getHeader("retinfo", "Internal Server Error"));
|
||||
}
|
||||
if (httbs.getResult() == null) {
|
||||
return null;
|
||||
}
|
||||
return JsonConvert.root().convertFrom(type, httbs.getResult());
|
||||
});
|
||||
}
|
||||
|
||||
public <T> CompletableFuture<T> sendMessage(Serializable userid, WebRequest request, Type type) {
|
||||
return sendMessage(generateHttpReqTopic(request, null), userid, null, request)
|
||||
.thenApply((HttpResult<byte[]> httbs) -> {
|
||||
if (!httbs.isSuccess()) {
|
||||
throw new RedkaleException(httbs.getHeader("retinfo", "Internal Server Error"));
|
||||
}
|
||||
if (httbs.getResult() == null) {
|
||||
return null;
|
||||
}
|
||||
return JsonConvert.root().convertFrom(type, httbs.getResult());
|
||||
});
|
||||
}
|
||||
public <T> CompletableFuture<T> sendMessage(Serializable userid, WebRequest request, Type type) {
|
||||
return sendMessage(generateHttpReqTopic(request, null), userid, null, request)
|
||||
.thenApply((HttpResult<byte[]> httbs) -> {
|
||||
if (!httbs.isSuccess()) {
|
||||
throw new RedkaleException(httbs.getHeader("retinfo", "Internal Server Error"));
|
||||
}
|
||||
if (httbs.getResult() == null) {
|
||||
return null;
|
||||
}
|
||||
return JsonConvert.root().convertFrom(type, httbs.getResult());
|
||||
});
|
||||
}
|
||||
|
||||
public <T> CompletableFuture<T> sendMessage(Serializable userid, String groupid, WebRequest request, Type type) {
|
||||
return sendMessage(generateHttpReqTopic(request, null), userid, groupid, request)
|
||||
.thenApply((HttpResult<byte[]> httbs) -> {
|
||||
if (!httbs.isSuccess()) {
|
||||
throw new RedkaleException(httbs.getHeader("retinfo", "Internal Server Error"));
|
||||
}
|
||||
if (httbs.getResult() == null) {
|
||||
return null;
|
||||
}
|
||||
return JsonConvert.root().convertFrom(type, httbs.getResult());
|
||||
});
|
||||
}
|
||||
public <T> CompletableFuture<T> sendMessage(Serializable userid, String groupid, WebRequest request, Type type) {
|
||||
return sendMessage(generateHttpReqTopic(request, null), userid, groupid, request)
|
||||
.thenApply((HttpResult<byte[]> httbs) -> {
|
||||
if (!httbs.isSuccess()) {
|
||||
throw new RedkaleException(httbs.getHeader("retinfo", "Internal Server Error"));
|
||||
}
|
||||
if (httbs.getResult() == null) {
|
||||
return null;
|
||||
}
|
||||
return JsonConvert.root().convertFrom(type, httbs.getResult());
|
||||
});
|
||||
}
|
||||
|
||||
// 格式: http.req.user
|
||||
public String generateHttpReqTopic(String module) {
|
||||
return Rest.generateHttpReqTopic(module, getNodeid());
|
||||
}
|
||||
// 格式: http.req.user
|
||||
public String generateHttpReqTopic(String module) {
|
||||
return Rest.generateHttpReqTopic(module, getNodeid());
|
||||
}
|
||||
|
||||
// 格式: http.req.user-n10
|
||||
public String generateHttpReqTopic(String module, String resname) {
|
||||
return Rest.generateHttpReqTopic(module, resname, getNodeid());
|
||||
}
|
||||
// 格式: http.req.user-n10
|
||||
public String generateHttpReqTopic(String module, String resname) {
|
||||
return Rest.generateHttpReqTopic(module, resname, getNodeid());
|
||||
}
|
||||
|
||||
public String generateHttpReqTopic(WebRequest request, String path) {
|
||||
String module = request.getPath();
|
||||
if (path != null && !path.isEmpty() && module.startsWith(path)) {
|
||||
module = module.substring(path.length());
|
||||
}
|
||||
module = module.substring(1); // 去掉/
|
||||
module = module.substring(0, module.indexOf('/'));
|
||||
String resname = request.getHeader(Rest.REST_HEADER_RESNAME, "");
|
||||
return Rest.generateHttpReqTopic(module, resname, getNodeid());
|
||||
}
|
||||
public String generateHttpReqTopic(WebRequest request, String path) {
|
||||
String module = request.getPath();
|
||||
if (path != null && !path.isEmpty() && module.startsWith(path)) {
|
||||
module = module.substring(path.length());
|
||||
}
|
||||
module = module.substring(1); // 去掉/
|
||||
module = module.substring(0, module.indexOf('/'));
|
||||
String resname = request.getHeader(Rest.REST_HEADER_RESNAME, "");
|
||||
return Rest.generateHttpReqTopic(module, resname, getNodeid());
|
||||
}
|
||||
|
||||
public abstract CompletableFuture<HttpResult<byte[]>> sendMessage(
|
||||
String topic, Serializable userid, String groupid, WebRequest request);
|
||||
public abstract CompletableFuture<HttpResult<byte[]>> sendMessage(
|
||||
String topic, Serializable userid, String groupid, WebRequest request);
|
||||
|
||||
public abstract CompletableFuture<Void> produceMessage(
|
||||
String topic, Serializable userid, String groupid, WebRequest request);
|
||||
public abstract CompletableFuture<Void> produceMessage(
|
||||
String topic, Serializable userid, String groupid, WebRequest request);
|
||||
|
||||
protected abstract String getNodeid();
|
||||
protected abstract String getNodeid();
|
||||
}
|
||||
|
||||
@@ -29,376 +29,376 @@ import org.redkale.util.*;
|
||||
*/
|
||||
public class CacheClusterAgent extends ClusterAgent implements Resourcable {
|
||||
|
||||
@Resource(name = Resource.PARENT_NAME)
|
||||
private CacheSource source;
|
||||
@Resource(name = Resource.PARENT_NAME)
|
||||
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
|
||||
protected final ConcurrentHashMap<String, Set<InetSocketAddress>> httpAddressMap = new ConcurrentHashMap<>();
|
||||
// 可能被HttpMessageClient用到的服务 key: serviceName,例如: cluster.service.http.user
|
||||
protected final ConcurrentHashMap<String, Set<InetSocketAddress>> httpAddressMap = new ConcurrentHashMap<>();
|
||||
|
||||
// 可能被sncp用到的服务 key: serviceName, 例如: cluster.service.sncp.user
|
||||
protected final ConcurrentHashMap<String, Set<InetSocketAddress>> sncpAddressMap = new ConcurrentHashMap<>();
|
||||
// 可能被sncp用到的服务 key: serviceName, 例如: cluster.service.sncp.user
|
||||
protected final ConcurrentHashMap<String, Set<InetSocketAddress>> sncpAddressMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void init(AnyValue config) {
|
||||
super.init(config);
|
||||
this.sourceName = getSourceName();
|
||||
this.ttls = config.getIntValue("ttls", 10);
|
||||
if (this.ttls < 5) { // 值不能太小
|
||||
this.ttls = 10;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void init(AnyValue config) {
|
||||
super.init(config);
|
||||
this.sourceName = getSourceName();
|
||||
this.ttls = config.getIntValue("ttls", 10);
|
||||
if (this.ttls < 5) { // 值不能太小
|
||||
this.ttls = 10;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ResourceChanged
|
||||
public void onResourceChange(ResourceEvent[] events) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int newTtls = this.ttls;
|
||||
for (ResourceEvent event : events) {
|
||||
if ("ttls".equals(event.name())) {
|
||||
newTtls = Integer.parseInt(event.newValue().toString());
|
||||
if (newTtls < 5) {
|
||||
sb.append(CacheClusterAgent.class.getSimpleName())
|
||||
.append("(name=")
|
||||
.append(resourceName())
|
||||
.append(") cannot change '")
|
||||
.append(event.name())
|
||||
.append("' to '")
|
||||
.append(event.coverNewValue())
|
||||
.append("'\r\n");
|
||||
} else {
|
||||
sb.append(CacheClusterAgent.class.getSimpleName())
|
||||
.append("(name=")
|
||||
.append(resourceName())
|
||||
.append(") change '")
|
||||
.append(event.name())
|
||||
.append("' to '")
|
||||
.append(event.coverNewValue())
|
||||
.append("'\r\n");
|
||||
}
|
||||
} else {
|
||||
sb.append(CacheClusterAgent.class.getSimpleName())
|
||||
.append("(name=")
|
||||
.append(resourceName())
|
||||
.append(") skip change '")
|
||||
.append(event.name())
|
||||
.append("' to '")
|
||||
.append(event.coverNewValue())
|
||||
.append("'\r\n");
|
||||
}
|
||||
}
|
||||
if (newTtls != this.ttls) {
|
||||
this.ttls = newTtls;
|
||||
start();
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
logger.log(Level.INFO, sb.toString());
|
||||
}
|
||||
}
|
||||
@Override
|
||||
@ResourceChanged
|
||||
public void onResourceChange(ResourceEvent[] events) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int newTtls = this.ttls;
|
||||
for (ResourceEvent event : events) {
|
||||
if ("ttls".equals(event.name())) {
|
||||
newTtls = Integer.parseInt(event.newValue().toString());
|
||||
if (newTtls < 5) {
|
||||
sb.append(CacheClusterAgent.class.getSimpleName())
|
||||
.append("(name=")
|
||||
.append(resourceName())
|
||||
.append(") cannot change '")
|
||||
.append(event.name())
|
||||
.append("' to '")
|
||||
.append(event.coverNewValue())
|
||||
.append("'\r\n");
|
||||
} else {
|
||||
sb.append(CacheClusterAgent.class.getSimpleName())
|
||||
.append("(name=")
|
||||
.append(resourceName())
|
||||
.append(") change '")
|
||||
.append(event.name())
|
||||
.append("' to '")
|
||||
.append(event.coverNewValue())
|
||||
.append("'\r\n");
|
||||
}
|
||||
} else {
|
||||
sb.append(CacheClusterAgent.class.getSimpleName())
|
||||
.append("(name=")
|
||||
.append(resourceName())
|
||||
.append(") skip change '")
|
||||
.append(event.name())
|
||||
.append("' to '")
|
||||
.append(event.coverNewValue())
|
||||
.append("'\r\n");
|
||||
}
|
||||
}
|
||||
if (newTtls != this.ttls) {
|
||||
this.ttls = newTtls;
|
||||
start();
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
logger.log(Level.INFO, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConfig(AnyValue config) {
|
||||
super.setConfig(config);
|
||||
this.sourceName = getSourceName();
|
||||
}
|
||||
@Override
|
||||
public void setConfig(AnyValue config) {
|
||||
super.setConfig(config);
|
||||
this.sourceName = getSourceName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy(AnyValue config) {
|
||||
if (scheduler != null) {
|
||||
scheduler.shutdownNow();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void destroy(AnyValue config) {
|
||||
if (scheduler != null) {
|
||||
scheduler.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
public String getSourceName() {
|
||||
return config.getValue("source");
|
||||
}
|
||||
public String getSourceName() {
|
||||
return config.getValue("source");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resourceName() {
|
||||
return sourceName;
|
||||
}
|
||||
@Override
|
||||
public String resourceName() {
|
||||
return sourceName;
|
||||
}
|
||||
|
||||
@Override // ServiceLoader时判断配置是否符合当前实现类
|
||||
public boolean acceptsConf(AnyValue config) {
|
||||
if (config == null) {
|
||||
return false;
|
||||
}
|
||||
return config.getValue("source") != null;
|
||||
}
|
||||
@Override // ServiceLoader时判断配置是否符合当前实现类
|
||||
public boolean acceptsConf(AnyValue config) {
|
||||
if (config == null) {
|
||||
return false;
|
||||
}
|
||||
return config.getValue("source") != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (this.scheduler == null) {
|
||||
this.scheduler = Utility.newScheduledExecutor(
|
||||
1, "Redkale-" + CacheClusterAgent.class.getSimpleName() + "-Check-Thread-%s");
|
||||
}
|
||||
if (this.taskFuture != null) {
|
||||
this.taskFuture.cancel(true);
|
||||
}
|
||||
this.taskFuture = this.scheduler.scheduleAtFixedRate(newTask(), ttls, ttls, TimeUnit.SECONDS);
|
||||
}
|
||||
@Override
|
||||
public void start() {
|
||||
if (this.scheduler == null) {
|
||||
this.scheduler = Utility.newScheduledExecutor(
|
||||
1, "Redkale-" + CacheClusterAgent.class.getSimpleName() + "-Check-Thread-%s");
|
||||
}
|
||||
if (this.taskFuture != null) {
|
||||
this.taskFuture.cancel(true);
|
||||
}
|
||||
this.taskFuture = this.scheduler.scheduleAtFixedRate(newTask(), ttls, ttls, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private Runnable newTask() {
|
||||
return () -> {
|
||||
try {
|
||||
long s = System.currentTimeMillis();
|
||||
localEntrys.values().stream().filter(e -> !e.canceled).forEach(this::checkLocalHealth);
|
||||
remoteEntrys.values().stream()
|
||||
.filter(entry -> "SNCP".equalsIgnoreCase(entry.protocol))
|
||||
.forEach(this::updateSncpAddress);
|
||||
checkApplicationHealth();
|
||||
checkHttpAddressHealth();
|
||||
loadSncpAddressHealth();
|
||||
long e = System.currentTimeMillis() - s;
|
||||
if (e >= ttls * 9 / 10) {
|
||||
logger.log(Level.WARNING, getClass().getSimpleName() + ".schedule check-slower cost " + e + " ms");
|
||||
} else if (e >= ttls / 2) {
|
||||
logger.log(Level.FINE, getClass().getSimpleName() + ".schedule check-slowly cost " + e + " ms");
|
||||
} else {
|
||||
logger.log(Level.FINEST, getClass().getSimpleName() + ".schedule check cost " + e + " ms");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, getClass().getSimpleName() + ".schedule check error", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
private Runnable newTask() {
|
||||
return () -> {
|
||||
try {
|
||||
long s = System.currentTimeMillis();
|
||||
localEntrys.values().stream().filter(e -> !e.canceled).forEach(this::checkLocalHealth);
|
||||
remoteEntrys.values().stream()
|
||||
.filter(entry -> "SNCP".equalsIgnoreCase(entry.protocol))
|
||||
.forEach(this::updateSncpAddress);
|
||||
checkApplicationHealth();
|
||||
checkHttpAddressHealth();
|
||||
loadSncpAddressHealth();
|
||||
long e = System.currentTimeMillis() - s;
|
||||
if (e >= ttls * 9 / 10) {
|
||||
logger.log(Level.WARNING, getClass().getSimpleName() + ".schedule check-slower cost " + e + " ms");
|
||||
} else if (e >= ttls / 2) {
|
||||
logger.log(Level.FINE, getClass().getSimpleName() + ".schedule check-slowly cost " + e + " ms");
|
||||
} else {
|
||||
logger.log(Level.FINEST, getClass().getSimpleName() + ".schedule check cost " + e + " ms");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, getClass().getSimpleName() + ".schedule check error", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected void loadSncpAddressHealth() {
|
||||
List<String> keys = source.keysStartsWith("cluster.sncp:");
|
||||
keys.forEach(serviceName -> {
|
||||
try {
|
||||
this.sncpAddressMap.put(serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS));
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "loadSncpAddressHealth check " + serviceName + " error", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
protected void loadSncpAddressHealth() {
|
||||
List<String> keys = source.keysStartsWith("cluster.sncp:");
|
||||
keys.forEach(serviceName -> {
|
||||
try {
|
||||
this.sncpAddressMap.put(serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS));
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "loadSncpAddressHealth check " + serviceName + " error", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void checkHttpAddressHealth() {
|
||||
try {
|
||||
this.httpAddressMap.keySet().stream().forEach(serviceName -> {
|
||||
try {
|
||||
this.httpAddressMap.put(
|
||||
serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS));
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "checkHttpAddressHealth check " + serviceName + " error", e);
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "checkHttpAddressHealth check error", ex);
|
||||
}
|
||||
}
|
||||
protected void checkHttpAddressHealth() {
|
||||
try {
|
||||
this.httpAddressMap.keySet().stream().forEach(serviceName -> {
|
||||
try {
|
||||
this.httpAddressMap.put(
|
||||
serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS));
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "checkHttpAddressHealth check " + serviceName + " error", e);
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "checkHttpAddressHealth check error", ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkLocalHealth(final ClusterEntry entry) {
|
||||
AddressEntry newaddr = new AddressEntry();
|
||||
newaddr.addr = entry.address;
|
||||
newaddr.resname = entry.resourceName;
|
||||
newaddr.nodeid = this.nodeid;
|
||||
newaddr.time = System.currentTimeMillis();
|
||||
source.hset(entry.checkName, entry.checkid, AddressEntry.class, newaddr);
|
||||
}
|
||||
protected void checkLocalHealth(final ClusterEntry entry) {
|
||||
AddressEntry newaddr = new AddressEntry();
|
||||
newaddr.addr = entry.address;
|
||||
newaddr.resname = entry.resourceName;
|
||||
newaddr.nodeid = this.nodeid;
|
||||
newaddr.time = System.currentTimeMillis();
|
||||
source.hset(entry.checkName, entry.checkid, AddressEntry.class, newaddr);
|
||||
}
|
||||
|
||||
@Override // 获取SNCP远程服务的可用ip列表
|
||||
public CompletableFuture<Set<InetSocketAddress>> querySncpAddress(String protocol, String module, String resname) {
|
||||
final String serviceName = generateSncpServiceName(protocol, module, resname);
|
||||
Set<InetSocketAddress> rs = sncpAddressMap.get(serviceName);
|
||||
if (rs != null) {
|
||||
return CompletableFuture.completedFuture(rs);
|
||||
}
|
||||
return queryAddress(serviceName).thenApply(t -> {
|
||||
sncpAddressMap.put(serviceName, t);
|
||||
return t;
|
||||
});
|
||||
}
|
||||
@Override // 获取SNCP远程服务的可用ip列表
|
||||
public CompletableFuture<Set<InetSocketAddress>> querySncpAddress(String protocol, String module, String resname) {
|
||||
final String serviceName = generateSncpServiceName(protocol, module, resname);
|
||||
Set<InetSocketAddress> rs = sncpAddressMap.get(serviceName);
|
||||
if (rs != null) {
|
||||
return CompletableFuture.completedFuture(rs);
|
||||
}
|
||||
return queryAddress(serviceName).thenApply(t -> {
|
||||
sncpAddressMap.put(serviceName, t);
|
||||
return t;
|
||||
});
|
||||
}
|
||||
|
||||
@Override // 获取HTTP远程服务的可用ip列表
|
||||
public CompletableFuture<Set<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname) {
|
||||
final String serviceName = generateHttpServiceName(protocol, module, resname);
|
||||
Set<InetSocketAddress> rs = httpAddressMap.get(serviceName);
|
||||
if (rs != null) {
|
||||
return CompletableFuture.completedFuture(rs);
|
||||
}
|
||||
return queryAddress(serviceName).thenApply(t -> {
|
||||
httpAddressMap.put(serviceName, t);
|
||||
return t;
|
||||
});
|
||||
}
|
||||
@Override // 获取HTTP远程服务的可用ip列表
|
||||
public CompletableFuture<Set<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname) {
|
||||
final String serviceName = generateHttpServiceName(protocol, module, resname);
|
||||
Set<InetSocketAddress> rs = httpAddressMap.get(serviceName);
|
||||
if (rs != null) {
|
||||
return CompletableFuture.completedFuture(rs);
|
||||
}
|
||||
return queryAddress(serviceName).thenApply(t -> {
|
||||
httpAddressMap.put(serviceName, t);
|
||||
return t;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompletableFuture<Set<InetSocketAddress>> queryAddress(final ClusterEntry entry) {
|
||||
return queryAddress(entry.serviceName);
|
||||
}
|
||||
@Override
|
||||
protected CompletableFuture<Set<InetSocketAddress>> queryAddress(final ClusterEntry entry) {
|
||||
return queryAddress(entry.serviceName);
|
||||
}
|
||||
|
||||
private CompletableFuture<Set<InetSocketAddress>> queryAddress(final String serviceName) {
|
||||
return queryAddress0(serviceName, new HashSet<>(), new AtomicLong());
|
||||
}
|
||||
private CompletableFuture<Set<InetSocketAddress>> queryAddress(final String serviceName) {
|
||||
return queryAddress0(serviceName, new HashSet<>(), new AtomicLong());
|
||||
}
|
||||
|
||||
private CompletableFuture<Set<InetSocketAddress>> queryAddress0(
|
||||
String serviceName, Set<InetSocketAddress> set, AtomicLong cursor) {
|
||||
final CompletableFuture<Map<String, AddressEntry>> future =
|
||||
source.hscanAsync(serviceName, AddressEntry.class, cursor, 10000);
|
||||
return future.thenCompose(map -> {
|
||||
map.forEach((n, v) -> {
|
||||
if (v != null && (System.currentTimeMillis() - v.time) / 1000 <= ttls) {
|
||||
set.add(v.addr);
|
||||
}
|
||||
});
|
||||
if (cursor.get() == 0) {
|
||||
return CompletableFuture.completedFuture(set);
|
||||
} else {
|
||||
return queryAddress0(serviceName, set, cursor);
|
||||
}
|
||||
});
|
||||
}
|
||||
private CompletableFuture<Set<InetSocketAddress>> queryAddress0(
|
||||
String serviceName, Set<InetSocketAddress> set, AtomicLong cursor) {
|
||||
final CompletableFuture<Map<String, AddressEntry>> future =
|
||||
source.hscanAsync(serviceName, AddressEntry.class, cursor, 10000);
|
||||
return future.thenCompose(map -> {
|
||||
map.forEach((n, v) -> {
|
||||
if (v != null && (System.currentTimeMillis() - v.time) / 1000 <= ttls) {
|
||||
set.add(v.addr);
|
||||
}
|
||||
});
|
||||
if (cursor.get() == 0) {
|
||||
return CompletableFuture.completedFuture(set);
|
||||
} else {
|
||||
return queryAddress0(serviceName, set, cursor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected boolean isApplicationHealth() {
|
||||
String serviceName = generateApplicationServiceName();
|
||||
String serviceid = generateApplicationServiceId();
|
||||
AddressEntry entry = (AddressEntry) source.hget(serviceName, serviceid, AddressEntry.class);
|
||||
return entry != null && (System.currentTimeMillis() - entry.time) / 1000 <= ttls;
|
||||
}
|
||||
protected boolean isApplicationHealth() {
|
||||
String serviceName = generateApplicationServiceName();
|
||||
String serviceid = generateApplicationServiceId();
|
||||
AddressEntry entry = (AddressEntry) source.hget(serviceName, serviceid, AddressEntry.class);
|
||||
return entry != null && (System.currentTimeMillis() - entry.time) / 1000 <= ttls;
|
||||
}
|
||||
|
||||
protected void checkApplicationHealth() {
|
||||
String checkName = generateApplicationServiceName();
|
||||
String checkid = generateApplicationCheckId();
|
||||
AddressEntry entry = new AddressEntry();
|
||||
entry.addr = this.appAddress;
|
||||
entry.nodeid = this.nodeid;
|
||||
entry.time = System.currentTimeMillis();
|
||||
source.hset(checkName, checkid, AddressEntry.class, entry);
|
||||
}
|
||||
protected void checkApplicationHealth() {
|
||||
String checkName = generateApplicationServiceName();
|
||||
String checkid = generateApplicationCheckId();
|
||||
AddressEntry entry = new AddressEntry();
|
||||
entry.addr = this.appAddress;
|
||||
entry.nodeid = this.nodeid;
|
||||
entry.time = System.currentTimeMillis();
|
||||
source.hset(checkName, checkid, AddressEntry.class, entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Application application) {
|
||||
if (isApplicationHealth()) {
|
||||
throw new RedkaleException("application.nodeid=" + nodeid + " exists in cluster");
|
||||
}
|
||||
deregister(application);
|
||||
@Override
|
||||
public void register(Application application) {
|
||||
if (isApplicationHealth()) {
|
||||
throw new RedkaleException("application.nodeid=" + nodeid + " exists in cluster");
|
||||
}
|
||||
deregister(application);
|
||||
|
||||
String serviceid = generateApplicationServiceId();
|
||||
String serviceName = generateApplicationServiceName();
|
||||
AddressEntry entry = new AddressEntry();
|
||||
entry.addr = this.appAddress;
|
||||
entry.nodeid = this.nodeid;
|
||||
entry.time = System.currentTimeMillis();
|
||||
source.hset(serviceName, serviceid, AddressEntry.class, entry);
|
||||
}
|
||||
String serviceid = generateApplicationServiceId();
|
||||
String serviceName = generateApplicationServiceName();
|
||||
AddressEntry entry = new AddressEntry();
|
||||
entry.addr = this.appAddress;
|
||||
entry.nodeid = this.nodeid;
|
||||
entry.time = System.currentTimeMillis();
|
||||
source.hset(serviceName, serviceid, AddressEntry.class, entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deregister(Application application) {
|
||||
String serviceid = generateApplicationServiceId();
|
||||
String serviceName = generateApplicationServiceName();
|
||||
source.hdel(serviceName, serviceid);
|
||||
}
|
||||
@Override
|
||||
public void deregister(Application application) {
|
||||
String serviceid = generateApplicationServiceId();
|
||||
String serviceName = generateApplicationServiceName();
|
||||
source.hdel(serviceName, serviceid);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClusterEntry register(NodeServer ns, String protocol, Service service) {
|
||||
deregister(ns, protocol, service, false);
|
||||
//
|
||||
ClusterEntry clusterEntry = new ClusterEntry(ns, protocol, service);
|
||||
AddressEntry entry = new AddressEntry();
|
||||
entry.addr = clusterEntry.address;
|
||||
entry.resname = clusterEntry.resourceName;
|
||||
entry.nodeid = this.nodeid;
|
||||
entry.time = System.currentTimeMillis();
|
||||
source.hset(clusterEntry.serviceName, clusterEntry.serviceid, AddressEntry.class, entry);
|
||||
return clusterEntry;
|
||||
}
|
||||
@Override
|
||||
protected ClusterEntry register(NodeServer ns, String protocol, Service service) {
|
||||
deregister(ns, protocol, service, false);
|
||||
//
|
||||
ClusterEntry clusterEntry = new ClusterEntry(ns, protocol, service);
|
||||
AddressEntry entry = new AddressEntry();
|
||||
entry.addr = clusterEntry.address;
|
||||
entry.resname = clusterEntry.resourceName;
|
||||
entry.nodeid = this.nodeid;
|
||||
entry.time = System.currentTimeMillis();
|
||||
source.hset(clusterEntry.serviceName, clusterEntry.serviceid, AddressEntry.class, entry);
|
||||
return clusterEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deregister(NodeServer ns, String protocol, Service service) {
|
||||
deregister(ns, protocol, service, true);
|
||||
}
|
||||
@Override
|
||||
protected void deregister(NodeServer ns, String protocol, Service service) {
|
||||
deregister(ns, protocol, service, true);
|
||||
}
|
||||
|
||||
protected void deregister(NodeServer ns, String protocol, Service service, boolean realCanceled) {
|
||||
String serviceName = generateServiceName(ns, protocol, service);
|
||||
String serviceid = generateServiceId(ns, protocol, service);
|
||||
ClusterEntry currEntry = null;
|
||||
for (final ClusterEntry entry : localEntrys.values()) {
|
||||
if (Objects.equals(entry.serviceName, serviceName) && Objects.equals(entry.serviceid, serviceid)) {
|
||||
currEntry = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (currEntry == null) {
|
||||
for (final ClusterEntry entry : remoteEntrys.values()) {
|
||||
if (Objects.equals(entry.serviceName, serviceName) && Objects.equals(entry.serviceid, serviceid)) {
|
||||
currEntry = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
source.hdel(serviceName, serviceid);
|
||||
if (realCanceled && currEntry != null) {
|
||||
currEntry.canceled = true;
|
||||
}
|
||||
}
|
||||
protected void deregister(NodeServer ns, String protocol, Service service, boolean realCanceled) {
|
||||
String serviceName = generateServiceName(ns, protocol, service);
|
||||
String serviceid = generateServiceId(ns, protocol, service);
|
||||
ClusterEntry currEntry = null;
|
||||
for (final ClusterEntry entry : localEntrys.values()) {
|
||||
if (Objects.equals(entry.serviceName, serviceName) && Objects.equals(entry.serviceid, serviceid)) {
|
||||
currEntry = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (currEntry == null) {
|
||||
for (final ClusterEntry entry : remoteEntrys.values()) {
|
||||
if (Objects.equals(entry.serviceName, serviceName) && Objects.equals(entry.serviceid, serviceid)) {
|
||||
currEntry = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
source.hdel(serviceName, serviceid);
|
||||
if (realCanceled && currEntry != null) {
|
||||
currEntry.canceled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String generateApplicationServiceName() {
|
||||
return "cluster:app:" + super.generateApplicationServiceName();
|
||||
}
|
||||
@Override
|
||||
protected String generateApplicationServiceName() {
|
||||
return "cluster:app:" + super.generateApplicationServiceName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String generateServiceName(NodeServer ns, String protocol, Service service) {
|
||||
return "cluster:service:" + super.generateServiceName(ns, protocol, service);
|
||||
}
|
||||
@Override
|
||||
protected String generateServiceName(NodeServer ns, String protocol, Service service) {
|
||||
return "cluster:service:" + super.generateServiceName(ns, protocol, service);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateHttpServiceName(String protocol, String module, String resname) {
|
||||
return "cluster:service:" + super.generateHttpServiceName(protocol, module, resname);
|
||||
}
|
||||
@Override
|
||||
public String generateHttpServiceName(String protocol, String module, String resname) {
|
||||
return "cluster:service:" + super.generateHttpServiceName(protocol, module, resname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateSncpServiceName(String protocol, String restype, String resname) {
|
||||
return "cluster:service:" + super.generateSncpServiceName(protocol, restype, resname);
|
||||
}
|
||||
@Override
|
||||
public String generateSncpServiceName(String protocol, String restype, String resname) {
|
||||
return "cluster:service:" + super.generateSncpServiceName(protocol, restype, resname);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String generateApplicationCheckName() {
|
||||
return generateApplicationServiceName();
|
||||
}
|
||||
@Override
|
||||
protected String generateApplicationCheckName() {
|
||||
return generateApplicationServiceName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String generateApplicationCheckId() {
|
||||
return generateApplicationServiceId();
|
||||
}
|
||||
@Override
|
||||
protected String generateApplicationCheckId() {
|
||||
return generateApplicationServiceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String generateCheckName(NodeServer ns, String protocol, Service service) {
|
||||
return generateServiceName(ns, protocol, service);
|
||||
}
|
||||
@Override
|
||||
protected String generateCheckName(NodeServer ns, String protocol, Service service) {
|
||||
return generateServiceName(ns, protocol, service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String generateCheckId(NodeServer ns, String protocol, Service service) {
|
||||
return generateServiceId(ns, protocol, service);
|
||||
}
|
||||
@Override
|
||||
protected String generateCheckId(NodeServer ns, String protocol, Service 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() {
|
||||
this.time = System.currentTimeMillis();
|
||||
return this;
|
||||
}
|
||||
public AddressEntry refresh() {
|
||||
this.time = System.currentTimeMillis();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,393 +35,393 @@ import org.redkale.util.*;
|
||||
*/
|
||||
public abstract class ClusterAgent {
|
||||
|
||||
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||
|
||||
@Resource(name = RESNAME_APP_NODEID)
|
||||
protected String nodeid;
|
||||
|
||||
@Resource(name = RESNAME_APP_NAME)
|
||||
protected String appName = "";
|
||||
|
||||
@Resource(name = RESNAME_APP_ADDR)
|
||||
protected InetSocketAddress appAddress;
|
||||
|
||||
@Resource(required = false)
|
||||
protected Application application;
|
||||
|
||||
protected String name;
|
||||
|
||||
protected boolean waits;
|
||||
|
||||
@Nullable
|
||||
protected String[] protocols; // 必须全大写
|
||||
|
||||
protected int[] ports;
|
||||
|
||||
protected AnyValue config;
|
||||
|
||||
protected Set<String> tags;
|
||||
|
||||
// key: serviceid
|
||||
protected final ConcurrentHashMap<String, ClusterEntry> localEntrys = new ConcurrentHashMap<>();
|
||||
|
||||
// key: serviceid
|
||||
protected final ConcurrentHashMap<String, ClusterEntry> remoteEntrys = new ConcurrentHashMap<>();
|
||||
|
||||
public void init(AnyValue config) {
|
||||
this.config = config;
|
||||
this.name = config.getValue("name", "");
|
||||
this.waits = config.getBoolValue("waits", false);
|
||||
String ps = config.getValue("protocols", "").toUpperCase();
|
||||
this.protocols = Utility.isEmpty(ps) ? null : ps.split(";");
|
||||
|
||||
String ts = config.getValue("ports", "");
|
||||
if (ts != null && !ts.isEmpty()) {
|
||||
String[] its = ts.split(";");
|
||||
List<Integer> list = new ArrayList<>();
|
||||
for (String str : its) {
|
||||
if (str.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
list.add(Integer.parseInt(str.trim()));
|
||||
}
|
||||
if (!list.isEmpty()) {
|
||||
this.ports = list.stream().mapToInt(x -> x).toArray();
|
||||
}
|
||||
}
|
||||
Set<String> tags0 = new HashSet<>();
|
||||
for (String str : config.getValue("tags", "").split(";|,")) {
|
||||
if (!str.trim().isEmpty()) {
|
||||
tags0.add(str.trim());
|
||||
}
|
||||
}
|
||||
if (!tags0.isEmpty()) {
|
||||
this.tags = tags0;
|
||||
}
|
||||
}
|
||||
|
||||
@ResourceChanged
|
||||
public abstract void onResourceChange(ResourceEvent[] events);
|
||||
|
||||
public void destroy(AnyValue config) {}
|
||||
|
||||
/**
|
||||
* ServiceLoader时判断配置是否符合当前实现类
|
||||
*
|
||||
* @param config 节点配置
|
||||
* @return boolean
|
||||
*/
|
||||
public abstract boolean acceptsConf(AnyValue config);
|
||||
|
||||
public boolean containsProtocol(String protocol) {
|
||||
if (Utility.isEmpty(protocol)) {
|
||||
return false;
|
||||
}
|
||||
return protocols == null || Utility.contains(protocols, protocol.toUpperCase());
|
||||
}
|
||||
|
||||
public boolean containsPort(int port) {
|
||||
if (ports == null || ports.length == 0) {
|
||||
return true;
|
||||
}
|
||||
return Utility.contains(ports, port);
|
||||
}
|
||||
|
||||
public void start() {}
|
||||
|
||||
public int intervalCheckSeconds() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
public abstract void register(Application application);
|
||||
|
||||
public abstract void deregister(Application application);
|
||||
|
||||
// 注册服务, 在NodeService调用Service.init方法之前调用
|
||||
public void register(
|
||||
NodeServer ns,
|
||||
String protocol,
|
||||
Set<Service> localServices,
|
||||
Set<Service> remoteServices,
|
||||
Set<Service> servletServices) {
|
||||
if (servletServices.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// 注册本地模式
|
||||
for (Service service : servletServices) {
|
||||
if (!canRegister(ns, protocol, service)) {
|
||||
continue;
|
||||
}
|
||||
ClusterEntry htentry = register(ns, protocol, service);
|
||||
localEntrys.put(htentry.serviceid, htentry);
|
||||
}
|
||||
// 远程模式加载IP列表, 只支持SNCP协议
|
||||
if (ns.isSNCP()) {
|
||||
for (Service service : remoteServices) {
|
||||
ClusterEntry entry = new ClusterEntry(ns, protocol, service);
|
||||
updateSncpAddress(entry);
|
||||
remoteEntrys.put(entry.serviceid, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 注销服务, 在NodeService调用Service.destroy 方法之前调用
|
||||
public void deregister(
|
||||
NodeServer ns,
|
||||
String protocol,
|
||||
Set<Service> localServices,
|
||||
Set<Service> remoteServices,
|
||||
Set<Service> servletServices) {
|
||||
// 注销本地模式 远程模式不注册
|
||||
for (Service service : servletServices) {
|
||||
if (!canRegister(ns, protocol, service)) {
|
||||
continue;
|
||||
}
|
||||
deregister(ns, protocol, service);
|
||||
}
|
||||
afterDeregister(ns, protocol);
|
||||
}
|
||||
|
||||
protected boolean canRegister(NodeServer ns, String protocol, Service service) {
|
||||
if (service.getClass().getAnnotation(Component.class) != null) {
|
||||
return false;
|
||||
}
|
||||
if ("SNCP".equalsIgnoreCase(protocol) && service.getClass().getAnnotation(Local.class) != null) {
|
||||
return false;
|
||||
}
|
||||
AutoLoad al = service.getClass().getAnnotation(AutoLoad.class);
|
||||
if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) {
|
||||
return false;
|
||||
}
|
||||
org.redkale.util.AutoLoad al2 = service.getClass().getAnnotation(org.redkale.util.AutoLoad.class);
|
||||
if (al2 != null && !al2.value() && service.getClass().getAnnotation(Local.class) != null) {
|
||||
return false;
|
||||
}
|
||||
if (service instanceof WebSocketNode) {
|
||||
if (((WebSocketNode) service).getLocalWebSocketEngine() == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ClusterEntry entry = new ClusterEntry(ns, protocol, service);
|
||||
if (entry.serviceName.trim().endsWith(".")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void afterDeregister(NodeServer ns, String protocol) {
|
||||
if (!this.waits) {
|
||||
return;
|
||||
}
|
||||
int s = intervalCheckSeconds();
|
||||
if (s > 0) { // 暂停,弥补其他依赖本进程服务的周期偏差
|
||||
Utility.sleep(s * 1000);
|
||||
logger.info(this.getClass().getSimpleName() + " wait for " + s * 1000 + "ms after deregister");
|
||||
}
|
||||
}
|
||||
|
||||
// 获取HTTP远程服务的可用ip列表
|
||||
public abstract CompletableFuture<Set<InetSocketAddress>> queryHttpAddress(
|
||||
String protocol, String module, String resname);
|
||||
|
||||
// 获取SNCP远程服务的可用ip列表 restype: resourceType.getName()
|
||||
public abstract CompletableFuture<Set<InetSocketAddress>> querySncpAddress(
|
||||
String protocol, String restype, String resname);
|
||||
|
||||
// 获取远程服务的可用ip列表
|
||||
protected abstract CompletableFuture<Set<InetSocketAddress>> queryAddress(ClusterEntry entry);
|
||||
|
||||
// 注册服务
|
||||
protected abstract ClusterEntry register(NodeServer ns, String protocol, Service service);
|
||||
|
||||
// 注销服务
|
||||
protected abstract void deregister(NodeServer ns, String protocol, Service service);
|
||||
|
||||
// 格式: protocol:classtype-resourcename
|
||||
protected void updateSncpAddress(ClusterEntry entry) {
|
||||
if (application == null) {
|
||||
return;
|
||||
}
|
||||
Service service = entry.serviceRef.get();
|
||||
if (service == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Set<InetSocketAddress> addrs = ClusterAgent.this.queryAddress(entry).join();
|
||||
SncpRpcGroups rpcGroups = application.getSncpRpcGroups();
|
||||
rpcGroups.putClusterAddress(entry.resourceid, addrs);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, entry + " updateSncpAddress error", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected String urlEncode(String value) {
|
||||
return value == null ? null : URLEncoder.encode(value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
protected String generateApplicationServiceName() {
|
||||
return Utility.isEmpty(appName) ? "node" : appName;
|
||||
}
|
||||
|
||||
protected String generateApplicationServiceType() {
|
||||
return "nodes";
|
||||
}
|
||||
|
||||
protected String generateApplicationServiceId() {
|
||||
return generateApplicationServiceName() + "@" + this.nodeid;
|
||||
}
|
||||
|
||||
protected String generateApplicationCheckName() {
|
||||
return "check-" + generateApplicationServiceName();
|
||||
}
|
||||
|
||||
protected String generateApplicationCheckId() {
|
||||
return "check-" + generateApplicationServiceId();
|
||||
}
|
||||
|
||||
protected String generateApplicationHost() {
|
||||
return this.appAddress.getHostString();
|
||||
}
|
||||
|
||||
protected int generateApplicationPort() {
|
||||
return this.appAddress.getPort();
|
||||
}
|
||||
|
||||
public String generateSncpServiceName(String protocol, String restype, String resname) {
|
||||
return protocol.toLowerCase() + ":" + restype + (Utility.isEmpty(resname) ? "" : ("-" + resname));
|
||||
}
|
||||
|
||||
// 也会提供给HttpMessageClusterAgent适用
|
||||
public String generateHttpServiceName(String protocol, String module, String resname) {
|
||||
return protocol.toLowerCase() + ":" + module + (Utility.isEmpty(resname) ? "" : ("-" + resname));
|
||||
}
|
||||
|
||||
// 格式: protocol:classtype-resourcename
|
||||
protected String generateServiceName(NodeServer ns, String protocol, Service service) {
|
||||
if (protocol.toLowerCase().startsWith("http")) { // HTTP使用RestService.name方式是为了与MessageClient中的module保持一致,
|
||||
// 因为HTTP依靠的url中的module,无法知道Service类名
|
||||
String resname = Sncp.getResourceName(service);
|
||||
String module = Rest.getRestModule(service).toLowerCase();
|
||||
return protocol.toLowerCase() + ":" + module + (resname.isEmpty() ? "" : ("-" + resname));
|
||||
}
|
||||
if (!Sncp.isSncpDyn(service)) {
|
||||
return protocol.toLowerCase() + ":" + service.getClass().getName();
|
||||
}
|
||||
String resname = Sncp.getResourceName(service);
|
||||
return protocol.toLowerCase() + ":" + Sncp.getResourceType(service).getName()
|
||||
+ (resname.isEmpty() ? "" : ("-" + resname));
|
||||
}
|
||||
|
||||
// 格式: protocol:classtype-resourcename:nodeid
|
||||
protected String generateServiceId(NodeServer ns, String protocol, Service service) {
|
||||
return generateServiceName(ns, protocol, service) + "@" + this.nodeid;
|
||||
}
|
||||
|
||||
protected String generateCheckName(NodeServer ns, String protocol, Service service) {
|
||||
return "check-" + generateServiceName(ns, protocol, service);
|
||||
}
|
||||
|
||||
protected String generateCheckId(NodeServer ns, String protocol, Service service) {
|
||||
return "check-" + generateServiceId(ns, protocol, service);
|
||||
}
|
||||
|
||||
protected ConcurrentHashMap<String, ClusterEntry> getLocalEntrys() {
|
||||
return localEntrys;
|
||||
}
|
||||
|
||||
protected ConcurrentHashMap<String, ClusterEntry> getRemoteEntrys() {
|
||||
return remoteEntrys;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String[] getProtocols() {
|
||||
return protocols;
|
||||
}
|
||||
|
||||
public void setProtocols(String[] protocols) {
|
||||
this.protocols = protocols;
|
||||
}
|
||||
|
||||
public int[] getPorts() {
|
||||
return ports;
|
||||
}
|
||||
|
||||
public void setPorts(int[] ports) {
|
||||
this.ports = ports;
|
||||
}
|
||||
|
||||
public AnyValue getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void setConfig(AnyValue config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public class ClusterEntry {
|
||||
|
||||
// serviceName+nodeid为主 服务的单个实例
|
||||
public String serviceid;
|
||||
|
||||
// 以协议+Rest资源名为主 服务类名
|
||||
public String serviceName;
|
||||
|
||||
public final String resourceType;
|
||||
|
||||
public final String resourceName;
|
||||
|
||||
public final String resourceid;
|
||||
|
||||
public String checkid;
|
||||
|
||||
public String checkName;
|
||||
|
||||
// http or sncp
|
||||
public String protocol;
|
||||
|
||||
// TCP or UDP
|
||||
public String netProtocol;
|
||||
|
||||
@ConvertDisabled
|
||||
public WeakReference<Service> serviceRef;
|
||||
|
||||
public InetSocketAddress address;
|
||||
|
||||
public boolean canceled;
|
||||
|
||||
public ClusterEntry(NodeServer ns, String protocol, Service service) {
|
||||
this.serviceid = generateServiceId(ns, protocol, service);
|
||||
this.serviceName = generateServiceName(ns, protocol, service);
|
||||
this.checkid = generateCheckId(ns, protocol, service);
|
||||
this.checkName = generateCheckName(ns, protocol, service);
|
||||
Class restype = Sncp.getResourceType(service);
|
||||
this.resourceType = restype.getName();
|
||||
this.resourceName = Sncp.getResourceName(service);
|
||||
this.resourceid = Sncp.resourceid(resourceName, restype);
|
||||
this.protocol = protocol;
|
||||
InetSocketAddress addr = ns.getSocketAddress();
|
||||
String host = addr.getHostString();
|
||||
if ("0.0.0.0".equals(host)) {
|
||||
host = appAddress.getHostString();
|
||||
addr = new InetSocketAddress(host, addr.getPort());
|
||||
}
|
||||
this.address = addr;
|
||||
this.serviceRef = new WeakReference(service);
|
||||
Server server = ns.getServer();
|
||||
this.netProtocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : "TCP";
|
||||
}
|
||||
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||
|
||||
@Resource(name = RESNAME_APP_NODEID)
|
||||
protected String nodeid;
|
||||
|
||||
@Resource(name = RESNAME_APP_NAME)
|
||||
protected String appName = "";
|
||||
|
||||
@Resource(name = RESNAME_APP_ADDR)
|
||||
protected InetSocketAddress appAddress;
|
||||
|
||||
@Resource(required = false)
|
||||
protected Application application;
|
||||
|
||||
protected String name;
|
||||
|
||||
protected boolean waits;
|
||||
|
||||
@Nullable
|
||||
protected String[] protocols; // 必须全大写
|
||||
|
||||
protected int[] ports;
|
||||
|
||||
protected AnyValue config;
|
||||
|
||||
protected Set<String> tags;
|
||||
|
||||
// key: serviceid
|
||||
protected final ConcurrentHashMap<String, ClusterEntry> localEntrys = new ConcurrentHashMap<>();
|
||||
|
||||
// key: serviceid
|
||||
protected final ConcurrentHashMap<String, ClusterEntry> remoteEntrys = new ConcurrentHashMap<>();
|
||||
|
||||
public void init(AnyValue config) {
|
||||
this.config = config;
|
||||
this.name = config.getValue("name", "");
|
||||
this.waits = config.getBoolValue("waits", false);
|
||||
String ps = config.getValue("protocols", "").toUpperCase();
|
||||
this.protocols = Utility.isEmpty(ps) ? null : ps.split(";");
|
||||
|
||||
String ts = config.getValue("ports", "");
|
||||
if (ts != null && !ts.isEmpty()) {
|
||||
String[] its = ts.split(";");
|
||||
List<Integer> list = new ArrayList<>();
|
||||
for (String str : its) {
|
||||
if (str.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
list.add(Integer.parseInt(str.trim()));
|
||||
}
|
||||
if (!list.isEmpty()) {
|
||||
this.ports = list.stream().mapToInt(x -> x).toArray();
|
||||
}
|
||||
}
|
||||
Set<String> tags0 = new HashSet<>();
|
||||
for (String str : config.getValue("tags", "").split(";|,")) {
|
||||
if (!str.trim().isEmpty()) {
|
||||
tags0.add(str.trim());
|
||||
}
|
||||
}
|
||||
if (!tags0.isEmpty()) {
|
||||
this.tags = tags0;
|
||||
}
|
||||
}
|
||||
|
||||
@ResourceChanged
|
||||
public abstract void onResourceChange(ResourceEvent[] events);
|
||||
|
||||
public void destroy(AnyValue config) {}
|
||||
|
||||
/**
|
||||
* ServiceLoader时判断配置是否符合当前实现类
|
||||
*
|
||||
* @param config 节点配置
|
||||
* @return boolean
|
||||
*/
|
||||
public abstract boolean acceptsConf(AnyValue config);
|
||||
|
||||
public boolean containsProtocol(String protocol) {
|
||||
if (Utility.isEmpty(protocol)) {
|
||||
return false;
|
||||
}
|
||||
return protocols == null || Utility.contains(protocols, protocol.toUpperCase());
|
||||
}
|
||||
|
||||
public boolean containsPort(int port) {
|
||||
if (ports == null || ports.length == 0) {
|
||||
return true;
|
||||
}
|
||||
return Utility.contains(ports, port);
|
||||
}
|
||||
|
||||
public void start() {}
|
||||
|
||||
public int intervalCheckSeconds() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
public abstract void register(Application application);
|
||||
|
||||
public abstract void deregister(Application application);
|
||||
|
||||
// 注册服务, 在NodeService调用Service.init方法之前调用
|
||||
public void register(
|
||||
NodeServer ns,
|
||||
String protocol,
|
||||
Set<Service> localServices,
|
||||
Set<Service> remoteServices,
|
||||
Set<Service> servletServices) {
|
||||
if (servletServices.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// 注册本地模式
|
||||
for (Service service : servletServices) {
|
||||
if (!canRegister(ns, protocol, service)) {
|
||||
continue;
|
||||
}
|
||||
ClusterEntry htentry = register(ns, protocol, service);
|
||||
localEntrys.put(htentry.serviceid, htentry);
|
||||
}
|
||||
// 远程模式加载IP列表, 只支持SNCP协议
|
||||
if (ns.isSNCP()) {
|
||||
for (Service service : remoteServices) {
|
||||
ClusterEntry entry = new ClusterEntry(ns, protocol, service);
|
||||
updateSncpAddress(entry);
|
||||
remoteEntrys.put(entry.serviceid, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 注销服务, 在NodeService调用Service.destroy 方法之前调用
|
||||
public void deregister(
|
||||
NodeServer ns,
|
||||
String protocol,
|
||||
Set<Service> localServices,
|
||||
Set<Service> remoteServices,
|
||||
Set<Service> servletServices) {
|
||||
// 注销本地模式 远程模式不注册
|
||||
for (Service service : servletServices) {
|
||||
if (!canRegister(ns, protocol, service)) {
|
||||
continue;
|
||||
}
|
||||
deregister(ns, protocol, service);
|
||||
}
|
||||
afterDeregister(ns, protocol);
|
||||
}
|
||||
|
||||
protected boolean canRegister(NodeServer ns, String protocol, Service service) {
|
||||
if (service.getClass().getAnnotation(Component.class) != null) {
|
||||
return false;
|
||||
}
|
||||
if ("SNCP".equalsIgnoreCase(protocol) && service.getClass().getAnnotation(Local.class) != null) {
|
||||
return false;
|
||||
}
|
||||
AutoLoad al = service.getClass().getAnnotation(AutoLoad.class);
|
||||
if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) {
|
||||
return false;
|
||||
}
|
||||
org.redkale.util.AutoLoad al2 = service.getClass().getAnnotation(org.redkale.util.AutoLoad.class);
|
||||
if (al2 != null && !al2.value() && service.getClass().getAnnotation(Local.class) != null) {
|
||||
return false;
|
||||
}
|
||||
if (service instanceof WebSocketNode) {
|
||||
if (((WebSocketNode) service).getLocalWebSocketEngine() == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ClusterEntry entry = new ClusterEntry(ns, protocol, service);
|
||||
if (entry.serviceName.trim().endsWith(".")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void afterDeregister(NodeServer ns, String protocol) {
|
||||
if (!this.waits) {
|
||||
return;
|
||||
}
|
||||
int s = intervalCheckSeconds();
|
||||
if (s > 0) { // 暂停,弥补其他依赖本进程服务的周期偏差
|
||||
Utility.sleep(s * 1000);
|
||||
logger.info(this.getClass().getSimpleName() + " wait for " + s * 1000 + "ms after deregister");
|
||||
}
|
||||
}
|
||||
|
||||
// 获取HTTP远程服务的可用ip列表
|
||||
public abstract CompletableFuture<Set<InetSocketAddress>> queryHttpAddress(
|
||||
String protocol, String module, String resname);
|
||||
|
||||
// 获取SNCP远程服务的可用ip列表 restype: resourceType.getName()
|
||||
public abstract CompletableFuture<Set<InetSocketAddress>> querySncpAddress(
|
||||
String protocol, String restype, String resname);
|
||||
|
||||
// 获取远程服务的可用ip列表
|
||||
protected abstract CompletableFuture<Set<InetSocketAddress>> queryAddress(ClusterEntry entry);
|
||||
|
||||
// 注册服务
|
||||
protected abstract ClusterEntry register(NodeServer ns, String protocol, Service service);
|
||||
|
||||
// 注销服务
|
||||
protected abstract void deregister(NodeServer ns, String protocol, Service service);
|
||||
|
||||
// 格式: protocol:classtype-resourcename
|
||||
protected void updateSncpAddress(ClusterEntry entry) {
|
||||
if (application == null) {
|
||||
return;
|
||||
}
|
||||
Service service = entry.serviceRef.get();
|
||||
if (service == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Set<InetSocketAddress> addrs = ClusterAgent.this.queryAddress(entry).join();
|
||||
SncpRpcGroups rpcGroups = application.getSncpRpcGroups();
|
||||
rpcGroups.putClusterAddress(entry.resourceid, addrs);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, entry + " updateSncpAddress error", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected String urlEncode(String value) {
|
||||
return value == null ? null : URLEncoder.encode(value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
protected String generateApplicationServiceName() {
|
||||
return Utility.isEmpty(appName) ? "node" : appName;
|
||||
}
|
||||
|
||||
protected String generateApplicationServiceType() {
|
||||
return "nodes";
|
||||
}
|
||||
|
||||
protected String generateApplicationServiceId() {
|
||||
return generateApplicationServiceName() + "@" + this.nodeid;
|
||||
}
|
||||
|
||||
protected String generateApplicationCheckName() {
|
||||
return "check-" + generateApplicationServiceName();
|
||||
}
|
||||
|
||||
protected String generateApplicationCheckId() {
|
||||
return "check-" + generateApplicationServiceId();
|
||||
}
|
||||
|
||||
protected String generateApplicationHost() {
|
||||
return this.appAddress.getHostString();
|
||||
}
|
||||
|
||||
protected int generateApplicationPort() {
|
||||
return this.appAddress.getPort();
|
||||
}
|
||||
|
||||
public String generateSncpServiceName(String protocol, String restype, String resname) {
|
||||
return protocol.toLowerCase() + ":" + restype + (Utility.isEmpty(resname) ? "" : ("-" + resname));
|
||||
}
|
||||
|
||||
// 也会提供给HttpMessageClusterAgent适用
|
||||
public String generateHttpServiceName(String protocol, String module, String resname) {
|
||||
return protocol.toLowerCase() + ":" + module + (Utility.isEmpty(resname) ? "" : ("-" + resname));
|
||||
}
|
||||
|
||||
// 格式: protocol:classtype-resourcename
|
||||
protected String generateServiceName(NodeServer ns, String protocol, Service service) {
|
||||
if (protocol.toLowerCase().startsWith("http")) { // HTTP使用RestService.name方式是为了与MessageClient中的module保持一致,
|
||||
// 因为HTTP依靠的url中的module,无法知道Service类名
|
||||
String resname = Sncp.getResourceName(service);
|
||||
String module = Rest.getRestModule(service).toLowerCase();
|
||||
return protocol.toLowerCase() + ":" + module + (resname.isEmpty() ? "" : ("-" + resname));
|
||||
}
|
||||
if (!Sncp.isSncpDyn(service)) {
|
||||
return protocol.toLowerCase() + ":" + service.getClass().getName();
|
||||
}
|
||||
String resname = Sncp.getResourceName(service);
|
||||
return protocol.toLowerCase() + ":" + Sncp.getResourceType(service).getName()
|
||||
+ (resname.isEmpty() ? "" : ("-" + resname));
|
||||
}
|
||||
|
||||
// 格式: protocol:classtype-resourcename:nodeid
|
||||
protected String generateServiceId(NodeServer ns, String protocol, Service service) {
|
||||
return generateServiceName(ns, protocol, service) + "@" + this.nodeid;
|
||||
}
|
||||
|
||||
protected String generateCheckName(NodeServer ns, String protocol, Service service) {
|
||||
return "check-" + generateServiceName(ns, protocol, service);
|
||||
}
|
||||
|
||||
protected String generateCheckId(NodeServer ns, String protocol, Service service) {
|
||||
return "check-" + generateServiceId(ns, protocol, service);
|
||||
}
|
||||
|
||||
protected ConcurrentHashMap<String, ClusterEntry> getLocalEntrys() {
|
||||
return localEntrys;
|
||||
}
|
||||
|
||||
protected ConcurrentHashMap<String, ClusterEntry> getRemoteEntrys() {
|
||||
return remoteEntrys;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String[] getProtocols() {
|
||||
return protocols;
|
||||
}
|
||||
|
||||
public void setProtocols(String[] protocols) {
|
||||
this.protocols = protocols;
|
||||
}
|
||||
|
||||
public int[] getPorts() {
|
||||
return ports;
|
||||
}
|
||||
|
||||
public void setPorts(int[] ports) {
|
||||
this.ports = ports;
|
||||
}
|
||||
|
||||
public AnyValue getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void setConfig(AnyValue config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public class ClusterEntry {
|
||||
|
||||
// serviceName+nodeid为主 服务的单个实例
|
||||
public String serviceid;
|
||||
|
||||
// 以协议+Rest资源名为主 服务类名
|
||||
public String serviceName;
|
||||
|
||||
public final String resourceType;
|
||||
|
||||
public final String resourceName;
|
||||
|
||||
public final String resourceid;
|
||||
|
||||
public String checkid;
|
||||
|
||||
public String checkName;
|
||||
|
||||
// http or sncp
|
||||
public String protocol;
|
||||
|
||||
// TCP or UDP
|
||||
public String netProtocol;
|
||||
|
||||
@ConvertDisabled
|
||||
public WeakReference<Service> serviceRef;
|
||||
|
||||
public InetSocketAddress address;
|
||||
|
||||
public boolean canceled;
|
||||
|
||||
public ClusterEntry(NodeServer ns, String protocol, Service service) {
|
||||
this.serviceid = generateServiceId(ns, protocol, service);
|
||||
this.serviceName = generateServiceName(ns, protocol, service);
|
||||
this.checkid = generateCheckId(ns, protocol, service);
|
||||
this.checkName = generateCheckName(ns, protocol, service);
|
||||
Class restype = Sncp.getResourceType(service);
|
||||
this.resourceType = restype.getName();
|
||||
this.resourceName = Sncp.getResourceName(service);
|
||||
this.resourceid = Sncp.resourceid(resourceName, restype);
|
||||
this.protocol = protocol;
|
||||
InetSocketAddress addr = ns.getSocketAddress();
|
||||
String host = addr.getHostString();
|
||||
if ("0.0.0.0".equals(host)) {
|
||||
host = appAddress.getHostString();
|
||||
addr = new InetSocketAddress(host, addr.getPort());
|
||||
}
|
||||
this.address = addr;
|
||||
this.serviceRef = new WeakReference(service);
|
||||
Server server = ns.getServer();
|
||||
this.netProtocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : "TCP";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonConvert.root().convertTo(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,231 +23,231 @@ import org.redkale.util.RedkaleClassLoader;
|
||||
/** @author zhangjx */
|
||||
public class ClusterModuleEngine extends ModuleEngine {
|
||||
|
||||
// 第三方服务配置资源
|
||||
// @since 2.8.0
|
||||
private Properties clusterProperties = new Properties();
|
||||
// 第三方服务配置资源
|
||||
// @since 2.8.0
|
||||
private Properties clusterProperties = new Properties();
|
||||
|
||||
// 第三方服务发现管理接口
|
||||
// @since 2.1.0
|
||||
private ClusterAgent clusterAgent;
|
||||
// 第三方服务发现管理接口
|
||||
// @since 2.1.0
|
||||
private ClusterAgent clusterAgent;
|
||||
|
||||
public ClusterModuleEngine(Application application) {
|
||||
super(application);
|
||||
}
|
||||
public ClusterModuleEngine(Application application) {
|
||||
super(application);
|
||||
}
|
||||
|
||||
/** 结束Application.init方法前被调用 */
|
||||
@Override
|
||||
public void onAppPostInit() {
|
||||
ClusterAgent cluster = null;
|
||||
AnyValue clusterConf = application.getAppConfig().getAnyValue("cluster");
|
||||
if (clusterConf != null) {
|
||||
try {
|
||||
String classVal = environment.getPropertyValue(
|
||||
clusterConf.getValue("type", clusterConf.getValue("value"))); // 兼容value字段
|
||||
if (classVal == null
|
||||
|| classVal.isEmpty()
|
||||
|| classVal.indexOf('.') < 0) { // 不包含.表示非类名,比如值: consul, nacos
|
||||
Iterator<ClusterAgentProvider> it = ServiceLoader.load(
|
||||
ClusterAgentProvider.class, application.getClassLoader())
|
||||
.iterator();
|
||||
RedkaleClassLoader.putServiceLoader(ClusterAgentProvider.class);
|
||||
while (it.hasNext()) {
|
||||
ClusterAgentProvider provider = it.next();
|
||||
if (provider != null) {
|
||||
RedkaleClassLoader.putReflectionPublicConstructors(
|
||||
provider.getClass(), provider.getClass().getName()); // loader class
|
||||
}
|
||||
if (provider != null && provider.acceptsConf(clusterConf)) {
|
||||
cluster = provider.createInstance();
|
||||
cluster.setConfig(clusterConf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cluster == null) {
|
||||
ClusterAgent cacheClusterAgent = new CacheClusterAgent();
|
||||
if (cacheClusterAgent.acceptsConf(clusterConf)) {
|
||||
cluster = cacheClusterAgent;
|
||||
cluster.setConfig(clusterConf);
|
||||
}
|
||||
}
|
||||
if (cluster == null) {
|
||||
logger.log(
|
||||
Level.SEVERE,
|
||||
"load application cluster resource, but not found name='type' value error: "
|
||||
+ clusterConf);
|
||||
}
|
||||
} else {
|
||||
Class type = application.getClassLoader().loadClass(classVal);
|
||||
if (!ClusterAgent.class.isAssignableFrom(type)) {
|
||||
logger.log(
|
||||
Level.SEVERE,
|
||||
"load application cluster resource, but not found " + ClusterAgent.class.getSimpleName()
|
||||
+ " implements class error: " + clusterConf);
|
||||
} else {
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(type, type.getName());
|
||||
cluster = (ClusterAgent) type.getDeclaredConstructor().newInstance();
|
||||
cluster.setConfig(clusterConf);
|
||||
}
|
||||
}
|
||||
// 此时不能执行cluster.init,因内置的对象可能依赖config.properties配置项
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "load application cluster resource error: " + clusterConf, e);
|
||||
}
|
||||
}
|
||||
this.clusterAgent = cluster;
|
||||
/** 结束Application.init方法前被调用 */
|
||||
@Override
|
||||
public void onAppPostInit() {
|
||||
ClusterAgent cluster = null;
|
||||
AnyValue clusterConf = application.getAppConfig().getAnyValue("cluster");
|
||||
if (clusterConf != null) {
|
||||
try {
|
||||
String classVal = environment.getPropertyValue(
|
||||
clusterConf.getValue("type", clusterConf.getValue("value"))); // 兼容value字段
|
||||
if (classVal == null
|
||||
|| classVal.isEmpty()
|
||||
|| classVal.indexOf('.') < 0) { // 不包含.表示非类名,比如值: consul, nacos
|
||||
Iterator<ClusterAgentProvider> it = ServiceLoader.load(
|
||||
ClusterAgentProvider.class, application.getClassLoader())
|
||||
.iterator();
|
||||
RedkaleClassLoader.putServiceLoader(ClusterAgentProvider.class);
|
||||
while (it.hasNext()) {
|
||||
ClusterAgentProvider provider = it.next();
|
||||
if (provider != null) {
|
||||
RedkaleClassLoader.putReflectionPublicConstructors(
|
||||
provider.getClass(), provider.getClass().getName()); // loader class
|
||||
}
|
||||
if (provider != null && provider.acceptsConf(clusterConf)) {
|
||||
cluster = provider.createInstance();
|
||||
cluster.setConfig(clusterConf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cluster == null) {
|
||||
ClusterAgent cacheClusterAgent = new CacheClusterAgent();
|
||||
if (cacheClusterAgent.acceptsConf(clusterConf)) {
|
||||
cluster = cacheClusterAgent;
|
||||
cluster.setConfig(clusterConf);
|
||||
}
|
||||
}
|
||||
if (cluster == null) {
|
||||
logger.log(
|
||||
Level.SEVERE,
|
||||
"load application cluster resource, but not found name='type' value error: "
|
||||
+ clusterConf);
|
||||
}
|
||||
} else {
|
||||
Class type = application.getClassLoader().loadClass(classVal);
|
||||
if (!ClusterAgent.class.isAssignableFrom(type)) {
|
||||
logger.log(
|
||||
Level.SEVERE,
|
||||
"load application cluster resource, but not found " + ClusterAgent.class.getSimpleName()
|
||||
+ " implements class error: " + clusterConf);
|
||||
} else {
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(type, type.getName());
|
||||
cluster = (ClusterAgent) type.getDeclaredConstructor().newInstance();
|
||||
cluster.setConfig(clusterConf);
|
||||
}
|
||||
}
|
||||
// 此时不能执行cluster.init,因内置的对象可能依赖config.properties配置项
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "load application cluster resource error: " + clusterConf, e);
|
||||
}
|
||||
}
|
||||
this.clusterAgent = cluster;
|
||||
|
||||
if (this.clusterAgent != null) {
|
||||
if (logger.isLoggable(Level.FINER)) {
|
||||
logger.log(
|
||||
Level.FINER,
|
||||
"ClusterAgent (type = " + this.clusterAgent.getClass().getSimpleName() + ") initing");
|
||||
}
|
||||
long s = System.currentTimeMillis();
|
||||
if (this.clusterAgent instanceof CacheClusterAgent) {
|
||||
String sourceName =
|
||||
((CacheClusterAgent) clusterAgent).getSourceName(); // 必须在inject前调用,需要赋值Resourcable.name
|
||||
SourceManager sourceManager = application.getResourceFactory().find(SourceManager.class);
|
||||
sourceManager.loadCacheSource(sourceName, false);
|
||||
}
|
||||
this.resourceFactory.inject(clusterAgent);
|
||||
clusterAgent.init(clusterAgent.getConfig());
|
||||
this.resourceFactory.register(ClusterAgent.class, clusterAgent);
|
||||
logger.info("ClusterAgent (type = " + this.clusterAgent.getClass().getSimpleName() + ") init in "
|
||||
+ (System.currentTimeMillis() - s) + " ms");
|
||||
}
|
||||
}
|
||||
if (this.clusterAgent != null) {
|
||||
if (logger.isLoggable(Level.FINER)) {
|
||||
logger.log(
|
||||
Level.FINER,
|
||||
"ClusterAgent (type = " + this.clusterAgent.getClass().getSimpleName() + ") initing");
|
||||
}
|
||||
long s = System.currentTimeMillis();
|
||||
if (this.clusterAgent instanceof CacheClusterAgent) {
|
||||
String sourceName =
|
||||
((CacheClusterAgent) clusterAgent).getSourceName(); // 必须在inject前调用,需要赋值Resourcable.name
|
||||
SourceManager sourceManager = application.getResourceFactory().find(SourceManager.class);
|
||||
sourceManager.loadCacheSource(sourceName, false);
|
||||
}
|
||||
this.resourceFactory.inject(clusterAgent);
|
||||
clusterAgent.init(clusterAgent.getConfig());
|
||||
this.resourceFactory.register(ClusterAgent.class, clusterAgent);
|
||||
logger.info("ClusterAgent (type = " + this.clusterAgent.getClass().getSimpleName() + ") init in "
|
||||
+ (System.currentTimeMillis() - s) + " ms");
|
||||
}
|
||||
}
|
||||
|
||||
/** 配置项加载后被调用 */
|
||||
@Override
|
||||
public void onEnvironmentLoaded(Properties allProps) {
|
||||
allProps.forEach((key, val) -> {
|
||||
if (key.toString().startsWith("redkale.cluster.")) {
|
||||
this.clusterProperties.put(key, val);
|
||||
}
|
||||
});
|
||||
}
|
||||
/** 配置项加载后被调用 */
|
||||
@Override
|
||||
public void onEnvironmentLoaded(Properties allProps) {
|
||||
allProps.forEach((key, val) -> {
|
||||
if (key.toString().startsWith("redkale.cluster.")) {
|
||||
this.clusterProperties.put(key, val);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置项变更时被调用
|
||||
*
|
||||
* @param namespace 命名空间
|
||||
* @param events 变更项
|
||||
*/
|
||||
@Override
|
||||
public void onEnvironmentChanged(String namespace, List<ResourceEvent> events) {
|
||||
Set<String> clusterRemovedKeys = new HashSet<>();
|
||||
Properties clusterChangedProps = new Properties();
|
||||
/**
|
||||
* 配置项变更时被调用
|
||||
*
|
||||
* @param namespace 命名空间
|
||||
* @param events 变更项
|
||||
*/
|
||||
@Override
|
||||
public void onEnvironmentChanged(String namespace, List<ResourceEvent> events) {
|
||||
Set<String> clusterRemovedKeys = new HashSet<>();
|
||||
Properties clusterChangedProps = new Properties();
|
||||
|
||||
for (ResourceEvent<String> event : events) {
|
||||
if (event.name().startsWith("redkale.cluster.")) {
|
||||
if (!Objects.equals(event.newValue(), this.clusterProperties.getProperty(event.name()))) {
|
||||
if (event.newValue() == null) {
|
||||
if (this.clusterProperties.containsKey(event.name())) {
|
||||
clusterRemovedKeys.add(event.name());
|
||||
}
|
||||
} else {
|
||||
clusterChangedProps.put(event.name(), event.newValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 第三方服务注册配置项的变更
|
||||
if (!clusterChangedProps.isEmpty() || !clusterRemovedKeys.isEmpty()) {
|
||||
if (this.clusterAgent != null) {
|
||||
final AnyValueWriter old =
|
||||
(AnyValueWriter) application.getAppConfig().getAnyValue("cluster");
|
||||
Properties newProps = new Properties();
|
||||
newProps.putAll(clusterProperties);
|
||||
List<ResourceEvent> changeEvents = new ArrayList<>();
|
||||
clusterChangedProps.forEach((k, v) -> {
|
||||
final String key = k.toString();
|
||||
newProps.put(k, v);
|
||||
changeEvents.add(ResourceEvent.create(
|
||||
key.substring("redkale.cluster.".length()), v, this.clusterProperties.getProperty(key)));
|
||||
});
|
||||
clusterRemovedKeys.forEach(k -> {
|
||||
final String key = k;
|
||||
newProps.remove(k);
|
||||
changeEvents.add(ResourceEvent.create(
|
||||
key.substring("redkale.cluster.".length()), null, this.clusterProperties.getProperty(key)));
|
||||
});
|
||||
if (!changeEvents.isEmpty()) {
|
||||
AnyValueWriter back = old.copy();
|
||||
try {
|
||||
old.replace(AnyValue.loadFromProperties(newProps)
|
||||
.getAnyValue("redkale")
|
||||
.getAnyValue("cluster"));
|
||||
clusterAgent.onResourceChange(changeEvents.toArray(new ResourceEvent[changeEvents.size()]));
|
||||
} catch (RuntimeException e) {
|
||||
old.replace(back); // 还原配置
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
clusterChangedProps.forEach((k, v) -> {
|
||||
sb.append(ClusterAgent.class.getSimpleName())
|
||||
.append(" skip change '")
|
||||
.append(k)
|
||||
.append("'\r\n");
|
||||
});
|
||||
clusterRemovedKeys.forEach(k -> {
|
||||
sb.append(ClusterAgent.class.getSimpleName())
|
||||
.append(" skip change '")
|
||||
.append(k)
|
||||
.append("'\r\n");
|
||||
});
|
||||
if (sb.length() > 0) {
|
||||
logger.log(Level.INFO, sb.toString());
|
||||
}
|
||||
}
|
||||
clusterRemovedKeys.forEach(k -> this.clusterProperties.remove(k));
|
||||
this.clusterProperties.putAll(clusterChangedProps);
|
||||
}
|
||||
}
|
||||
for (ResourceEvent<String> event : events) {
|
||||
if (event.name().startsWith("redkale.cluster.")) {
|
||||
if (!Objects.equals(event.newValue(), this.clusterProperties.getProperty(event.name()))) {
|
||||
if (event.newValue() == null) {
|
||||
if (this.clusterProperties.containsKey(event.name())) {
|
||||
clusterRemovedKeys.add(event.name());
|
||||
}
|
||||
} else {
|
||||
clusterChangedProps.put(event.name(), event.newValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 第三方服务注册配置项的变更
|
||||
if (!clusterChangedProps.isEmpty() || !clusterRemovedKeys.isEmpty()) {
|
||||
if (this.clusterAgent != null) {
|
||||
final AnyValueWriter old =
|
||||
(AnyValueWriter) application.getAppConfig().getAnyValue("cluster");
|
||||
Properties newProps = new Properties();
|
||||
newProps.putAll(clusterProperties);
|
||||
List<ResourceEvent> changeEvents = new ArrayList<>();
|
||||
clusterChangedProps.forEach((k, v) -> {
|
||||
final String key = k.toString();
|
||||
newProps.put(k, v);
|
||||
changeEvents.add(ResourceEvent.create(
|
||||
key.substring("redkale.cluster.".length()), v, this.clusterProperties.getProperty(key)));
|
||||
});
|
||||
clusterRemovedKeys.forEach(k -> {
|
||||
final String key = k;
|
||||
newProps.remove(k);
|
||||
changeEvents.add(ResourceEvent.create(
|
||||
key.substring("redkale.cluster.".length()), null, this.clusterProperties.getProperty(key)));
|
||||
});
|
||||
if (!changeEvents.isEmpty()) {
|
||||
AnyValueWriter back = old.copy();
|
||||
try {
|
||||
old.replace(AnyValue.loadFromProperties(newProps)
|
||||
.getAnyValue("redkale")
|
||||
.getAnyValue("cluster"));
|
||||
clusterAgent.onResourceChange(changeEvents.toArray(new ResourceEvent[changeEvents.size()]));
|
||||
} catch (RuntimeException e) {
|
||||
old.replace(back); // 还原配置
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
clusterChangedProps.forEach((k, v) -> {
|
||||
sb.append(ClusterAgent.class.getSimpleName())
|
||||
.append(" skip change '")
|
||||
.append(k)
|
||||
.append("'\r\n");
|
||||
});
|
||||
clusterRemovedKeys.forEach(k -> {
|
||||
sb.append(ClusterAgent.class.getSimpleName())
|
||||
.append(" skip change '")
|
||||
.append(k)
|
||||
.append("'\r\n");
|
||||
});
|
||||
if (sb.length() > 0) {
|
||||
logger.log(Level.INFO, sb.toString());
|
||||
}
|
||||
}
|
||||
clusterRemovedKeys.forEach(k -> this.clusterProperties.remove(k));
|
||||
this.clusterProperties.putAll(clusterChangedProps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
|
||||
*
|
||||
* @param path 配置项路径
|
||||
* @param key 配置项名称
|
||||
* @param val1 配置项原值
|
||||
* @param val2 配置项新值
|
||||
* @return MergeEnum
|
||||
*/
|
||||
@Override
|
||||
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
|
||||
if ("".equals(path) && "cluster".equals(key)) {
|
||||
return AnyValue.MergeEnum.REPLACE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
|
||||
*
|
||||
* @param path 配置项路径
|
||||
* @param key 配置项名称
|
||||
* @param val1 配置项原值
|
||||
* @param val2 配置项新值
|
||||
* @return MergeEnum
|
||||
*/
|
||||
@Override
|
||||
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
|
||||
if ("".equals(path) && "cluster".equals(key)) {
|
||||
return AnyValue.MergeEnum.REPLACE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 进入Application.start方法被调用 */
|
||||
@Override
|
||||
public void onAppPreStart() {
|
||||
if (!application.isSingletonMode() && !application.isCompileMode() && this.clusterAgent != null) {
|
||||
this.clusterAgent.register(application);
|
||||
}
|
||||
}
|
||||
/** 进入Application.start方法被调用 */
|
||||
@Override
|
||||
public void onAppPreStart() {
|
||||
if (!application.isSingletonMode() && !application.isCompileMode() && this.clusterAgent != null) {
|
||||
this.clusterAgent.register(application);
|
||||
}
|
||||
}
|
||||
|
||||
/** 服务全部启动后被调用 */
|
||||
public void onServersPostStart() {
|
||||
if (this.clusterAgent != null) {
|
||||
this.clusterAgent.start();
|
||||
}
|
||||
}
|
||||
/** 服务全部启动后被调用 */
|
||||
public void onServersPostStart() {
|
||||
if (this.clusterAgent != null) {
|
||||
this.clusterAgent.start();
|
||||
}
|
||||
}
|
||||
|
||||
/** 服务全部停掉后被调用 */
|
||||
public void onServersPostStop() {
|
||||
if (!application.isCompileMode() && clusterAgent != null) {
|
||||
if (logger.isLoggable(Level.FINER)) {
|
||||
logger.log(Level.FINER, "ClusterAgent destroying");
|
||||
}
|
||||
long s = System.currentTimeMillis();
|
||||
clusterAgent.deregister(application);
|
||||
clusterAgent.destroy(clusterAgent.getConfig());
|
||||
logger.info("ClusterAgent destroy in " + (System.currentTimeMillis() - s) + " ms");
|
||||
}
|
||||
}
|
||||
/** 服务全部停掉后被调用 */
|
||||
public void onServersPostStop() {
|
||||
if (!application.isCompileMode() && clusterAgent != null) {
|
||||
if (logger.isLoggable(Level.FINER)) {
|
||||
logger.log(Level.FINER, "ClusterAgent destroying");
|
||||
}
|
||||
long s = System.currentTimeMillis();
|
||||
clusterAgent.deregister(application);
|
||||
clusterAgent.destroy(clusterAgent.getConfig());
|
||||
logger.info("ClusterAgent destroy in " + (System.currentTimeMillis() - s) + " ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,201 +28,201 @@ import org.redkale.util.Utility;
|
||||
*/
|
||||
public class HttpClusterRpcClient extends HttpRpcClient {
|
||||
|
||||
// jdk.internal.net.http.common.Utils.DISALLOWED_HEADERS_SET
|
||||
private static final Set<String> DISALLOWED_HEADERS_SET = Utility.ofSet(
|
||||
"connection",
|
||||
"content-length",
|
||||
"date",
|
||||
"expect",
|
||||
"from",
|
||||
"host",
|
||||
"origin",
|
||||
"referer",
|
||||
"upgrade",
|
||||
"via",
|
||||
"warning");
|
||||
// jdk.internal.net.http.common.Utils.DISALLOWED_HEADERS_SET
|
||||
private static final Set<String> DISALLOWED_HEADERS_SET = Utility.ofSet(
|
||||
"connection",
|
||||
"content-length",
|
||||
"date",
|
||||
"expect",
|
||||
"from",
|
||||
"host",
|
||||
"origin",
|
||||
"referer",
|
||||
"upgrade",
|
||||
"via",
|
||||
"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)
|
||||
protected WebClient webClient;
|
||||
@Resource(name = "cluster.httpClient", required = false)
|
||||
protected WebClient webClient;
|
||||
|
||||
@Resource(name = "cluster.httpClient", required = false)
|
||||
protected java.net.http.HttpClient httpClient;
|
||||
@Resource(name = "cluster.httpClient", required = false)
|
||||
protected java.net.http.HttpClient httpClient;
|
||||
|
||||
public HttpClusterRpcClient(Application application, String resourceName, ClusterAgent clusterAgent) {
|
||||
Objects.requireNonNull(clusterAgent);
|
||||
this.localClient = new HttpLocalRpcClient(application, resourceName);
|
||||
this.clusterAgent = clusterAgent;
|
||||
}
|
||||
public HttpClusterRpcClient(Application application, String resourceName, ClusterAgent clusterAgent) {
|
||||
Objects.requireNonNull(clusterAgent);
|
||||
this.localClient = new HttpLocalRpcClient(application, resourceName);
|
||||
this.clusterAgent = clusterAgent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getNodeid() {
|
||||
return localClient.getNodeid();
|
||||
}
|
||||
@Override
|
||||
protected String getNodeid() {
|
||||
return localClient.getNodeid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<HttpResult<byte[]>> sendMessage(
|
||||
String topic, Serializable userid, String groupid, WebRequest request) {
|
||||
if (topicServletMap.computeIfAbsent(topic, t -> localClient.findHttpServlet(t) != null)) {
|
||||
return localClient.sendMessage(topic, userid, groupid, request);
|
||||
} else {
|
||||
return httpAsync(false, userid, request);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public CompletableFuture<HttpResult<byte[]>> sendMessage(
|
||||
String topic, Serializable userid, String groupid, WebRequest request) {
|
||||
if (topicServletMap.computeIfAbsent(topic, t -> localClient.findHttpServlet(t) != null)) {
|
||||
return localClient.sendMessage(topic, userid, groupid, request);
|
||||
} else {
|
||||
return httpAsync(false, userid, request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> produceMessage(
|
||||
String topic, Serializable userid, String groupid, WebRequest request) {
|
||||
if (topicServletMap.computeIfAbsent(topic, t -> localClient.findHttpServlet(t) != null)) {
|
||||
return localClient.produceMessage(topic, userid, groupid, request);
|
||||
} else {
|
||||
return httpAsync(true, userid, request).thenApply(v -> null);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public CompletableFuture<Void> produceMessage(
|
||||
String topic, Serializable userid, String groupid, WebRequest request) {
|
||||
if (topicServletMap.computeIfAbsent(topic, t -> localClient.findHttpServlet(t) != null)) {
|
||||
return localClient.produceMessage(topic, userid, groupid, request);
|
||||
} else {
|
||||
return httpAsync(true, userid, request).thenApply(v -> null);
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<HttpResult<byte[]>> httpAsync(boolean produce, Serializable userid, WebRequest req) {
|
||||
req.setTraceid(Traces.computeIfAbsent(req.getTraceid(), Traces.currentTraceid()));
|
||||
String module = req.getPath();
|
||||
module = module.substring(1, module.indexOf('/', 1));
|
||||
HttpHeaders headers = req.getHeaders();
|
||||
String resname = req.getHeader(Rest.REST_HEADER_RESNAME, "");
|
||||
final String localModule = module;
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.log(Level.FINEST, "httpAsync.queryHttpAddress: module=" + localModule + ", resname=" + resname);
|
||||
}
|
||||
return clusterAgent.queryHttpAddress("http", module, resname).thenCompose(addrs -> {
|
||||
Traces.currentTraceid(req.getTraceid());
|
||||
if (isEmpty(addrs)) {
|
||||
if (logger.isLoggable(Level.WARNING)) {
|
||||
logger.log(
|
||||
Level.WARNING,
|
||||
"httpAsync." + (produce ? "produceMessage" : "sendMessage") + " failed, module="
|
||||
+ localModule + ", resname=" + resname + ", address is empty");
|
||||
}
|
||||
return new HttpResult<byte[]>().status(404).toFuture();
|
||||
}
|
||||
final HttpHeaders clientHeaders = HttpHeaders.create();
|
||||
if (headers != null) {
|
||||
boolean ws = headers.contains("Sec-WebSocket-Key");
|
||||
headers.forEach((n, v) -> {
|
||||
if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase())
|
||||
&& (!ws
|
||||
|| (!"Connection".equals(n)
|
||||
&& !"Sec-WebSocket-Key".equals(n)
|
||||
&& !"Sec-WebSocket-Version".equals(n)))) {
|
||||
clientHeaders.add(n, v);
|
||||
}
|
||||
});
|
||||
}
|
||||
clientHeaders.set("Content-Type", "x-www-form-urlencoded");
|
||||
if (req.isRpc()) {
|
||||
clientHeaders.set(Rest.REST_HEADER_RPC, "true");
|
||||
}
|
||||
if (isNotEmpty(req.getTraceid())) {
|
||||
clientHeaders.set(Rest.REST_HEADER_TRACEID, req.getTraceid());
|
||||
}
|
||||
if (userid != null) {
|
||||
clientHeaders.set(Rest.REST_HEADER_CURRUSERID, String.valueOf(userid));
|
||||
}
|
||||
if (req.getReqConvertType() != null) {
|
||||
clientHeaders.set(
|
||||
Rest.REST_HEADER_REQ_CONVERT, req.getReqConvertType().toString());
|
||||
}
|
||||
if (req.getRespConvertType() != null) {
|
||||
clientHeaders.set(
|
||||
Rest.REST_HEADER_RESP_CONVERT, req.getRespConvertType().toString());
|
||||
}
|
||||
private CompletableFuture<HttpResult<byte[]>> httpAsync(boolean produce, Serializable userid, WebRequest req) {
|
||||
req.setTraceid(Traces.computeIfAbsent(req.getTraceid(), Traces.currentTraceid()));
|
||||
String module = req.getPath();
|
||||
module = module.substring(1, module.indexOf('/', 1));
|
||||
HttpHeaders headers = req.getHeaders();
|
||||
String resname = req.getHeader(Rest.REST_HEADER_RESNAME, "");
|
||||
final String localModule = module;
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.log(Level.FINEST, "httpAsync.queryHttpAddress: module=" + localModule + ", resname=" + resname);
|
||||
}
|
||||
return clusterAgent.queryHttpAddress("http", module, resname).thenCompose(addrs -> {
|
||||
Traces.currentTraceid(req.getTraceid());
|
||||
if (isEmpty(addrs)) {
|
||||
if (logger.isLoggable(Level.WARNING)) {
|
||||
logger.log(
|
||||
Level.WARNING,
|
||||
"httpAsync." + (produce ? "produceMessage" : "sendMessage") + " failed, module="
|
||||
+ localModule + ", resname=" + resname + ", address is empty");
|
||||
}
|
||||
return new HttpResult<byte[]>().status(404).toFuture();
|
||||
}
|
||||
final HttpHeaders clientHeaders = HttpHeaders.create();
|
||||
if (headers != null) {
|
||||
boolean ws = headers.contains("Sec-WebSocket-Key");
|
||||
headers.forEach((n, v) -> {
|
||||
if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase())
|
||||
&& (!ws
|
||||
|| (!"Connection".equals(n)
|
||||
&& !"Sec-WebSocket-Key".equals(n)
|
||||
&& !"Sec-WebSocket-Version".equals(n)))) {
|
||||
clientHeaders.add(n, v);
|
||||
}
|
||||
});
|
||||
}
|
||||
clientHeaders.set("Content-Type", "x-www-form-urlencoded");
|
||||
if (req.isRpc()) {
|
||||
clientHeaders.set(Rest.REST_HEADER_RPC, "true");
|
||||
}
|
||||
if (isNotEmpty(req.getTraceid())) {
|
||||
clientHeaders.set(Rest.REST_HEADER_TRACEID, req.getTraceid());
|
||||
}
|
||||
if (userid != null) {
|
||||
clientHeaders.set(Rest.REST_HEADER_CURRUSERID, String.valueOf(userid));
|
||||
}
|
||||
if (req.getReqConvertType() != null) {
|
||||
clientHeaders.set(
|
||||
Rest.REST_HEADER_REQ_CONVERT, req.getReqConvertType().toString());
|
||||
}
|
||||
if (req.getRespConvertType() != null) {
|
||||
clientHeaders.set(
|
||||
Rest.REST_HEADER_RESP_CONVERT, req.getRespConvertType().toString());
|
||||
}
|
||||
|
||||
if (webClient != null) {
|
||||
WebRequest newReq = req.copy().headers(clientHeaders);
|
||||
InetSocketAddress addr = randomAddress(newReq, addrs);
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.log(
|
||||
Level.FINEST,
|
||||
"httpAsync: module=" + localModule + ", resname=" + resname + ", addr=" + addr);
|
||||
}
|
||||
return (CompletableFuture) webClient.sendAsync(addr, newReq);
|
||||
}
|
||||
byte[] clientBody = null;
|
||||
if (isNotEmpty(req.getBody())) {
|
||||
String paramstr = req.getParametersToString();
|
||||
if (paramstr != null) {
|
||||
if (req.getPath().indexOf('?') > 0) {
|
||||
req.setPath(req.getPath() + "&" + paramstr);
|
||||
} else {
|
||||
req.setPath(req.getPath() + "?" + paramstr);
|
||||
}
|
||||
}
|
||||
clientBody = req.getBody();
|
||||
} else {
|
||||
String paramstr = req.getParametersToString();
|
||||
if (paramstr != null) {
|
||||
clientBody = paramstr.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.log(
|
||||
Level.FINEST,
|
||||
"httpAsync: module=" + localModule + ", resname=" + resname + ", enter sendEachAddressAsync");
|
||||
}
|
||||
return sendEachAddressAsync(req, req.requestPath(), clientHeaders, clientBody, addrs.iterator());
|
||||
});
|
||||
}
|
||||
if (webClient != null) {
|
||||
WebRequest newReq = req.copy().headers(clientHeaders);
|
||||
InetSocketAddress addr = randomAddress(newReq, addrs);
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.log(
|
||||
Level.FINEST,
|
||||
"httpAsync: module=" + localModule + ", resname=" + resname + ", addr=" + addr);
|
||||
}
|
||||
return (CompletableFuture) webClient.sendAsync(addr, newReq);
|
||||
}
|
||||
byte[] clientBody = null;
|
||||
if (isNotEmpty(req.getBody())) {
|
||||
String paramstr = req.getParametersToString();
|
||||
if (paramstr != null) {
|
||||
if (req.getPath().indexOf('?') > 0) {
|
||||
req.setPath(req.getPath() + "&" + paramstr);
|
||||
} else {
|
||||
req.setPath(req.getPath() + "?" + paramstr);
|
||||
}
|
||||
}
|
||||
clientBody = req.getBody();
|
||||
} else {
|
||||
String paramstr = req.getParametersToString();
|
||||
if (paramstr != null) {
|
||||
clientBody = paramstr.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.log(
|
||||
Level.FINEST,
|
||||
"httpAsync: module=" + localModule + ", resname=" + resname + ", enter sendEachAddressAsync");
|
||||
}
|
||||
return sendEachAddressAsync(req, req.requestPath(), clientHeaders, clientBody, addrs.iterator());
|
||||
});
|
||||
}
|
||||
|
||||
protected InetSocketAddress randomAddress(WebRequest req, Set<InetSocketAddress> addrs) {
|
||||
InetSocketAddress[] array = addrs.toArray(new InetSocketAddress[addrs.size()]);
|
||||
return array[ThreadLocalRandom.current().nextInt(array.length)];
|
||||
}
|
||||
protected InetSocketAddress randomAddress(WebRequest req, Set<InetSocketAddress> addrs) {
|
||||
InetSocketAddress[] array = addrs.toArray(new InetSocketAddress[addrs.size()]);
|
||||
return array[ThreadLocalRandom.current().nextInt(array.length)];
|
||||
}
|
||||
|
||||
protected CompletableFuture<HttpResult<byte[]>> sendEachAddressAsync(
|
||||
WebRequest req,
|
||||
String requestPath,
|
||||
final HttpHeaders clientHeaders,
|
||||
byte[] clientBody,
|
||||
Iterator<InetSocketAddress> it) {
|
||||
if (!it.hasNext()) {
|
||||
return new HttpResult<byte[]>().status(404).toFuture();
|
||||
}
|
||||
InetSocketAddress addr = it.next();
|
||||
String host = addr.getPort() > 0 && addr.getPort() != 80
|
||||
? (addr.getHostString() + ":" + addr.getPort())
|
||||
: addr.getHostString();
|
||||
String url = "http://" + host + requestPath;
|
||||
if (logger.isLoggable(Level.FINER)) {
|
||||
logger.log(
|
||||
Level.FINER,
|
||||
"sendEachAddressAsync: url: " + url + ", body: "
|
||||
+ (clientBody != null ? new String(clientBody, StandardCharsets.UTF_8) : "") + ", headers: "
|
||||
+ clientHeaders);
|
||||
}
|
||||
java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.timeout(Duration.ofMillis(10_000))
|
||||
// 存在sendHeader后不发送body数据的问题, java.net.http.HttpRequest的bug?
|
||||
.method("POST", createBodyPublisher(clientBody));
|
||||
clientHeaders.forEach(builder::header);
|
||||
return httpClient
|
||||
.sendAsync(builder.build(), java.net.http.HttpResponse.BodyHandlers.ofByteArray())
|
||||
.thenApply((java.net.http.HttpResponse<byte[]> resp) -> {
|
||||
Traces.currentTraceid(req.getTraceid());
|
||||
final int rs = resp.statusCode();
|
||||
if (rs != 200) {
|
||||
return new HttpResult<byte[]>().status(rs);
|
||||
}
|
||||
return new HttpResult<>(resp.body());
|
||||
});
|
||||
}
|
||||
protected CompletableFuture<HttpResult<byte[]>> sendEachAddressAsync(
|
||||
WebRequest req,
|
||||
String requestPath,
|
||||
final HttpHeaders clientHeaders,
|
||||
byte[] clientBody,
|
||||
Iterator<InetSocketAddress> it) {
|
||||
if (!it.hasNext()) {
|
||||
return new HttpResult<byte[]>().status(404).toFuture();
|
||||
}
|
||||
InetSocketAddress addr = it.next();
|
||||
String host = addr.getPort() > 0 && addr.getPort() != 80
|
||||
? (addr.getHostString() + ":" + addr.getPort())
|
||||
: addr.getHostString();
|
||||
String url = "http://" + host + requestPath;
|
||||
if (logger.isLoggable(Level.FINER)) {
|
||||
logger.log(
|
||||
Level.FINER,
|
||||
"sendEachAddressAsync: url: " + url + ", body: "
|
||||
+ (clientBody != null ? new String(clientBody, StandardCharsets.UTF_8) : "") + ", headers: "
|
||||
+ clientHeaders);
|
||||
}
|
||||
java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.timeout(Duration.ofMillis(10_000))
|
||||
// 存在sendHeader后不发送body数据的问题, java.net.http.HttpRequest的bug?
|
||||
.method("POST", createBodyPublisher(clientBody));
|
||||
clientHeaders.forEach(builder::header);
|
||||
return httpClient
|
||||
.sendAsync(builder.build(), java.net.http.HttpResponse.BodyHandlers.ofByteArray())
|
||||
.thenApply((java.net.http.HttpResponse<byte[]> resp) -> {
|
||||
Traces.currentTraceid(req.getTraceid());
|
||||
final int rs = resp.statusCode();
|
||||
if (rs != 200) {
|
||||
return new HttpResult<byte[]>().status(rs);
|
||||
}
|
||||
return new HttpResult<>(resp.body());
|
||||
});
|
||||
}
|
||||
|
||||
private static java.net.http.HttpRequest.BodyPublisher createBodyPublisher(byte[] clientBody) {
|
||||
return clientBody == null
|
||||
? java.net.http.HttpRequest.BodyPublishers.noBody()
|
||||
: java.net.http.HttpRequest.BodyPublishers.ofByteArray(clientBody);
|
||||
}
|
||||
private static java.net.http.HttpRequest.BodyPublisher createBodyPublisher(byte[] clientBody) {
|
||||
return clientBody == null
|
||||
? java.net.http.HttpRequest.BodyPublishers.noBody()
|
||||
: java.net.http.HttpRequest.BodyPublishers.ofByteArray(clientBody);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,320 +32,320 @@ import org.redkale.util.Traces;
|
||||
*/
|
||||
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) {
|
||||
this.application = application;
|
||||
this.resourceName = resourceName;
|
||||
}
|
||||
public HttpLocalRpcClient(Application application, String resourceName) {
|
||||
this.application = application;
|
||||
this.resourceName = resourceName;
|
||||
}
|
||||
|
||||
private HttpServer httpServer() {
|
||||
if (this.currServer == null) {
|
||||
NodeHttpServer nodeHttpServer = null;
|
||||
List<NodeServer> nodeServers = application.getNodeServers();
|
||||
for (NodeServer n : nodeServers) {
|
||||
if (n.getClass() == NodeHttpServer.class
|
||||
&& Objects.equals(
|
||||
resourceName,
|
||||
((NodeHttpServer) n).getHttpServer().getName())) {
|
||||
nodeHttpServer = (NodeHttpServer) n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nodeHttpServer == null) {
|
||||
for (NodeServer n : nodeServers) {
|
||||
if (n.getClass() == NodeHttpServer.class) {
|
||||
nodeHttpServer = (NodeHttpServer) n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodeHttpServer == null) {
|
||||
throw new HttpException("Not found HttpServer");
|
||||
}
|
||||
this.currServer = nodeHttpServer.getServer();
|
||||
}
|
||||
return this.currServer;
|
||||
}
|
||||
private HttpServer httpServer() {
|
||||
if (this.currServer == null) {
|
||||
NodeHttpServer nodeHttpServer = null;
|
||||
List<NodeServer> nodeServers = application.getNodeServers();
|
||||
for (NodeServer n : nodeServers) {
|
||||
if (n.getClass() == NodeHttpServer.class
|
||||
&& Objects.equals(
|
||||
resourceName,
|
||||
((NodeHttpServer) n).getHttpServer().getName())) {
|
||||
nodeHttpServer = (NodeHttpServer) n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nodeHttpServer == null) {
|
||||
for (NodeServer n : nodeServers) {
|
||||
if (n.getClass() == NodeHttpServer.class) {
|
||||
nodeHttpServer = (NodeHttpServer) n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodeHttpServer == null) {
|
||||
throw new HttpException("Not found HttpServer");
|
||||
}
|
||||
this.currServer = nodeHttpServer.getServer();
|
||||
}
|
||||
return this.currServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getNodeid() {
|
||||
return application.getNodeid();
|
||||
}
|
||||
@Override
|
||||
protected String getNodeid() {
|
||||
return application.getNodeid();
|
||||
}
|
||||
|
||||
protected HttpContext context() {
|
||||
return httpServer().getContext();
|
||||
}
|
||||
protected HttpContext context() {
|
||||
return httpServer().getContext();
|
||||
}
|
||||
|
||||
protected HttpDispatcherServlet dispatcherServlet() {
|
||||
return (HttpDispatcherServlet) httpServer().getDispatcherServlet();
|
||||
}
|
||||
protected HttpDispatcherServlet dispatcherServlet() {
|
||||
return (HttpDispatcherServlet) httpServer().getDispatcherServlet();
|
||||
}
|
||||
|
||||
public HttpServlet findHttpServlet(String topic) {
|
||||
return dispatcherServlet().findServletByTopic(topic);
|
||||
}
|
||||
public HttpServlet findHttpServlet(String topic) {
|
||||
return dispatcherServlet().findServletByTopic(topic);
|
||||
}
|
||||
|
||||
public HttpServlet findHttpServlet(WebRequest request) {
|
||||
return dispatcherServlet().findServletByTopic(generateHttpReqTopic(request, request.getContextPath()));
|
||||
}
|
||||
public HttpServlet findHttpServlet(WebRequest request) {
|
||||
return dispatcherServlet().findServletByTopic(generateHttpReqTopic(request, request.getContextPath()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> CompletableFuture<T> sendMessage(WebRequest request, Type type) {
|
||||
return sendMessage((Serializable) null, (String) null, request, type);
|
||||
}
|
||||
@Override
|
||||
public <T> CompletableFuture<T> sendMessage(WebRequest request, Type type) {
|
||||
return sendMessage((Serializable) null, (String) null, request, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> CompletableFuture<T> sendMessage(Serializable userid, WebRequest request, Type type) {
|
||||
return sendMessage(userid, (String) null, request, type);
|
||||
}
|
||||
@Override
|
||||
public <T> CompletableFuture<T> sendMessage(Serializable userid, WebRequest request, Type type) {
|
||||
return sendMessage(userid, (String) null, request, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> CompletableFuture<T> sendMessage(Serializable userid, String groupid, WebRequest request, Type type) {
|
||||
if (isEmpty(request.getTraceid())) {
|
||||
request.setTraceid(Traces.currentTraceid());
|
||||
}
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
String topic = generateHttpReqTopic(request, request.getContextPath());
|
||||
HttpServlet servlet = findHttpServlet(topic);
|
||||
if (servlet == null) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.log(Level.FINE, "sendMessage: request=" + request + ", not found servlet");
|
||||
}
|
||||
future.completeExceptionally(new HttpException("404 Not Found " + topic));
|
||||
return future;
|
||||
}
|
||||
HttpRequest req = new HttpMessageLocalRequest(context(), request, userid);
|
||||
HttpResponse resp = new HttpMessageLocalResponse(req, future);
|
||||
try {
|
||||
servlet.execute(req, resp);
|
||||
} catch (Exception e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
return future;
|
||||
}
|
||||
@Override
|
||||
public <T> CompletableFuture<T> sendMessage(Serializable userid, String groupid, WebRequest request, Type type) {
|
||||
if (isEmpty(request.getTraceid())) {
|
||||
request.setTraceid(Traces.currentTraceid());
|
||||
}
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
String topic = generateHttpReqTopic(request, request.getContextPath());
|
||||
HttpServlet servlet = findHttpServlet(topic);
|
||||
if (servlet == null) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.log(Level.FINE, "sendMessage: request=" + request + ", not found servlet");
|
||||
}
|
||||
future.completeExceptionally(new HttpException("404 Not Found " + topic));
|
||||
return future;
|
||||
}
|
||||
HttpRequest req = new HttpMessageLocalRequest(context(), request, userid);
|
||||
HttpResponse resp = new HttpMessageLocalResponse(req, future);
|
||||
try {
|
||||
servlet.execute(req, resp);
|
||||
} catch (Exception e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<HttpResult<byte[]>> sendMessage(
|
||||
String topic, Serializable userid, String groupid, WebRequest request) {
|
||||
if (isEmpty(request.getTraceid())) {
|
||||
request.setTraceid(Traces.currentTraceid());
|
||||
}
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
HttpServlet servlet = findHttpServlet(topic);
|
||||
if (servlet == null) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.log(Level.FINE, "sendMessage: request=" + request + ", not found servlet");
|
||||
}
|
||||
future.complete(new HttpResult().status(404));
|
||||
return future;
|
||||
}
|
||||
HttpRequest req = new HttpMessageLocalRequest(context(), request, userid);
|
||||
HttpResponse resp = new HttpMessageLocalResponse(req, future);
|
||||
try {
|
||||
servlet.execute(req, resp);
|
||||
} catch (Exception e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
return future.thenApply(rs -> {
|
||||
Traces.currentTraceid(request.getTraceid());
|
||||
if (rs == null) {
|
||||
return new HttpResult();
|
||||
}
|
||||
if (rs instanceof HttpResult) {
|
||||
Object result = ((HttpResult) rs).getResult();
|
||||
if (result == null || result instanceof byte[]) {
|
||||
return (HttpResult) rs;
|
||||
}
|
||||
return new HttpResult(JsonConvert.root().convertToBytes(result));
|
||||
}
|
||||
return new HttpResult(JsonConvert.root().convertToBytes(rs));
|
||||
});
|
||||
}
|
||||
@Override
|
||||
public CompletableFuture<HttpResult<byte[]>> sendMessage(
|
||||
String topic, Serializable userid, String groupid, WebRequest request) {
|
||||
if (isEmpty(request.getTraceid())) {
|
||||
request.setTraceid(Traces.currentTraceid());
|
||||
}
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
HttpServlet servlet = findHttpServlet(topic);
|
||||
if (servlet == null) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.log(Level.FINE, "sendMessage: request=" + request + ", not found servlet");
|
||||
}
|
||||
future.complete(new HttpResult().status(404));
|
||||
return future;
|
||||
}
|
||||
HttpRequest req = new HttpMessageLocalRequest(context(), request, userid);
|
||||
HttpResponse resp = new HttpMessageLocalResponse(req, future);
|
||||
try {
|
||||
servlet.execute(req, resp);
|
||||
} catch (Exception e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
return future.thenApply(rs -> {
|
||||
Traces.currentTraceid(request.getTraceid());
|
||||
if (rs == null) {
|
||||
return new HttpResult();
|
||||
}
|
||||
if (rs instanceof HttpResult) {
|
||||
Object result = ((HttpResult) rs).getResult();
|
||||
if (result == null || result instanceof byte[]) {
|
||||
return (HttpResult) rs;
|
||||
}
|
||||
return new HttpResult(JsonConvert.root().convertToBytes(result));
|
||||
}
|
||||
return new HttpResult(JsonConvert.root().convertToBytes(rs));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> produceMessage(
|
||||
String topic, Serializable userid, String groupid, WebRequest request) {
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
HttpDispatcherServlet ps = dispatcherServlet();
|
||||
HttpServlet servlet = ps.findServletByTopic(topic);
|
||||
if (servlet == null) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.log(Level.FINE, "produceMessage: request=" + request + ", not found servlet");
|
||||
}
|
||||
future.completeExceptionally(new RuntimeException("404 Not Found " + topic));
|
||||
return future;
|
||||
}
|
||||
HttpRequest req = new HttpMessageLocalRequest(context(), request, userid);
|
||||
HttpResponse resp = new HttpMessageLocalResponse(req, null);
|
||||
try {
|
||||
servlet.execute(req, resp);
|
||||
} catch (Exception e) {
|
||||
throw new RedkaleException(e);
|
||||
}
|
||||
return future.thenApply(rs -> {
|
||||
Traces.currentTraceid(request.getTraceid());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
@Override
|
||||
public CompletableFuture<Void> produceMessage(
|
||||
String topic, Serializable userid, String groupid, WebRequest request) {
|
||||
CompletableFuture future = new CompletableFuture();
|
||||
HttpDispatcherServlet ps = dispatcherServlet();
|
||||
HttpServlet servlet = ps.findServletByTopic(topic);
|
||||
if (servlet == null) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.log(Level.FINE, "produceMessage: request=" + request + ", not found servlet");
|
||||
}
|
||||
future.completeExceptionally(new RuntimeException("404 Not Found " + topic));
|
||||
return future;
|
||||
}
|
||||
HttpRequest req = new HttpMessageLocalRequest(context(), request, userid);
|
||||
HttpResponse resp = new HttpMessageLocalResponse(req, null);
|
||||
try {
|
||||
servlet.execute(req, resp);
|
||||
} catch (Exception e) {
|
||||
throw new RedkaleException(e);
|
||||
}
|
||||
return future.thenApply(rs -> {
|
||||
Traces.currentTraceid(request.getTraceid());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public static class HttpMessageLocalRequest extends HttpRequest {
|
||||
public static class HttpMessageLocalRequest extends HttpRequest {
|
||||
|
||||
public HttpMessageLocalRequest(HttpContext context, WebRequest req, Serializable userid) {
|
||||
super(context, req);
|
||||
if (userid != null) {
|
||||
this.currentUserid = userid;
|
||||
}
|
||||
}
|
||||
}
|
||||
public HttpMessageLocalRequest(HttpContext context, WebRequest req, Serializable userid) {
|
||||
super(context, req);
|
||||
if (userid != null) {
|
||||
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) {
|
||||
super(req.getContext(), req, null);
|
||||
this.future = future;
|
||||
}
|
||||
public HttpMessageLocalResponse(HttpRequest req, CompletableFuture future) {
|
||||
super(req.getContext(), req, null);
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishJson(final Convert convert, final Type type, final Object obj) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
future.complete(obj);
|
||||
}
|
||||
@Override
|
||||
public void finishJson(final Convert convert, final Type type, final Object obj) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
future.complete(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish(final Convert convert, Type type, org.redkale.service.RetResult ret) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
future.complete(ret);
|
||||
}
|
||||
@Override
|
||||
public void finish(final Convert convert, Type type, org.redkale.service.RetResult ret) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
future.complete(ret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish(final Convert convert, final Type type, Object obj) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
if (obj instanceof CompletableFuture) {
|
||||
((CompletableFuture) obj).whenComplete((r, t) -> {
|
||||
if (t == null) {
|
||||
future.complete(r);
|
||||
} else {
|
||||
future.completeExceptionally((Throwable) t);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
future.complete(obj);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void finish(final Convert convert, final Type type, Object obj) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
if (obj instanceof CompletableFuture) {
|
||||
((CompletableFuture) obj).whenComplete((r, t) -> {
|
||||
if (t == null) {
|
||||
future.complete(r);
|
||||
} else {
|
||||
future.completeExceptionally((Throwable) t);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
future.complete(obj);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish(String obj) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
future.complete(obj == null ? "" : obj);
|
||||
}
|
||||
@Override
|
||||
public void finish(String obj) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
future.complete(obj == null ? "" : obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish304() {
|
||||
finish(304, null);
|
||||
}
|
||||
@Override
|
||||
public void finish304() {
|
||||
finish(304, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish404() {
|
||||
finish(404, null);
|
||||
}
|
||||
@Override
|
||||
public void finish404() {
|
||||
finish(404, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish500() {
|
||||
finish(500, null);
|
||||
}
|
||||
@Override
|
||||
public void finish500() {
|
||||
finish(500, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish504() {
|
||||
finish(504, null);
|
||||
}
|
||||
@Override
|
||||
public void finish504() {
|
||||
finish(504, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish(int status, String msg) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
if (status == 0 || status == 200) {
|
||||
future.complete(msg == null ? "" : msg);
|
||||
} else {
|
||||
future.complete(new HttpResult(msg == null ? "" : msg).status(status));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void finish(int status, String msg) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
if (status == 0 || status == 200) {
|
||||
future.complete(msg == null ? "" : msg);
|
||||
} else {
|
||||
future.complete(new HttpResult(msg == null ? "" : msg).status(status));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish(final Convert convert, Type valueType, HttpResult result) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
if (convert != null) {
|
||||
result.convert(convert);
|
||||
}
|
||||
future.complete(result);
|
||||
}
|
||||
@Override
|
||||
public void finish(final Convert convert, Type valueType, HttpResult result) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
if (convert != null) {
|
||||
result.convert(convert);
|
||||
}
|
||||
future.complete(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish(boolean kill, final byte[] bs, int offset, int length) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
if (offset == 0 && bs.length == length) {
|
||||
future.complete(bs);
|
||||
} else {
|
||||
future.complete(Arrays.copyOfRange(bs, offset, offset + length));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void finish(boolean kill, final byte[] bs, int offset, int length) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
if (offset == 0 && bs.length == length) {
|
||||
future.complete(bs);
|
||||
} else {
|
||||
future.complete(Arrays.copyOfRange(bs, offset, offset + length));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
byte[] rs = (offset == 0 && bs.length == length) ? bs : Arrays.copyOfRange(bs, offset, offset + length);
|
||||
future.complete(rs);
|
||||
}
|
||||
@Override
|
||||
public void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
byte[] rs = (offset == 0 && bs.length == length) ? bs : Arrays.copyOfRange(bs, offset, offset + length);
|
||||
future.complete(rs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishBuffer(boolean kill, ByteBuffer buffer) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
byte[] bs = new byte[buffer.remaining()];
|
||||
buffer.get(bs);
|
||||
future.complete(bs);
|
||||
}
|
||||
@Override
|
||||
public void finishBuffer(boolean kill, ByteBuffer buffer) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
byte[] bs = new byte[buffer.remaining()];
|
||||
buffer.get(bs);
|
||||
future.complete(bs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishBuffers(boolean kill, ByteBuffer... buffers) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
int size = 0;
|
||||
for (ByteBuffer buf : buffers) {
|
||||
size += buf.remaining();
|
||||
}
|
||||
byte[] bs = new byte[size];
|
||||
int index = 0;
|
||||
for (ByteBuffer buf : buffers) {
|
||||
int r = buf.remaining();
|
||||
buf.get(bs, index, r);
|
||||
index += r;
|
||||
}
|
||||
future.complete(bs);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void finishBuffers(boolean kill, ByteBuffer... buffers) {
|
||||
if (future == null) {
|
||||
return;
|
||||
}
|
||||
int size = 0;
|
||||
for (ByteBuffer buf : buffers) {
|
||||
size += buf.remaining();
|
||||
}
|
||||
byte[] bs = new byte[size];
|
||||
int index = 0;
|
||||
for (ByteBuffer buf : buffers) {
|
||||
int r = buf.remaining();
|
||||
buf.get(bs, index, r);
|
||||
index += r;
|
||||
}
|
||||
future.complete(bs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,61 +21,61 @@ import org.redkale.util.*;
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public AnyDecoder(final ConvertFactory factory) {
|
||||
this(mapCreator, mapObjectType, collectionCreator, collectionObjectType, factory.loadDecoder(String.class));
|
||||
}
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param factory ConvertFactory
|
||||
*/
|
||||
public AnyDecoder(final ConvertFactory factory) {
|
||||
this(mapCreator, mapObjectType, collectionCreator, collectionObjectType, factory.loadDecoder(String.class));
|
||||
}
|
||||
|
||||
protected AnyDecoder(
|
||||
Creator<? extends Map> mapCreator,
|
||||
Type mapObjectType,
|
||||
Creator<? extends Collection> listCreator,
|
||||
Type listObjectType,
|
||||
Decodeable<Reader, String> keyDecoder) {
|
||||
this.stringDecoder = keyDecoder;
|
||||
this.collectionDecoder = new CollectionDecoder(listObjectType, Object.class, listCreator, this);
|
||||
this.mapDecoder = new MapDecoder(mapObjectType, String.class, Object.class, mapCreator, keyDecoder, this);
|
||||
}
|
||||
protected AnyDecoder(
|
||||
Creator<? extends Map> mapCreator,
|
||||
Type mapObjectType,
|
||||
Creator<? extends Collection> listCreator,
|
||||
Type listObjectType,
|
||||
Decodeable<Reader, String> keyDecoder) {
|
||||
this.stringDecoder = keyDecoder;
|
||||
this.collectionDecoder = new CollectionDecoder(listObjectType, Object.class, listCreator, this);
|
||||
this.mapDecoder = new MapDecoder(mapObjectType, String.class, Object.class, mapCreator, keyDecoder, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T convertFrom(Reader in) {
|
||||
ValueType vt = in.readType();
|
||||
if (vt == null) {
|
||||
return null;
|
||||
}
|
||||
switch (vt) {
|
||||
case ARRAY:
|
||||
return (T) this.collectionDecoder.convertFrom(in);
|
||||
case MAP:
|
||||
return (T) this.mapDecoder.convertFrom(in);
|
||||
}
|
||||
return (T) stringFrom(in);
|
||||
}
|
||||
@Override
|
||||
public T convertFrom(Reader in) {
|
||||
ValueType vt = in.readType();
|
||||
if (vt == null) {
|
||||
return null;
|
||||
}
|
||||
switch (vt) {
|
||||
case ARRAY:
|
||||
return (T) this.collectionDecoder.convertFrom(in);
|
||||
case MAP:
|
||||
return (T) this.mapDecoder.convertFrom(in);
|
||||
}
|
||||
return (T) stringFrom(in);
|
||||
}
|
||||
|
||||
protected T stringFrom(Reader in) {
|
||||
return (T) this.stringDecoder.convertFrom(in);
|
||||
}
|
||||
protected T stringFrom(Reader in) {
|
||||
return (T) this.stringDecoder.convertFrom(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return void.class;
|
||||
}
|
||||
@Override
|
||||
public Type getType() {
|
||||
return void.class;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,39 +17,39 @@ import java.lang.reflect.Type;
|
||||
*/
|
||||
public final class AnyEncoder<T> implements Encodeable<Writer, T> {
|
||||
|
||||
final ConvertFactory factory;
|
||||
final ConvertFactory factory;
|
||||
|
||||
AnyEncoder(ConvertFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
AnyEncoder(ConvertFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void convertTo(final Writer out, final T value) {
|
||||
if (value == null) {
|
||||
out.writeClassName(null);
|
||||
out.writeNull();
|
||||
} else {
|
||||
Class clazz = value.getClass();
|
||||
if (clazz == Object.class) {
|
||||
out.writeObjectB(value);
|
||||
out.writeObjectE(value);
|
||||
return;
|
||||
}
|
||||
if (out.needWriteClassName()) {
|
||||
out.writeClassName(factory.getEntityAlias(clazz));
|
||||
}
|
||||
factory.loadEncoder(clazz).convertTo(out, value);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void convertTo(final Writer out, final T value) {
|
||||
if (value == null) {
|
||||
out.writeClassName(null);
|
||||
out.writeNull();
|
||||
} else {
|
||||
Class clazz = value.getClass();
|
||||
if (clazz == Object.class) {
|
||||
out.writeObjectB(value);
|
||||
out.writeObjectE(value);
|
||||
return;
|
||||
}
|
||||
if (out.needWriteClassName()) {
|
||||
out.writeClassName(factory.getEntityAlias(clazz));
|
||||
}
|
||||
factory.loadEncoder(clazz).convertTo(out, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Object.class;
|
||||
}
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean specifyable() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean specifyable() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,19 +19,19 @@ import org.redkale.util.AnyValue;
|
||||
*/
|
||||
public class AnyValueDecoder<R extends Reader> implements Decodeable<R, AnyValue> {
|
||||
|
||||
protected final ConvertFactory factory;
|
||||
protected final ConvertFactory factory;
|
||||
|
||||
public AnyValueDecoder(final ConvertFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
public AnyValueDecoder(final ConvertFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnyValue convertFrom(R in) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public AnyValue convertFrom(R in) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return AnyValue.class;
|
||||
}
|
||||
@Override
|
||||
public Type getType() {
|
||||
return AnyValue.class;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,13 +19,13 @@ import org.redkale.util.AnyValue;
|
||||
*/
|
||||
public class AnyValueEncoder<W extends Writer> implements Encodeable<W, AnyValue> {
|
||||
|
||||
@Override
|
||||
public void convertTo(W out, AnyValue value) {
|
||||
// do nothing
|
||||
}
|
||||
@Override
|
||||
public void convertTo(W out, AnyValue value) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return AnyValue.class;
|
||||
}
|
||||
@Override
|
||||
public Type getType() {
|
||||
return AnyValue.class;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,138 +24,138 @@ import org.redkale.util.Creator;
|
||||
@SuppressWarnings("unchecked")
|
||||
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) {
|
||||
this.type = type;
|
||||
try {
|
||||
if (type instanceof GenericArrayType) {
|
||||
Type t = ((GenericArrayType) type).getGenericComponentType();
|
||||
this.componentType = t instanceof TypeVariable ? Object.class : t;
|
||||
} else if ((type instanceof Class) && ((Class) type).isArray()) {
|
||||
this.componentType = ((Class) type).getComponentType();
|
||||
} else {
|
||||
throw new ConvertException("(" + type + ") is not a array type");
|
||||
}
|
||||
if (this.componentType instanceof ParameterizedType) {
|
||||
this.componentClass = (Class) ((ParameterizedType) this.componentType).getRawType();
|
||||
} else {
|
||||
this.componentClass = (Class) this.componentType;
|
||||
}
|
||||
factory.register(type, this);
|
||||
this.componentDecoder = factory.loadDecoder(this.componentType);
|
||||
this.componentArrayFunction = Creator.funcArray(this.componentClass);
|
||||
} finally {
|
||||
inited = true;
|
||||
lock.lock();
|
||||
try {
|
||||
condition.signalAll();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
public ArrayDecoder(final ConvertFactory factory, final Type type) {
|
||||
this.type = type;
|
||||
try {
|
||||
if (type instanceof GenericArrayType) {
|
||||
Type t = ((GenericArrayType) type).getGenericComponentType();
|
||||
this.componentType = t instanceof TypeVariable ? Object.class : t;
|
||||
} else if ((type instanceof Class) && ((Class) type).isArray()) {
|
||||
this.componentType = ((Class) type).getComponentType();
|
||||
} else {
|
||||
throw new ConvertException("(" + type + ") is not a array type");
|
||||
}
|
||||
if (this.componentType instanceof ParameterizedType) {
|
||||
this.componentClass = (Class) ((ParameterizedType) this.componentType).getRawType();
|
||||
} else {
|
||||
this.componentClass = (Class) this.componentType;
|
||||
}
|
||||
factory.register(type, this);
|
||||
this.componentDecoder = factory.loadDecoder(this.componentType);
|
||||
this.componentArrayFunction = Creator.funcArray(this.componentClass);
|
||||
} finally {
|
||||
inited = true;
|
||||
lock.lock();
|
||||
try {
|
||||
condition.signalAll();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T[] convertFrom(Reader in) {
|
||||
return convertFrom(in, null);
|
||||
}
|
||||
@Override
|
||||
public T[] convertFrom(Reader in) {
|
||||
return convertFrom(in, null);
|
||||
}
|
||||
|
||||
public T[] convertFrom(Reader in, DeMember member) {
|
||||
byte[] typevals = new byte[1];
|
||||
int len = in.readArrayB(member, typevals, componentDecoder);
|
||||
int contentLength = -1;
|
||||
if (len == Reader.SIGN_NULL) {
|
||||
return null;
|
||||
}
|
||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||
contentLength = in.readMemberContentLength(member, componentDecoder);
|
||||
len = Reader.SIGN_NOLENGTH;
|
||||
}
|
||||
if (this.componentDecoder == null) {
|
||||
if (!this.inited) {
|
||||
lock.lock();
|
||||
try {
|
||||
condition.await();
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
|
||||
final List<T> result = new ArrayList();
|
||||
boolean first = true;
|
||||
if (len == Reader.SIGN_NOLENGTH) {
|
||||
int startPosition = in.position();
|
||||
while (hasNext(in, member, startPosition, contentLength, first)) {
|
||||
Reader itemReader = getItemReader(in, member, first);
|
||||
if (itemReader == null) {
|
||||
break;
|
||||
}
|
||||
result.add(readMemberValue(itemReader, member, localdecoder, first));
|
||||
first = false;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < len; i++) {
|
||||
result.add(localdecoder.convertFrom(in));
|
||||
}
|
||||
}
|
||||
in.readArrayE();
|
||||
T[] rs = this.componentArrayFunction.apply(result.size());
|
||||
return result.toArray(rs);
|
||||
}
|
||||
public T[] convertFrom(Reader in, DeMember member) {
|
||||
byte[] typevals = new byte[1];
|
||||
int len = in.readArrayB(member, typevals, componentDecoder);
|
||||
int contentLength = -1;
|
||||
if (len == Reader.SIGN_NULL) {
|
||||
return null;
|
||||
}
|
||||
if (len == Reader.SIGN_NOLENBUTBYTES) {
|
||||
contentLength = in.readMemberContentLength(member, componentDecoder);
|
||||
len = Reader.SIGN_NOLENGTH;
|
||||
}
|
||||
if (this.componentDecoder == null) {
|
||||
if (!this.inited) {
|
||||
lock.lock();
|
||||
try {
|
||||
condition.await();
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
|
||||
final List<T> result = new ArrayList();
|
||||
boolean first = true;
|
||||
if (len == Reader.SIGN_NOLENGTH) {
|
||||
int startPosition = in.position();
|
||||
while (hasNext(in, member, startPosition, contentLength, first)) {
|
||||
Reader itemReader = getItemReader(in, member, first);
|
||||
if (itemReader == null) {
|
||||
break;
|
||||
}
|
||||
result.add(readMemberValue(itemReader, member, localdecoder, first));
|
||||
first = false;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < len; i++) {
|
||||
result.add(localdecoder.convertFrom(in));
|
||||
}
|
||||
}
|
||||
in.readArrayE();
|
||||
T[] rs = this.componentArrayFunction.apply(result.size());
|
||||
return result.toArray(rs);
|
||||
}
|
||||
|
||||
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
|
||||
return in.hasNext(startPosition, contentLength);
|
||||
}
|
||||
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
|
||||
return in.hasNext(startPosition, contentLength);
|
||||
}
|
||||
|
||||
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||
return decoder;
|
||||
}
|
||||
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
|
||||
return decoder;
|
||||
}
|
||||
|
||||
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
||||
return in;
|
||||
}
|
||||
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
|
||||
return in;
|
||||
}
|
||||
|
||||
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
|
||||
if (in == null) {
|
||||
return null;
|
||||
}
|
||||
return decoder.convertFrom(in);
|
||||
}
|
||||
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
|
||||
if (in == null) {
|
||||
return null;
|
||||
}
|
||||
return decoder.convertFrom(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:"
|
||||
+ this.componentDecoder + "}";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:"
|
||||
+ this.componentDecoder + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Type getComponentType() {
|
||||
return componentType;
|
||||
}
|
||||
public Type getComponentType() {
|
||||
return componentType;
|
||||
}
|
||||
|
||||
public Decodeable<Reader, T> getComponentDecoder() {
|
||||
return componentDecoder;
|
||||
}
|
||||
public Decodeable<Reader, T> getComponentDecoder() {
|
||||
return componentDecoder;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user