From 83091599c75e1b697e89ee84b9174bf7a420a1db Mon Sep 17 00:00:00 2001 From: yongbiaofeng Date: Sat, 30 Sep 2017 14:16:40 +0800 Subject: [PATCH 01/14] https://github.com/uavorg/uavstack/issues/34 Increased disk monitoring for Windows, supported disk IO for Windows (win7 through 10), disk IO for each service process. --- .../handlers/HBClientDefaultHandler.java | 30 +++--- .../agent/helpers/osproc/DiskIOCollector.java | 35 +++++++ .../helpers/osproc/ProcDiskIOCollector.java | 93 ++++++++++++++----- 3 files changed, 115 insertions(+), 43 deletions(-) diff --git a/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/hbagent/handlers/HBClientDefaultHandler.java b/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/hbagent/handlers/HBClientDefaultHandler.java index 6bcb4cf2..9e400063 100644 --- a/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/hbagent/handlers/HBClientDefaultHandler.java +++ b/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/hbagent/handlers/HBClientDefaultHandler.java @@ -291,28 +291,22 @@ private String getIODiskInfo() throws Exception { if (JVMToolHelper.isWindows()) { File[] roots = File.listRoots(); - StringBuilder sb = new StringBuilder("{"); - + Map> resultMap = new HashMap>(); for (int i = 0; i < roots.length; i++) { File file = roots[i]; - sb.append("\"" + file.getPath() + "\":{") - .append("\"free\":\"" + Math.round((double) (file.getFreeSpace() / 1024)) + "\",")// 空闲空间 - .append("\"total\":\"" + +Math.round((double) (file.getTotalSpace() / 1024)) + "\",")// 总空间 - .append("\"use\":\"" - + +Math.round((double) ((file.getTotalSpace() - file.getFreeSpace()) / 1024)) + "\",")// 已使用空间 - .append("\"useRate\":\"" - + ((file.getTotalSpace() == 0) ? "0" - : (file.getTotalSpace() - file.getFreeSpace()) * 100 / file.getTotalSpace()) - + "%\"")// 空间占用率 - .append("}"); - - if (i < roots.length - 1) { - sb.append(","); - } + Map temp = new HashMap(); + temp.put("free", String.valueOf(Math.round((double) (file.getFreeSpace() / 1024)))); + temp.put("total", String.valueOf(Math.round((double) (file.getTotalSpace() / 1024)))); + temp.put("use", + String.valueOf(Math.round((double) ((file.getTotalSpace() - file.getFreeSpace()) / 1024)))); + temp.put("useRate", ((file.getTotalSpace() == 0) ? 0 + : (file.getTotalSpace() - file.getFreeSpace()) * 100 / file.getTotalSpace()) + "%"); + resultMap.put(file.getPath().substring(0, file.getPath().length() - 1), temp); } - sb.append("}"); - return sb.toString(); + dioc.collectWin(resultMap); + + return JSON.toJSONString(resultMap); } else { Map> resultMap = new HashMap>(); diff --git a/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/osproc/DiskIOCollector.java b/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/osproc/DiskIOCollector.java index 63565350..2d78b871 100644 --- a/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/osproc/DiskIOCollector.java +++ b/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/osproc/DiskIOCollector.java @@ -26,6 +26,8 @@ import java.util.regex.Pattern; import com.creditease.agent.helpers.IOHelper; +import com.creditease.agent.helpers.RuntimeHelper; +import com.creditease.agent.helpers.StringHelper; public class DiskIOCollector { @@ -39,6 +41,39 @@ public class DiskIOCollector { private Map> lastDiskIoMap = new HashMap>(); private long time = 0; + public void collectWin(Map> resultMap) { + + try { + String output = RuntimeHelper.exec( + "wmic path Win32_PerfFormattedData_PerfDisk_LogicalDisk get DiskReadBytesPerSec,DiskWriteBytesPerSec,Name"); + + if (StringHelper.isEmpty(output)) { + return; + } + + String[] strs = output.split("\n"); + for (String str : strs) { + str = str.replaceAll("\\s{2,}", " "); + String[] args = str.split(" "); + if (1 == args.length) { + continue; + } + + if (!(args[2].equals("_Total")) && !(args[2].equals("Name"))) { + double rd_persec = Long.parseLong(args[0]) / 1024.0; + double wr_persec = Long.parseLong(args[1]) / 1024.0; + + DecimalFormat df = new DecimalFormat("#0.00"); + resultMap.get(args[2]).put("disk_read", df.format(rd_persec)); + resultMap.get(args[2]).put("disk_write", df.format(wr_persec)); + } + } + } + catch (Exception e) { + // ignore + } + } + public void collect(Map> resultMap) { Map> currentDiskIoMap = new HashMap>(); diff --git a/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/osproc/ProcDiskIOCollector.java b/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/osproc/ProcDiskIOCollector.java index b8e17723..d6802e82 100644 --- a/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/osproc/ProcDiskIOCollector.java +++ b/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/osproc/ProcDiskIOCollector.java @@ -26,6 +26,8 @@ import com.creditease.agent.helpers.IOHelper; import com.creditease.agent.helpers.JVMToolHelper; +import com.creditease.agent.helpers.RuntimeHelper; +import com.creditease.agent.helpers.StringHelper; public class ProcDiskIOCollector { @@ -37,45 +39,86 @@ public class ProcDiskIOCollector { public void collect(Map procs) { - if (JVMToolHelper.isWindows()) { - return; - } Map> currentPidsDiskIoMap = new HashMap>(); - for (String pid : procs.keySet()) { + if (JVMToolHelper.isWindows()) { + // for Windows try { - Map lastIoStat = lastPidsDiskIoMap.get(pid); - Map ioStat = new HashMap(); - String procpath = "/proc/" + pid + "/io"; - if (!IOHelper.exists(procpath)) { - continue; + String output = RuntimeHelper.exec("wmic process list IO"); + if (StringHelper.isEmpty(output)) { + return; } - String[] strs = IOHelper.readTxtFile(procpath, "UTF-8").split("\n"); + String[] strs = output.split("\n"); for (String str : strs) { - - if (str.startsWith("read_bytes")) { - ioStat.put("read_bytes", Long.parseLong(str.split(":")[1].replace(" ", ""))); - } - if (str.startsWith("write_bytes")) { - ioStat.put("write_bytes", Long.parseLong(str.split(":")[1].replace(" ", ""))); + str = str.replaceAll("\\s{2,}", " "); + String[] args = str.split(" "); + if (1 == args.length) { + continue; } + if (procs.containsKey(args[1])) { + Map lastIoStat = lastPidsDiskIoMap.get(args[1]); + Map ioStat = new HashMap(); + + ioStat.put(read_bytes, Long.parseLong(args[3])); + ioStat.put(write_bytes, Long.parseLong(args[5])); + + if (null != lastIoStat && time != 0) { + long timerange = System.currentTimeMillis() - time; + DecimalFormat df = new DecimalFormat("#0.00"); + + double rd_persec = (ioStat.get(read_bytes) - lastIoStat.get(read_bytes)) * 1.0 / timerange; + double wr_persec = (ioStat.get(write_bytes) - lastIoStat.get(write_bytes)) * 1.0 + / timerange; + procs.get(args[1]).addTag("disk_read", df.format(rd_persec)); + procs.get(args[1]).addTag("disk_write", df.format(wr_persec)); + } + currentPidsDiskIoMap.put(args[1], ioStat); + } } - if (null != lastIoStat && time != 0) { - long timerange = System.currentTimeMillis() - time; - DecimalFormat df = new DecimalFormat("#0.00"); - double rd_persec = (ioStat.get(read_bytes) - lastIoStat.get(read_bytes)) * 1.0 / timerange; - double wr_persec = (ioStat.get(write_bytes) - lastIoStat.get(write_bytes)) * 1.0 / timerange; - procs.get(pid).addTag("disk_read", df.format(rd_persec)); - procs.get(pid).addTag("disk_write", df.format(wr_persec)); - } - currentPidsDiskIoMap.put(pid, ioStat); } catch (Exception e) { // ignore } + } + else { + // for linux + for (String pid : procs.keySet()) { + try { + Map lastIoStat = lastPidsDiskIoMap.get(pid); + Map ioStat = new HashMap(); + String procpath = "/proc/" + pid + "/io"; + if (!IOHelper.exists(procpath)) { + continue; + } + + String[] strs = IOHelper.readTxtFile(procpath, "UTF-8").split("\n"); + for (String str : strs) { + + if (str.startsWith("read_bytes")) { + ioStat.put("read_bytes", Long.parseLong(str.split(":")[1].replace(" ", ""))); + } + if (str.startsWith("write_bytes")) { + ioStat.put("write_bytes", Long.parseLong(str.split(":")[1].replace(" ", ""))); + } + + } + if (null != lastIoStat && time != 0) { + long timerange = System.currentTimeMillis() - time; + DecimalFormat df = new DecimalFormat("#0.00"); + double rd_persec = (ioStat.get(read_bytes) - lastIoStat.get(read_bytes)) * 1.0 / timerange; + double wr_persec = (ioStat.get(write_bytes) - lastIoStat.get(write_bytes)) * 1.0 / timerange; + procs.get(pid).addTag("disk_read", df.format(rd_persec)); + procs.get(pid).addTag("disk_write", df.format(wr_persec)); + } + currentPidsDiskIoMap.put(pid, ioStat); + } + catch (Exception e) { + // ignore + } + } } lastPidsDiskIoMap = currentPidsDiskIoMap; time = System.currentTimeMillis(); From c89a80ce388fa24cdb9de03ff5da6f5b890652ee Mon Sep 17 00:00:00 2001 From: "zhenzhang18@creditease.cn" Date: Mon, 9 Oct 2017 16:23:03 +0800 Subject: [PATCH 02/14] 1. add new menu of AppOS/Process Metrics Window to App/Service Monitor panel. Then, the end user can watch its OS or Process Metrics by click the menu of App/Service Monitor panel. This is a new collection chain between App Perf Metrics and its Env Perf Metrics 2. FIX App Monitor Metrics Loss after opening an App Instance Metrics Window. The reason is that the wrong customized App Instance Metrics Watch is actived, then the query only return the customized App Instance's Metrics data. --- .../main/webapp/apphub/js/common/helper.js | 13 +- .../appmonitor/css/uav.appmonitor.css | 10 +- .../uavapp_godeye/appmonitor/js/uav.apm.js | 218 ++++++++++++++++-- .../appmonitor/js/uav.appmonitor.js | 142 ++++++++++-- .../uavnetwork/js/uav.network.js | 149 +++++++++++- 5 files changed, 488 insertions(+), 44 deletions(-) diff --git a/com.creditease.uav.console/src/main/webapp/apphub/js/common/helper.js b/com.creditease.uav.console/src/main/webapp/apphub/js/common/helper.js index 9efb34b7..2865d8b3 100644 --- a/com.creditease.uav.console/src/main/webapp/apphub/js/common/helper.js +++ b/com.creditease.uav.console/src/main/webapp/apphub/js/common/helper.js @@ -449,7 +449,18 @@ var HtmlHelper={ var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); var r = window.location.search.substr(1).match(reg); if (r != null) return unescape(r[2]); return undefined; - } + }, + //get all url params + getQParams:function() { + var vars = [], hash; + var hashes = window.location.href.slice(window.location.href.indexOf('?')+1).split('&'); + for(var i = 0; i < hashes.length; i++) { + hash = hashes[i].split('='); + vars.push(hash[0]); + vars[hash[0]] = hash[1]; + } + return vars; + } }; /** * 日志输出 diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/css/uav.appmonitor.css b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/css/uav.appmonitor.css index 2fbbd469..5d91a127 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/css/uav.appmonitor.css +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/css/uav.appmonitor.css @@ -591,9 +591,17 @@ select{ } /*APM相关CSS*/ +.AppIVCWnd_AppMode { + height: 80px; + text-align: left; + padding-top: 5px; + padding-left: 5px; + color: #000; +} + .AppIVCWnd_GlobalMode{ font-size: 14px; - height: 80px; + height: 105px; text-align: left; padding-top: 0px; padding-left: 10px; diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.apm.js b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.apm.js index da404138..c84733be 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.apm.js +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.apm.js @@ -303,25 +303,25 @@ function APMTool(app) { case 11: return ""+value+""; case 1: - return "
"+TimeHelper.getTime(value,"FMSN")+"
"; + return "
"+TimeHelper.getTime(value,"FMSN")+"
"; case 2: - return "
"+value+"
"; + return "
"+value+"
"; case 3: - return "
"+value+"
"; + return "
"+value+"
"; case 4: - return "
"+value+"
"; + return "
"+value+"
"; case 5: - return "
"+value+"
"; + return "
"+value+"
"; case 6: - return "
"+value+"
"; + return "
"+value+"
"; case 7: - return "
"+value+"
"; + return "
"+value+"
"; case 8: var color=""; if (value.indexOf(_this.appInfo["appid"])>-1) { color="font-weight:bold;color:#36648B;"; } - return "
"+value+"
"; + return "
"+value+"
"; case 9: return _this.UI_list_state(value,true); case 10: @@ -465,6 +465,8 @@ function APMTool(app) { ""+this.appInfo["appurl"]+"" + "
" + ""; + + html+="
"; } //全局模式 else { @@ -472,13 +474,27 @@ function APMTool(app) { html+= "
应用实例
"; } - html+="
" + - " "+ + html+="
时间
" + + "" + + "" + + "" + + + "" + + + "
"; + +// + "
搜索 " + + html+=" "+ " " + " " + - " " + - - "
"; + " " ; + html+="
"; return html; @@ -522,8 +538,43 @@ function APMTool(app) { this.mainList.cellClickUser = function(id,pNode) { app.controller.showWindow({traceid:id},"AppIVCTraceWnd","buildAppIVCTraceWnd","runAppIVCTraceWnd"); }; + + //init datetime picker + $('.form_datetime').datetimepicker({ + language : 'zh-CN', + autoclose : true, + minuteStep : 1, + minView: 1, + format:"yyyy-mm-dd hh", + todayBtn : true + }); + + //init timetrange selector + this.timeRangeSelector=new AppHubSelector({ + id:"AppIVCWnd_TimeRangeSelector", + cid:"AppIVCWnd_TimeRangeSelectorCtn", + title:"时间单位", + style:"font-size:12px;width:50px", + events:{ + onchange:"appAPM.onChangeTimeRangeSelector()" + } + }); + this.timeRangeSelector.init(); + this.timeRangeSelector.load([{title:"日期",value:"D"},{title:"小时",value:"H",select:true},{title:"分钟",value:"M"}]); + + //init time sort selector + this.timeSortSelector=new AppHubSelector({ + id:"AppIVCWnd_TimeSortSelector", + cid:"AppIVCWnd_TimeRangeSelectorCtn", + title:"时间排序方式", + style:"font-size:12px;width:50px" + }); + this.timeSortSelector.init(); + this.timeSortSelector.load([{title:"降序",value:"DESC", select:true},{title:"升序",value:"ASC"}]); }; + + /** * 调用链Trace窗口UI */ @@ -554,7 +605,7 @@ function APMTool(app) { /** * 跳转到重调用链明细页 */ - jumpAppIVCDataWnd = function(sObj){ + this.jumpAppIVCDataWnd = function(sObj){ var pNode = sObj.parentNode.parentNode; var spanid = pNode.getElementsByTagName("td")[0].id; var stime = pNode.getElementsByTagName("td")[1].id; @@ -569,7 +620,8 @@ function APMTool(app) { var parentid = $(pNode).attr("data-tt-parent-id"); app.controller.showWindow({traceid:traceid,stime:stime,url:url,epinfo:epinfo,clazz:clazz,method:method,ipport:ipport,appid:appid,state:state,spanid:spanid,parentid:parentid},"AppIVCDataWnd","buildAppIVCDataWnd","runAppIVCDataWnd"); - } + }; + /** * 重调用链窗口UI */ @@ -584,7 +636,7 @@ function APMTool(app) { "
"; var sb=new StringBuffer(); - sb.append("
" + + sb.append("
" + "
" + " 时间"+ TimeHelper.getTime(Number(sObj["stime"]),"FMS") +""+ "
" + @@ -609,8 +661,8 @@ function APMTool(app) { "
" + " 状态"+ _this.UI_list_state(sObj["state"],false) +""+ "
" + - " 元数据" + - " "); + html+="
"+sb.toString()+"
"; return html; }; @@ -716,16 +771,16 @@ function APMTool(app) { } if(isEmpty){ - var errMsg = "数据处理中,请刷新重试"; + var errMsg = "无数据,请刷新重试"; var epinfo = sObj["epinfo"].split(",")[0]; //当前支持的类型 var epinfos = ["http.service","apache.http.Client","apache.http.AsyncClient","mq.service","rabbitmq.client","jdbc.client","method","dubbo.provider","dubbo.consumer"]; if($.inArray(epinfo, epinfos)==-1){ - errMsg = "不支持的数据类型,努力更新中..."; + errMsg = "不支持的数据类型"; } sb.append(""+errMsg+""); } - HtmlHelper.id("AppIVCDataWnd_TContainer_ContentDiv").innerHTML+=sb.toString(); + HtmlHelper.id("AppIVCDataWnd_TContainer_ContentDiv").innerHTML=sb.toString(); } @@ -941,6 +996,36 @@ function APMTool(app) { } switch(intent) { + /** + * 完整查询 + */ + case "qsearch": + dataList=this.mainList; + + var timeRange=_this.getCurTimeRange(); + + if (timeRange==undefined) { + var tmp=new Date().getTime(); + timeRange={etime:tmp,stime:tmp-60000}; + } + + var etime=timeRange["etime"]; + var stime=timeRange["stime"]; + data["request"]["appuuid"]=appuuid; + data["request"]["stime"]=stime+""; + data["request"]["etime"]=etime+""; + data["request"]["eptype"]="E,S"; + data["request"]["from"]=0+""; + data["request"]["size"]=500+""; + + var timeSort=this.timeSortSelector.value(); + if (timeSort=="DESC") { + data["request"]["sort"]="stime=DESC"; + } + else { + data["request"]["sort"]="stime=ASC"; + } + break; case "lst1min": dataList=this.mainList; @@ -1092,6 +1177,97 @@ function APMTool(app) { this.runIVCCfgWnd=function(sObj) { }; + + //TODO -----------------------------------------------调用链时间控制------------------------------------------ + /** + * 改变时间区段的单位 + */ + this.onChangeTimeRangeSelector=function() { + + var val=this.timeRangeSelector.value(); + + if (val=="D") { + $('.form_datetime').datetimepicker("remove"); + HtmlHelper.id("AppIVCWnd_TimeRange").value=""; + $('.form_datetime').datetimepicker({ + language : 'zh-CN', + autoclose : true, + minuteStep : 1, + minView: 2, + format:"yyyy-mm-dd", + todayBtn : true + }); + } + else if (val=="H") { + $('.form_datetime').datetimepicker("remove"); + HtmlHelper.id("AppIVCWnd_TimeRange").value=""; + $('.form_datetime').datetimepicker({ + language : 'zh-CN', + autoclose : true, + minuteStep : 1, + minView: 1, + format:"yyyy-mm-dd hh", + todayBtn : true + }); + } + else if (val=="M") { + $('.form_datetime').datetimepicker("remove"); + HtmlHelper.id("AppIVCWnd_TimeRange").value=""; + $('.form_datetime').datetimepicker({ + language : 'zh-CN', + autoclose : true, + minuteStep : 1, + minView: 0, + format:"yyyy-mm-dd hh:ii", + todayBtn : true + }); + } + + }; + + /** + * 清除时间选择 + */ + this.cleanTimeRange=function() { + HtmlHelper.id("AppIVCWnd_TimeRange").value=""; + }; + + /** + * 获取当前的时间区段 + */ + this.getCurTimeRange=function() { + + var timeRange=HtmlHelper.id("AppIVCWnd_TimeRange").value; + var timeUnit=this.timeRangeSelector.value(); + + //全部时间 + if (timeRange=="") { + return undefined; + } + + var date; + var plus; + switch(timeUnit) { + case "D": + date=TimeHelper.toDate(timeRange+" 00:00:00"); + plus=24*3600*1000; + break; + case "H": + date=TimeHelper.toDate(timeRange+":00:00"); + plus=3600*1000; + break; + case "M": + date=TimeHelper.toDate(timeRange+":00"); + plus=60*1000; + break; + } + + var startTime=date.getTime(); + var endTime=startTime+plus; + var reqDate=TimeHelper.getTime(startTime,"FD"); + + return {stime:startTime,etime:endTime,indexdate:reqDate}; + }; } diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.appmonitor.js b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.appmonitor.js index 28d8cf1e..4dff102d 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.appmonitor.js +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.appmonitor.js @@ -1019,6 +1019,39 @@ var monitorCfg={ } }; +/** + * TODO: open link + */ +var openLink={ + + /** + * 延迟打开window + * @param ip + * @param winId + * @param func + * @param callback + * @param tag + */ + showWindowDelay:function(ip,winId,func,callback,tag) { + var info={ip:ip,winId:winId,func:func,callback:callback,tag:tag}; + window["openlink_"+tag]=info; + }, + + /** + * 触发点执行打开窗口 + * @param tag + */ + runWindowDelay:function(tag) { + if (window["openlink_"+tag]==undefined) { + return; + } + + var info=window["openlink_"+tag]; + app.controller.showWindow(info["ip"],info["winId"],info["func"],info["callback"]); + window["openlink_"+tag]=undefined; + } +}; + /** * TODO:应用画像与监控 */ @@ -1255,12 +1288,25 @@ var mvcObj={ //not start sync return false; } + // for 应用实例监控 + else if (view=="appinst") { + window.winmgr.show("AppInstWnd"); + var param=HtmlHelper.getQParams()["param"]; + param=decodeURI(param); + var params=param.split(","); + var id=params[0]; + var instid=params[1]; + var isJse=params[2]; + var appInfo={id:id,instid:instid,isJse:isJse}; + openLink.showWindowDelay(appInfo,"AppInstChartWnd","buildAppInstChart","runAppInstChart","monitorapp"); + } //for 应用监控 else { - window.winmgr.show("AppList"); - window.tablistmgr.build(appTabListConfig); + window.winmgr.show("AppList"); } + //init app tab list + window.tablistmgr.build(appTabListConfig); //init monitorcfg dialog this.controller.initMonitorCfgDialog(); }, @@ -1735,6 +1781,9 @@ var mvcObj={ //启动图谱的Edge的刷新 appStream.startAppEdgeMoUpdate(); + + //完成openlink事件 + openLink.runWindowDelay("monitorapp"); }, //--------------元数据定义----------------- //primary key @@ -1924,6 +1973,13 @@ var mvcObj={ */ controller:{ //----------------------COMMON-------------------------- + /** + * TODO: delay open + */ + showWindowDelay:function(iObj,winId,func,callback,tag) { + var info={iObj:iObj,winId:winId,func:func,callback:callback,tag:tag}; + window["openlink_"+tag]=info; + }, /** * TODO: controller COMMON */ @@ -2307,7 +2363,7 @@ var mvcObj={ /** * check if one app instance window is open and try to query history data */ - if (monitorCfg.app["id"]!=undefined) { + if (monitorCfg.app["id"]!=undefined&&monitorCfg["app"].isusecustomized==true) { pdata=[pdata[monitorCfg.app["id"]]]; } } @@ -2912,6 +2968,10 @@ var mvcObj={ */ quitMonitorChartData:function(dType) { + if (dType=="app") { + monitorCfg.app["id"]=undefined; + } + if (monitorCfg[dType].isusecustomized==false) { return; } @@ -2923,16 +2983,12 @@ var mvcObj={ if (dType=="app") { monitorCfg.startTime=undefined; + //reset isautorefresh + monitorCfg.isautorefresh=true; + + app.refresh("app.monitor"); } - switch(dType) { - case "app": - //reset isautorefresh - monitorCfg.isautorefresh=true; - monitorCfg.app["id"]=undefined; - app.refresh("app.monitor"); - break; - } }, /** * init LogCfgDialog @@ -3654,6 +3710,13 @@ var mvcObj={ var jsonObj=mdata[obj.id]; + if(jsonObj==undefined) { + setTimeout(function() { + openLink.runWindowDelay("monitorapp"); + },1000); + return; + } + var isJse=this.isJSE(jsonObj.appurl); if (isJse==true) { @@ -3665,6 +3728,10 @@ var mvcObj={ var appInstMO=app.mdata("monitor.app")[appInstMOId]; + if (appInstMO==undefined) { + console.log(appInstMOId+" monitor data is null~~~"); + } + var sObjStr=StringHelper.obj2str(obj); var backWndId=""; @@ -3734,6 +3801,19 @@ var mvcObj={ html+="
"+this.buildAppInstServerWndContent(jsonObj)+ "
"; + /** + * 主机(应用容器)查看窗口 + */ + html+="
"+this.buildAppMachineWndContent(jsonObj,appInstMOId,isJse)+ + "
"; + + /** + * 应用进程查看窗口 + */ + html+="
"+this.buildAppProcessWndContent(jsonObj,appInstMOId,isJse)+ + "
"; + + /** * AppInst Chart 日志组件按钮列表,可以打开日志组件查看窗口 */ @@ -3756,6 +3836,42 @@ var mvcObj={ html+="
"; return html; }, + /** + * buildAppMachineWndContent + */ + buildAppMachineWndContent:function(jsonObj,appInstMOId,isJse) { + var ip=jsonObj["ip"]; + var sb=new StringBuffer(); + var param=encodeURI(jsonObj["id"]+","+appInstMOId+","+isJse); + sb.append("应用容器 "+ip+""); + + return sb.toString(); + }, + /** + * buildAppProcessWndContent + */ + buildAppProcessWndContent:function(jsonObj,appInstMOId,isJse) { + var ip=jsonObj["ip"]; + var proc; + //jse can get the pid directly + if (isJse) { + var jseInfo=jsonObj["appurl"].split("-"); + proc="pid="+jseInfo[jseInfo.length-1]; + } + //jee can get the port + else { + var ipport=app.controller.getAppInstIPPort( jsonObj["appurl"]); + proc="port="+ipport.split(":")[2]; + } + + var param=encodeURI(jsonObj["id"]+","+appInstMOId+","+isJse); + + var sb=new StringBuffer(); + + sb.append("应用进程"); + + return sb.toString(); + }, /** * App Customized Metrics */ @@ -5324,7 +5440,7 @@ var mvcObj={ var ret = JSON.parse(data); if(ret.code){ // dba server error... if(ret.code == 20002){ - alert("该数据源性能数据不存在。\n注:数据源性能数据由系统部DBA提供,如有疑问请联系dba.list"); + alert("该数据源性能数据不存在。\n注:数据源性能数据由系统部DBA提供,如有疑问请联系dba.list@creditease.cn"); } app.controller.accessDbInstData(reqs,index+1,models); return; @@ -5379,7 +5495,7 @@ var mvcObj={ if(ret.code){ // dba server error... app.controller.openClose(id); console.log(data); - alert("访问数据源性能数据服务失败!\n注:数据源性能数据由系统部DBA提供,如有疑问请联系dba.list"); + alert("访问数据源性能数据服务失败!\n注:数据源性能数据由系统部DBA提供,如有疑问请联系dba.list@creditease.cn"); return; } var html = '
'; diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js index 0bec415d..b6dae8f8 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js @@ -376,6 +376,9 @@ var dataCacheCfg={ var dataCache={}; +/** + * TODO: UserFilterCache + */ var UserFilterCache={ all:false, nomapping:false, @@ -775,6 +778,80 @@ var preUpgradeDialog = { } } +/** + * TODO: open link + */ +var openLink={ + + /** + * 延迟打开window + * @param ip + * @param winId + * @param func + * @param callback + * @param tag + */ + showWindowDelay:function(ip,winId,func,callback,tag,proc) { + + var info={ip:ip,winId:winId,func:func,callback:callback,tag:tag}; + + if (proc!=undefined) { + if (proc["pid"]!=undefined) { + info["pid"]=proc["pid"]; + } + else { + info["port"]=proc["port"]; + } + } + + window["openlink_"+tag]=info; + }, + + /** + * 触发点执行打开窗口 + * @param tag + */ + runWindowDelay:function(tag) { + if (window["openlink_"+tag]==undefined) { + return; + } + + var info=window["openlink_"+tag]; + window["openlink_"+tag]=undefined; + if (tag=="procinfo") { + + var pid=info["pid"]; + //need find pid by port + if (pid==undefined) { + var macInfo=app.mdata("macinfo")[info["ip"]]; + + var procs=eval("("+macInfo["node.procs"]+")"); + + for(var key in procs) { + + var proc=procs[key]; + + var ports=proc["ports"]; + + for(var i=0;i\n" + "
\n" + " "+resultObj["host"]+"
\n" + " "+resultObj["ip"]+"\n" + - "
\n" + + "
\n" + "
\n" + "
" + "
" + @@ -2099,6 +2213,12 @@ var mvcObj={ buildProcessChartContent : function(resultObj,pid){ var procs=eval("("+resultObj["node.procs"]+")"); var proc=procs[pid]; + + if (proc==undefined) { + alert("进程号["+pid+"]的进程在["+resultObj["ip"]+"]不存在!") + return; + } + var ports=proc["ports"]; var connSeries=[ { @@ -2152,12 +2272,25 @@ var mvcObj={ window["appcharts"].bulid(processConnChartCfg); window["appcharts"].bulid(processFluxChartCfg); - + + var backScript="javascript:app.controller.closeWindow('ProcessChartWnd','destroyProcessChart')"; + + //if open link + var view=HtmlHelper.getQParam("view"); + + if (view!=undefined) { + var from=HtmlHelper.getQParam("from"); + var fview=HtmlHelper.getQParam("fview"); + var fparam=HtmlHelper.getQParams()["fparam"]; + var burl=from+"?view="+fview+"¶m="+fparam; + backScript="window.parent.jumpUrl('"+burl+"','应用监控')"; + } + return "
\n" + "
\n" + " "+resultObj["ip"]+"
\n" + " "+"["+pid+"] "+app.controller.getJavaProName(proc)+"\n" + - "
\n" + + "
\n" + "
\n" + "
" + "
" + From 6f10e2efbc10b6fd7a3c237c884a5bee8497642a Mon Sep 17 00:00:00 2001 From: "zhenzhang18@creditease.cn" Date: Mon, 9 Oct 2017 16:23:03 +0800 Subject: [PATCH 03/14] UAV.Monitor add struts2 support --- .../main/webapp/apphub/js/common/helper.js | 13 +- .../appmonitor/css/uav.appmonitor.css | 10 +- .../uavapp_godeye/appmonitor/js/uav.apm.js | 218 +- .../appmonitor/js/uav.appmonitor.js | 147 +- .../uavnetwork/js/uav.network.js | 149 +- .../handlers/ProfileDataMessageHandler.java | 1954 +++++++++-------- .../handlers/ComponentProfileHandler.java | 593 ++++- 7 files changed, 2133 insertions(+), 951 deletions(-) diff --git a/com.creditease.uav.console/src/main/webapp/apphub/js/common/helper.js b/com.creditease.uav.console/src/main/webapp/apphub/js/common/helper.js index 9efb34b7..2865d8b3 100644 --- a/com.creditease.uav.console/src/main/webapp/apphub/js/common/helper.js +++ b/com.creditease.uav.console/src/main/webapp/apphub/js/common/helper.js @@ -449,7 +449,18 @@ var HtmlHelper={ var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); var r = window.location.search.substr(1).match(reg); if (r != null) return unescape(r[2]); return undefined; - } + }, + //get all url params + getQParams:function() { + var vars = [], hash; + var hashes = window.location.href.slice(window.location.href.indexOf('?')+1).split('&'); + for(var i = 0; i < hashes.length; i++) { + hash = hashes[i].split('='); + vars.push(hash[0]); + vars[hash[0]] = hash[1]; + } + return vars; + } }; /** * 日志输出 diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/css/uav.appmonitor.css b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/css/uav.appmonitor.css index 2fbbd469..5d91a127 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/css/uav.appmonitor.css +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/css/uav.appmonitor.css @@ -591,9 +591,17 @@ select{ } /*APM相关CSS*/ +.AppIVCWnd_AppMode { + height: 80px; + text-align: left; + padding-top: 5px; + padding-left: 5px; + color: #000; +} + .AppIVCWnd_GlobalMode{ font-size: 14px; - height: 80px; + height: 105px; text-align: left; padding-top: 0px; padding-left: 10px; diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.apm.js b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.apm.js index da404138..c84733be 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.apm.js +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.apm.js @@ -303,25 +303,25 @@ function APMTool(app) { case 11: return ""+value+""; case 1: - return "
"+TimeHelper.getTime(value,"FMSN")+"
"; + return "
"+TimeHelper.getTime(value,"FMSN")+"
"; case 2: - return "
"+value+"
"; + return "
"+value+"
"; case 3: - return "
"+value+"
"; + return "
"+value+"
"; case 4: - return "
"+value+"
"; + return "
"+value+"
"; case 5: - return "
"+value+"
"; + return "
"+value+"
"; case 6: - return "
"+value+"
"; + return "
"+value+"
"; case 7: - return "
"+value+"
"; + return "
"+value+"
"; case 8: var color=""; if (value.indexOf(_this.appInfo["appid"])>-1) { color="font-weight:bold;color:#36648B;"; } - return "
"+value+"
"; + return "
"+value+"
"; case 9: return _this.UI_list_state(value,true); case 10: @@ -465,6 +465,8 @@ function APMTool(app) { ""+this.appInfo["appurl"]+"" + "
" + "
"; + + html+="
"; } //全局模式 else { @@ -472,13 +474,27 @@ function APMTool(app) { html+= "
应用实例
"; } - html+="
" + - " "+ + html+="
时间
" + + "" + + "" + + "" + + + "" + + + "
"; + +// + "
搜索 " + + html+=" "+ " " + " " + - " " + - - "
"; + " " ; + html+="
"; return html; @@ -522,8 +538,43 @@ function APMTool(app) { this.mainList.cellClickUser = function(id,pNode) { app.controller.showWindow({traceid:id},"AppIVCTraceWnd","buildAppIVCTraceWnd","runAppIVCTraceWnd"); }; + + //init datetime picker + $('.form_datetime').datetimepicker({ + language : 'zh-CN', + autoclose : true, + minuteStep : 1, + minView: 1, + format:"yyyy-mm-dd hh", + todayBtn : true + }); + + //init timetrange selector + this.timeRangeSelector=new AppHubSelector({ + id:"AppIVCWnd_TimeRangeSelector", + cid:"AppIVCWnd_TimeRangeSelectorCtn", + title:"时间单位", + style:"font-size:12px;width:50px", + events:{ + onchange:"appAPM.onChangeTimeRangeSelector()" + } + }); + this.timeRangeSelector.init(); + this.timeRangeSelector.load([{title:"日期",value:"D"},{title:"小时",value:"H",select:true},{title:"分钟",value:"M"}]); + + //init time sort selector + this.timeSortSelector=new AppHubSelector({ + id:"AppIVCWnd_TimeSortSelector", + cid:"AppIVCWnd_TimeRangeSelectorCtn", + title:"时间排序方式", + style:"font-size:12px;width:50px" + }); + this.timeSortSelector.init(); + this.timeSortSelector.load([{title:"降序",value:"DESC", select:true},{title:"升序",value:"ASC"}]); }; + + /** * 调用链Trace窗口UI */ @@ -554,7 +605,7 @@ function APMTool(app) { /** * 跳转到重调用链明细页 */ - jumpAppIVCDataWnd = function(sObj){ + this.jumpAppIVCDataWnd = function(sObj){ var pNode = sObj.parentNode.parentNode; var spanid = pNode.getElementsByTagName("td")[0].id; var stime = pNode.getElementsByTagName("td")[1].id; @@ -569,7 +620,8 @@ function APMTool(app) { var parentid = $(pNode).attr("data-tt-parent-id"); app.controller.showWindow({traceid:traceid,stime:stime,url:url,epinfo:epinfo,clazz:clazz,method:method,ipport:ipport,appid:appid,state:state,spanid:spanid,parentid:parentid},"AppIVCDataWnd","buildAppIVCDataWnd","runAppIVCDataWnd"); - } + }; + /** * 重调用链窗口UI */ @@ -584,7 +636,7 @@ function APMTool(app) { "
"; var sb=new StringBuffer(); - sb.append("
" + + sb.append("
" + "
" + " 时间"+ TimeHelper.getTime(Number(sObj["stime"]),"FMS") +""+ "
" + @@ -609,8 +661,8 @@ function APMTool(app) { "
" + " 状态"+ _this.UI_list_state(sObj["state"],false) +""+ "
" + - " 元数据" + - " "); + html+="
"+sb.toString()+"
"; return html; }; @@ -716,16 +771,16 @@ function APMTool(app) { } if(isEmpty){ - var errMsg = "数据处理中,请刷新重试"; + var errMsg = "无数据,请刷新重试"; var epinfo = sObj["epinfo"].split(",")[0]; //当前支持的类型 var epinfos = ["http.service","apache.http.Client","apache.http.AsyncClient","mq.service","rabbitmq.client","jdbc.client","method","dubbo.provider","dubbo.consumer"]; if($.inArray(epinfo, epinfos)==-1){ - errMsg = "不支持的数据类型,努力更新中..."; + errMsg = "不支持的数据类型"; } sb.append(""+errMsg+""); } - HtmlHelper.id("AppIVCDataWnd_TContainer_ContentDiv").innerHTML+=sb.toString(); + HtmlHelper.id("AppIVCDataWnd_TContainer_ContentDiv").innerHTML=sb.toString(); } @@ -941,6 +996,36 @@ function APMTool(app) { } switch(intent) { + /** + * 完整查询 + */ + case "qsearch": + dataList=this.mainList; + + var timeRange=_this.getCurTimeRange(); + + if (timeRange==undefined) { + var tmp=new Date().getTime(); + timeRange={etime:tmp,stime:tmp-60000}; + } + + var etime=timeRange["etime"]; + var stime=timeRange["stime"]; + data["request"]["appuuid"]=appuuid; + data["request"]["stime"]=stime+""; + data["request"]["etime"]=etime+""; + data["request"]["eptype"]="E,S"; + data["request"]["from"]=0+""; + data["request"]["size"]=500+""; + + var timeSort=this.timeSortSelector.value(); + if (timeSort=="DESC") { + data["request"]["sort"]="stime=DESC"; + } + else { + data["request"]["sort"]="stime=ASC"; + } + break; case "lst1min": dataList=this.mainList; @@ -1092,6 +1177,97 @@ function APMTool(app) { this.runIVCCfgWnd=function(sObj) { }; + + //TODO -----------------------------------------------调用链时间控制------------------------------------------ + /** + * 改变时间区段的单位 + */ + this.onChangeTimeRangeSelector=function() { + + var val=this.timeRangeSelector.value(); + + if (val=="D") { + $('.form_datetime').datetimepicker("remove"); + HtmlHelper.id("AppIVCWnd_TimeRange").value=""; + $('.form_datetime').datetimepicker({ + language : 'zh-CN', + autoclose : true, + minuteStep : 1, + minView: 2, + format:"yyyy-mm-dd", + todayBtn : true + }); + } + else if (val=="H") { + $('.form_datetime').datetimepicker("remove"); + HtmlHelper.id("AppIVCWnd_TimeRange").value=""; + $('.form_datetime').datetimepicker({ + language : 'zh-CN', + autoclose : true, + minuteStep : 1, + minView: 1, + format:"yyyy-mm-dd hh", + todayBtn : true + }); + } + else if (val=="M") { + $('.form_datetime').datetimepicker("remove"); + HtmlHelper.id("AppIVCWnd_TimeRange").value=""; + $('.form_datetime').datetimepicker({ + language : 'zh-CN', + autoclose : true, + minuteStep : 1, + minView: 0, + format:"yyyy-mm-dd hh:ii", + todayBtn : true + }); + } + + }; + + /** + * 清除时间选择 + */ + this.cleanTimeRange=function() { + HtmlHelper.id("AppIVCWnd_TimeRange").value=""; + }; + + /** + * 获取当前的时间区段 + */ + this.getCurTimeRange=function() { + + var timeRange=HtmlHelper.id("AppIVCWnd_TimeRange").value; + var timeUnit=this.timeRangeSelector.value(); + + //全部时间 + if (timeRange=="") { + return undefined; + } + + var date; + var plus; + switch(timeUnit) { + case "D": + date=TimeHelper.toDate(timeRange+" 00:00:00"); + plus=24*3600*1000; + break; + case "H": + date=TimeHelper.toDate(timeRange+":00:00"); + plus=3600*1000; + break; + case "M": + date=TimeHelper.toDate(timeRange+":00"); + plus=60*1000; + break; + } + + var startTime=date.getTime(); + var endTime=startTime+plus; + var reqDate=TimeHelper.getTime(startTime,"FD"); + + return {stime:startTime,etime:endTime,indexdate:reqDate}; + }; } diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.appmonitor.js b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.appmonitor.js index 28d8cf1e..dba892d9 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.appmonitor.js +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.appmonitor.js @@ -1019,6 +1019,39 @@ var monitorCfg={ } }; +/** + * TODO: open link + */ +var openLink={ + + /** + * 延迟打开window + * @param ip + * @param winId + * @param func + * @param callback + * @param tag + */ + showWindowDelay:function(ip,winId,func,callback,tag) { + var info={ip:ip,winId:winId,func:func,callback:callback,tag:tag}; + window["openlink_"+tag]=info; + }, + + /** + * 触发点执行打开窗口 + * @param tag + */ + runWindowDelay:function(tag) { + if (window["openlink_"+tag]==undefined) { + return; + } + + var info=window["openlink_"+tag]; + app.controller.showWindow(info["ip"],info["winId"],info["func"],info["callback"]); + window["openlink_"+tag]=undefined; + } +}; + /** * TODO:应用画像与监控 */ @@ -1255,12 +1288,25 @@ var mvcObj={ //not start sync return false; } + // for 应用实例监控 + else if (view=="appinst") { + window.winmgr.show("AppInstWnd"); + var param=HtmlHelper.getQParams()["param"]; + param=decodeURI(param); + var params=param.split(","); + var id=params[0]; + var instid=params[1]; + var isJse=params[2]; + var appInfo={id:id,instid:instid,isJse:isJse}; + openLink.showWindowDelay(appInfo,"AppInstChartWnd","buildAppInstChart","runAppInstChart","monitorapp"); + } //for 应用监控 else { - window.winmgr.show("AppList"); - window.tablistmgr.build(appTabListConfig); + window.winmgr.show("AppList"); } + //init app tab list + window.tablistmgr.build(appTabListConfig); //init monitorcfg dialog this.controller.initMonitorCfgDialog(); }, @@ -1552,6 +1598,7 @@ var mvcObj={ "cpt.jaxrs":"cpt.jaxrs", "cpt.springmvc":"cpt.springmvc", "cpt.springmvcRest":"cpt.springmvcRest", + "cpt.struts2":"cpt.struts2", state:"state", "cpt.services":"cpt.services", "cpt.clients":"cpt.clients", @@ -1735,6 +1782,9 @@ var mvcObj={ //启动图谱的Edge的刷新 appStream.startAppEdgeMoUpdate(); + + //完成openlink事件 + openLink.runWindowDelay("monitorapp"); }, //--------------元数据定义----------------- //primary key @@ -1924,6 +1974,13 @@ var mvcObj={ */ controller:{ //----------------------COMMON-------------------------- + /** + * TODO: delay open + */ + showWindowDelay:function(iObj,winId,func,callback,tag) { + var info={iObj:iObj,winId:winId,func:func,callback:callback,tag:tag}; + window["openlink_"+tag]=info; + }, /** * TODO: controller COMMON */ @@ -2307,7 +2364,7 @@ var mvcObj={ /** * check if one app instance window is open and try to query history data */ - if (monitorCfg.app["id"]!=undefined) { + if (monitorCfg.app["id"]!=undefined&&monitorCfg["app"].isusecustomized==true) { pdata=[pdata[monitorCfg.app["id"]]]; } } @@ -2912,6 +2969,10 @@ var mvcObj={ */ quitMonitorChartData:function(dType) { + if (dType=="app") { + monitorCfg.app["id"]=undefined; + } + if (monitorCfg[dType].isusecustomized==false) { return; } @@ -2923,16 +2984,12 @@ var mvcObj={ if (dType=="app") { monitorCfg.startTime=undefined; + //reset isautorefresh + monitorCfg.isautorefresh=true; + + app.refresh("app.monitor"); } - switch(dType) { - case "app": - //reset isautorefresh - monitorCfg.isautorefresh=true; - monitorCfg.app["id"]=undefined; - app.refresh("app.monitor"); - break; - } }, /** * init LogCfgDialog @@ -3654,6 +3711,13 @@ var mvcObj={ var jsonObj=mdata[obj.id]; + if(jsonObj==undefined) { + setTimeout(function() { + openLink.runWindowDelay("monitorapp"); + },1000); + return; + } + var isJse=this.isJSE(jsonObj.appurl); if (isJse==true) { @@ -3665,6 +3729,10 @@ var mvcObj={ var appInstMO=app.mdata("monitor.app")[appInstMOId]; + if (appInstMO==undefined) { + console.log(appInstMOId+" monitor data is null~~~"); + } + var sObjStr=StringHelper.obj2str(obj); var backWndId=""; @@ -3734,6 +3802,19 @@ var mvcObj={ html+="
"+this.buildAppInstServerWndContent(jsonObj)+ "
"; + /** + * 主机(应用容器)查看窗口 + */ + html+="
"+this.buildAppMachineWndContent(jsonObj,appInstMOId,isJse)+ + "
"; + + /** + * 应用进程查看窗口 + */ + html+="
"+this.buildAppProcessWndContent(jsonObj,appInstMOId,isJse)+ + "
"; + + /** * AppInst Chart 日志组件按钮列表,可以打开日志组件查看窗口 */ @@ -3756,6 +3837,42 @@ var mvcObj={ html+="
"; return html; }, + /** + * buildAppMachineWndContent + */ + buildAppMachineWndContent:function(jsonObj,appInstMOId,isJse) { + var ip=jsonObj["ip"]; + var sb=new StringBuffer(); + var param=encodeURI(jsonObj["id"]+","+appInstMOId+","+isJse); + sb.append("应用容器 "+ip+""); + + return sb.toString(); + }, + /** + * buildAppProcessWndContent + */ + buildAppProcessWndContent:function(jsonObj,appInstMOId,isJse) { + var ip=jsonObj["ip"]; + var proc; + //jse can get the pid directly + if (isJse) { + var jseInfo=jsonObj["appurl"].split("-"); + proc="pid="+jseInfo[jseInfo.length-1]; + } + //jee can get the port + else { + var ipport=app.controller.getAppInstIPPort( jsonObj["appurl"]); + proc="port="+ipport.split(":")[2]; + } + + var param=encodeURI(jsonObj["id"]+","+appInstMOId+","+isJse); + + var sb=new StringBuffer(); + + sb.append("应用进程"); + + return sb.toString(); + }, /** * App Customized Metrics */ @@ -4505,6 +4622,10 @@ var mvcObj={ if (jsonObj["cpt.springmvcRest"]!=undefined&&jsonObj["cpt.springmvcRest"]!="{}") { sb.append("组件[SpringMVCRest]" ); } + + if (jsonObj["cpt.struts2"]!=undefined&&jsonObj["cpt.struts2"]!="{}") { + sb.append("组件[Struts2]" ); + } sb.append("
"); sb.append("
其他组件"); @@ -5324,7 +5445,7 @@ var mvcObj={ var ret = JSON.parse(data); if(ret.code){ // dba server error... if(ret.code == 20002){ - alert("该数据源性能数据不存在。\n注:数据源性能数据由系统部DBA提供,如有疑问请联系dba.list"); + alert("该数据源性能数据不存在。\n注:数据源性能数据由系统部DBA提供,如有疑问请联系dba.list@creditease.cn"); } app.controller.accessDbInstData(reqs,index+1,models); return; @@ -5379,7 +5500,7 @@ var mvcObj={ if(ret.code){ // dba server error... app.controller.openClose(id); console.log(data); - alert("访问数据源性能数据服务失败!\n注:数据源性能数据由系统部DBA提供,如有疑问请联系dba.list"); + alert("访问数据源性能数据服务失败!\n注:数据源性能数据由系统部DBA提供,如有疑问请联系dba.list@creditease.cn"); return; } var html = '
'; diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js index 0bec415d..b6dae8f8 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js @@ -376,6 +376,9 @@ var dataCacheCfg={ var dataCache={}; +/** + * TODO: UserFilterCache + */ var UserFilterCache={ all:false, nomapping:false, @@ -775,6 +778,80 @@ var preUpgradeDialog = { } } +/** + * TODO: open link + */ +var openLink={ + + /** + * 延迟打开window + * @param ip + * @param winId + * @param func + * @param callback + * @param tag + */ + showWindowDelay:function(ip,winId,func,callback,tag,proc) { + + var info={ip:ip,winId:winId,func:func,callback:callback,tag:tag}; + + if (proc!=undefined) { + if (proc["pid"]!=undefined) { + info["pid"]=proc["pid"]; + } + else { + info["port"]=proc["port"]; + } + } + + window["openlink_"+tag]=info; + }, + + /** + * 触发点执行打开窗口 + * @param tag + */ + runWindowDelay:function(tag) { + if (window["openlink_"+tag]==undefined) { + return; + } + + var info=window["openlink_"+tag]; + window["openlink_"+tag]=undefined; + if (tag=="procinfo") { + + var pid=info["pid"]; + //need find pid by port + if (pid==undefined) { + var macInfo=app.mdata("macinfo")[info["ip"]]; + + var procs=eval("("+macInfo["node.procs"]+")"); + + for(var key in procs) { + + var proc=procs[key]; + + var ports=proc["ports"]; + + for(var i=0;i\n" + "
\n" + " "+resultObj["host"]+"
\n" + " "+resultObj["ip"]+"\n" + - "
\n" + + "
\n" + "
\n" + "
" + "
" + @@ -2099,6 +2213,12 @@ var mvcObj={ buildProcessChartContent : function(resultObj,pid){ var procs=eval("("+resultObj["node.procs"]+")"); var proc=procs[pid]; + + if (proc==undefined) { + alert("进程号["+pid+"]的进程在["+resultObj["ip"]+"]不存在!") + return; + } + var ports=proc["ports"]; var connSeries=[ { @@ -2152,12 +2272,25 @@ var mvcObj={ window["appcharts"].bulid(processConnChartCfg); window["appcharts"].bulid(processFluxChartCfg); - + + var backScript="javascript:app.controller.closeWindow('ProcessChartWnd','destroyProcessChart')"; + + //if open link + var view=HtmlHelper.getQParam("view"); + + if (view!=undefined) { + var from=HtmlHelper.getQParam("from"); + var fview=HtmlHelper.getQParam("fview"); + var fparam=HtmlHelper.getQParams()["fparam"]; + var burl=from+"?view="+fview+"¶m="+fparam; + backScript="window.parent.jumpUrl('"+burl+"','应用监控')"; + } + return "
\n" + "
\n" + " "+resultObj["ip"]+"
\n" + " "+"["+pid+"] "+app.controller.getJavaProName(proc)+"\n" + - "
\n" + + "
\n" + "
\n" + "
" + "
" + diff --git a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/healthmanager/messaging/handlers/ProfileDataMessageHandler.java b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/healthmanager/messaging/handlers/ProfileDataMessageHandler.java index 55ad286d..c8201112 100644 --- a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/healthmanager/messaging/handlers/ProfileDataMessageHandler.java +++ b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/healthmanager/messaging/handlers/ProfileDataMessageHandler.java @@ -21,8 +21,10 @@ package com.creditease.uav.feature.healthmanager.messaging.handlers; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -41,1115 +43,1311 @@ public class ProfileDataMessageHandler extends AbstractMessageHandler { - @Override - public void handle(Message msg) { + @Override + public void handle(Message msg) { - // push the latest profile data to cache - List newMDFs = pushLatestProfileDataToCacheCenter(msg.getParam(getMsgTypeName())); + // push the latest profile data to cache + List newMDFs = pushLatestProfileDataToCacheCenter(msg.getParam(getMsgTypeName())); - if (newMDFs.size() > 0) { - // set the new MDFs into msg - msg.setParam(getMsgTypeName(), JSONHelper.toString(newMDFs)); - // store profile data - super.handle(msg); - } - } + if (newMDFs.size() > 0) { + // set the new MDFs into msg + msg.setParam(getMsgTypeName(), JSONHelper.toString(newMDFs)); + // store profile data + super.handle(msg); + } + } - @Override - public String getMsgTypeName() { + @Override + public String getMsgTypeName() { - return MonitorDataFrame.MessageType.Profile.toString(); - } + return MonitorDataFrame.MessageType.Profile.toString(); + } - @Override - protected void preInsert(DataStoreMsg dsMsg) { - - // set target collection - dsMsg.put(DataStoreProtocol.MONGO_COLLECTION_NAME, HealthManagerConstants.MONGO_COLLECTION_PROFILE); - } - - /** - * 推送最新的ProfileData到缓存中心 - * - * @param profileString - */ - @SuppressWarnings({ "rawtypes" }) - private List pushLatestProfileDataToCacheCenter(String profileString) { - - CacheManager cm = (CacheManager) ConfigurationManager.getInstance().getComponent("healthmanager", - "HMCacheManager"); - - cm.beginBatch(); - - List monitorDataFrames = JSONHelper.toObjectArray(profileString, String.class); - - List newMDFs = new ArrayList(); - - for (String mdfStr : monitorDataFrames) { - MonitorDataFrame mdf = new MonitorDataFrame(mdfStr); - - String tag = mdf.getTag(); - - /** - * note: only tag==P means this MDF is the new MDF, otherwise this MDF is just for heartbeat - */ - if (tag.equalsIgnoreCase("P")) { - newMDFs.add(mdfStr); - } - - /** - * Step 1: build all profile node info - */ - Map> frames = mdf.getDatas(); - for (String appid : frames.keySet()) { - - Map appProfile = new LinkedHashMap(); - - /** - * 1.1 basic info of the application - */ - Map values = mdf.getElemInstValues(appid, "cpt", "webapp"); - - String appurl = (String) values.get("appurl"); - - /** - * appgroup - */ - String appgroup = ""; - - if (values.containsKey("appgroup")) { - appgroup = (String) values.get("appgroup"); - } - - /** - * appdes from web.xml's description {org:"owner info"} - */ - String appdes = ""; - - if (values.containsKey("appdes")) { - appdes = (String) values.get("appdes"); - } - - /** - * appmetrics - */ - String appmetrics = ""; - - if (values.containsKey("appmetrics")) { - appmetrics = JSONHelper.toString(values.get("appmetrics")); - } - - /** - * appName - */ - String appName = (String) values.get("appname"); - - /** - * app root - */ - String appRoot = (String) values.get("webapproot"); - - /** - * MOF metadata - */ - String mofMeta = ""; - - if (values.containsKey("mofmeta")) { - mofMeta = JSONHelper.toString(values.get("mofmeta")); - } - - appProfile.put("appid", appid); - appProfile.put("ip", mdf.getIP()); - appProfile.put("svrid", mdf.getServerId()); - appProfile.put("host", mdf.getHost()); - appProfile.put("time", mdf.getTimeFlag()); - appProfile.put("appname", appName); - appProfile.put("appdes", appdes); - appProfile.put("appmetrics", appmetrics); - appProfile.put("appgroup", appgroup); - appProfile.put("webapproot", appRoot); - appProfile.put("appurl", appurl); - appProfile.put("mofmeta", mofMeta); - - /** - * step 1.2: cache the application clients profile data - */ - String clientsJSONstr = cacheAppClientProfileData(cm, mdf, appid, appurl, appgroup); - - /** - * Step 1.3 cache the application profile data - */ - cacheAppProfileData(cm, mdf, appProfile, clientsJSONstr, appid, appurl, appgroup); - - /** - * step 1.4: cache application ip_link & access data - */ - cacheAppIPLinkProfileData(cm, mdf, appid, appurl, appgroup); - } - } - - cm.submitBatch(); - - return newMDFs; - } - - /** - * cacheAppIPLinkProfileData - * - * @param cm - * @param mdf - * @param appid - * @param appurl - * @param appgroup - */ - @SuppressWarnings("rawtypes") - private void cacheAppIPLinkProfileData(CacheManager cm, MonitorDataFrame mdf, String appid, String appurl, - String appgroup) { - - List iplinks = mdf.getElemInstances(appid, "iplnk"); - - Map appIpLnkMap = new HashMap(); - - for (Map iplink : iplinks) { - String iplnk_id = (String) iplink.get("id"); - @SuppressWarnings("unchecked") - Map iplnk_values = (Map) iplink.get("values"); - appIpLnkMap.put(iplnk_id, JSONHelper.toString(iplnk_values)); - appIpLnkMap.put(iplnk_id + "-ts", String.valueOf(iplnk_values.get("ts"))); - } - - String iplnkfieldKey = "LNK@" + appgroup + "@" + appurl; - - cm.putHash(HealthManagerConstants.STORE_REGION_UAV, iplnkfieldKey, appIpLnkMap); - } - - /** - * cacheAppClientProfileData - * - * @param cm - * @param mdf - * @param appid - * @param appurl - * @param appgroup - */ - @SuppressWarnings("rawtypes") - private String cacheAppClientProfileData(CacheManager cm, MonitorDataFrame mdf, String appid, String appurl, - String appgroup) { - - List clients = mdf.getElemInstances(appid, "clients"); - - long checkTime = System.currentTimeMillis(); - - long expireTime = 60000; - - for (int i = 0; i < clients.size(); i++) { - - Map client = clients.get(i); - - @SuppressWarnings("unchecked") - Map cVals = (Map) client.get("values"); - - Long client_ts = (Long) cVals.get("ts"); - - if (client_ts == null) { - continue; - } - - long client_timeout = checkTime - client_ts; - - if (client_timeout < expireTime) { - cVals.put("state", "1"); - } - else if (client_timeout >= expireTime && client_timeout < expireTime * 2) { - cVals.put("state", "0"); - } - else if (client_timeout >= expireTime * 2) { - cVals.put("state", "-1"); - } - } - - String fieldKey = "C@" + appgroup + "@" + appurl; - - String clientsStr = JSONHelper.toString(clients); - - cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO_APPCLIENT, - fieldKey, clientsStr); - - return clientsStr; - } - - /** - * cache the application profile data - * - * @param cm - * @param mdf - * @param appid - */ - private void cacheAppProfileData(CacheManager cm, MonitorDataFrame mdf, Map pi, - String clientsJSONstr, String appid, String appurl, String appgroup) { + @Override + protected void preInsert(DataStoreMsg dsMsg) { + + // set target collection + dsMsg.put(DataStoreProtocol.MONGO_COLLECTION_NAME, HealthManagerConstants.MONGO_COLLECTION_PROFILE); + } + + /** + * 推送最新的ProfileData到缓存中心 + * + * @param profileString + */ + @SuppressWarnings({ "rawtypes" }) + private List pushLatestProfileDataToCacheCenter(String profileString) { + + CacheManager cm = (CacheManager) ConfigurationManager.getInstance().getComponent("healthmanager", + "HMCacheManager"); + + cm.beginBatch(); + + List monitorDataFrames = JSONHelper.toObjectArray(profileString, String.class); + + List newMDFs = new ArrayList(); + + for (String mdfStr : monitorDataFrames) { + MonitorDataFrame mdf = new MonitorDataFrame(mdfStr); + + String tag = mdf.getTag(); + + /** + * note: only tag==P means this MDF is the new MDF, otherwise this + * MDF is just for heartbeat + */ + if (tag.equalsIgnoreCase("P")) { + newMDFs.add(mdfStr); + } + + /** + * Step 1: build all profile node info + */ + Map> frames = mdf.getDatas(); + for (String appid : frames.keySet()) { + + Map appProfile = new LinkedHashMap(); + + /** + * 1.1 basic info of the application + */ + Map values = mdf.getElemInstValues(appid, "cpt", "webapp"); + + String appurl = (String) values.get("appurl"); + + /** + * appgroup + */ + String appgroup = ""; + + if (values.containsKey("appgroup")) { + appgroup = (String) values.get("appgroup"); + } + + /** + * appdes from web.xml's description {org:"owner info"} + */ + String appdes = ""; + + if (values.containsKey("appdes")) { + appdes = (String) values.get("appdes"); + } + + /** + * appmetrics + */ + String appmetrics = ""; + + if (values.containsKey("appmetrics")) { + appmetrics = JSONHelper.toString(values.get("appmetrics")); + } + + /** + * appName + */ + String appName = (String) values.get("appname"); + + /** + * app root + */ + String appRoot = (String) values.get("webapproot"); + + /** + * MOF metadata + */ + String mofMeta = ""; + + if (values.containsKey("mofmeta")) { + mofMeta = JSONHelper.toString(values.get("mofmeta")); + } + + appProfile.put("appid", appid); + appProfile.put("ip", mdf.getIP()); + appProfile.put("svrid", mdf.getServerId()); + appProfile.put("host", mdf.getHost()); + appProfile.put("time", mdf.getTimeFlag()); + appProfile.put("appname", appName); + appProfile.put("appdes", appdes); + appProfile.put("appmetrics", appmetrics); + appProfile.put("appgroup", appgroup); + appProfile.put("webapproot", appRoot); + appProfile.put("appurl", appurl); + appProfile.put("mofmeta", mofMeta); + + /** + * step 1.2: cache the application clients profile data + */ + String clientsJSONstr = cacheAppClientProfileData(cm, mdf, appid, appurl, appgroup); + + /** + * Step 1.3 cache the application profile data + */ + cacheAppProfileData(cm, mdf, appProfile, clientsJSONstr, appid, appurl, appgroup); + + /** + * step 1.4: cache application ip_link & access data + */ + cacheAppIPLinkProfileData(cm, mdf, appid, appurl, appgroup); + } + } + + cm.submitBatch(); + + return newMDFs; + } + + /** + * cacheAppIPLinkProfileData + * + * @param cm + * @param mdf + * @param appid + * @param appurl + * @param appgroup + */ + @SuppressWarnings("rawtypes") + private void cacheAppIPLinkProfileData(CacheManager cm, MonitorDataFrame mdf, String appid, String appurl, + String appgroup) { + + List iplinks = mdf.getElemInstances(appid, "iplnk"); + + Map appIpLnkMap = new HashMap(); + + for (Map iplink : iplinks) { + String iplnk_id = (String) iplink.get("id"); + @SuppressWarnings("unchecked") + Map iplnk_values = (Map) iplink.get("values"); + appIpLnkMap.put(iplnk_id, JSONHelper.toString(iplnk_values)); + appIpLnkMap.put(iplnk_id + "-ts", String.valueOf(iplnk_values.get("ts"))); + } + + String iplnkfieldKey = "LNK@" + appgroup + "@" + appurl; + + cm.putHash(HealthManagerConstants.STORE_REGION_UAV, iplnkfieldKey, appIpLnkMap); + } + + /** + * cacheAppClientProfileData + * + * @param cm + * @param mdf + * @param appid + * @param appurl + * @param appgroup + */ + @SuppressWarnings("rawtypes") + private String cacheAppClientProfileData(CacheManager cm, MonitorDataFrame mdf, String appid, String appurl, + String appgroup) { + + List clients = mdf.getElemInstances(appid, "clients"); + + long checkTime = System.currentTimeMillis(); + + long expireTime = 60000; + + for (int i = 0; i < clients.size(); i++) { + + Map client = clients.get(i); + + @SuppressWarnings("unchecked") + Map cVals = (Map) client.get("values"); + + Long client_ts = (Long) cVals.get("ts"); + + if (client_ts == null) { + continue; + } + + long client_timeout = checkTime - client_ts; + + if (client_timeout < expireTime) { + cVals.put("state", "1"); + } else if (client_timeout >= expireTime && client_timeout < expireTime * 2) { + cVals.put("state", "0"); + } else if (client_timeout >= expireTime * 2) { + cVals.put("state", "-1"); + } + } + + String fieldKey = "C@" + appgroup + "@" + appurl; + + String clientsStr = JSONHelper.toString(clients); + + cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO_APPCLIENT, + fieldKey, clientsStr); + + return clientsStr; + } + + /** + * cache the application profile data + * + * @param cm + * @param mdf + * @param appid + */ + private void cacheAppProfileData(CacheManager cm, MonitorDataFrame mdf, Map pi, + String clientsJSONstr, String appid, String appurl, String appgroup) { - /** - * client - */ - pi.put("cpt.clients", clientsJSONstr); + /** + * client + */ + pi.put("cpt.clients", clientsJSONstr); - /** - * lib - */ - Map libs = mdf.getElemInstValues(appid, "jars", "lib"); + /** + * lib + */ + Map libs = mdf.getElemInstValues(appid, "jars", "lib"); - pi.put("jars.lib", "@LAZY"); + pi.put("jars.lib", "@LAZY"); - /** - * NOTE:独立存储,延迟加载 - */ - String jarLib = JSONHelper.toString(libs); + /** + * NOTE:独立存储,延迟加载 + */ + String jarLib = JSONHelper.toString(libs); - /** - * logs - */ - Map logs = mdf.getElemInstValues(appid, "logs", "log4j"); + /** + * logs + */ + Map logs = mdf.getElemInstValues(appid, "logs", "log4j"); - pi.put("logs.log4j", JSONHelper.toString(logs)); + pi.put("logs.log4j", JSONHelper.toString(logs)); - /** - * components - */ - Map> compServices = new LinkedHashMap>(); + /** + * components + */ + Map> compServices = new LinkedHashMap>(); - // JEE Service Components - buildJEEServiceComponents(mdf, pi, appid, appurl, compServices); + // JEE Service Components + buildJEEServiceComponents(mdf, pi, appid, appurl, compServices); - // MSCP Service Components - buildMSCPServiceComponents(mdf, pi, appid, compServices); + // MSCP Service Components + buildMSCPServiceComponents(mdf, pi, appid, compServices); - // Dubbo Components - buildDubboServiceComponents(mdf, pi, appid, compServices); + // Dubbo Components + buildDubboServiceComponents(mdf, pi, appid, compServices); - pi.put("cpt.services", JSONHelper.toString(compServices)); + pi.put("cpt.services", JSONHelper.toString(compServices)); - pi.put("state", "1"); + pi.put("state", "1"); - /** - * use appgroup + appurl as the cache key, then we can get profile data by appgroup - */ - String fieldKey = appgroup + "@" + appurl; + /** + * use appgroup + appurl as the cache key, then we can get profile data + * by appgroup + */ + String fieldKey = appgroup + "@" + appurl; - cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO, fieldKey, - JSONHelper.toString(pi)); + cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO, fieldKey, + JSONHelper.toString(pi)); - /** - * NOTE: 独立存储类库,这样可以减少profile的数据量,提升加载速度,需要读取类库时再读取 - */ - cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO_JARLIB, - fieldKey, jarLib); - } + /** + * NOTE: 独立存储类库,这样可以减少profile的数据量,提升加载速度,需要读取类库时再读取 + */ + cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO_JARLIB, + fieldKey, jarLib); + } - /** - * buildDubboServiceComponents - * - * @param mdf - * @param pi - * @param appid - * @param compServices - */ - @SuppressWarnings("unchecked") - private void buildDubboServiceComponents(MonitorDataFrame mdf, Map pi, String appid, - Map> compServices) { + /** + * buildDubboServiceComponents + * + * @param mdf + * @param pi + * @param appid + * @param compServices + */ + @SuppressWarnings("unchecked") + private void buildDubboServiceComponents(MonitorDataFrame mdf, Map pi, String appid, + Map> compServices) { - Map comps = mdf.getElemInstValues(appid, "cpt", "com.alibaba.dubbo.config.spring.ServiceBean"); + Map comps = mdf.getElemInstValues(appid, "cpt", "com.alibaba.dubbo.config.spring.ServiceBean"); - // 获取dubbo provider的ip - String ip = mdf.getIP(); - if (comps == null || comps.size() == 0) { - return; - } + // 获取dubbo provider的ip + String ip = mdf.getIP(); + if (comps == null || comps.size() == 0) { + return; + } - pi.put("cpt.dubbo.provider", JSONHelper.toString(comps)); + pi.put("cpt.dubbo.provider", JSONHelper.toString(comps)); - for (String compName : comps.keySet()) { + for (String compName : comps.keySet()) { - Map info = (Map) comps.get(compName); + Map info = (Map) comps.get(compName); - Set compServicesURLs = compServices.get(compName); + Set compServicesURLs = compServices.get(compName); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compName, compServicesURLs); - } + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compName, compServicesURLs); + } - String group = (String) info.get("group"); - String version = (String) info.get("version"); - String servcls = (String) info.get("servcls"); + String group = (String) info.get("group"); + String version = (String) info.get("version"); + String servcls = (String) info.get("servcls"); - Map compMethodInfo = (Map) info.get("methods"); + Map compMethodInfo = (Map) info.get("methods"); - if (compMethodInfo == null || compMethodInfo.size() == 0) { - continue; - } + if (compMethodInfo == null || compMethodInfo.size() == 0) { + continue; + } - Map protocols = (Map) info.get("protocols"); + Map protocols = (Map) info.get("protocols"); - if (protocols == null || protocols.size() == 0) { - continue; - } + if (protocols == null || protocols.size() == 0) { + continue; + } - for (String method : compMethodInfo.keySet()) { + for (String method : compMethodInfo.keySet()) { - for (String protocol : protocols.keySet()) { + for (String protocol : protocols.keySet()) { - Map pAttrs = (Map) protocols.get(protocol); + Map pAttrs = (Map) protocols.get(protocol); - Integer port = (Integer) pAttrs.get("port"); - String path = (String) pAttrs.get("path"); + Integer port = (Integer) pAttrs.get("port"); + String path = (String) pAttrs.get("path"); - path = (StringHelper.isEmpty(path)) ? servcls : path; + path = (StringHelper.isEmpty(path)) ? servcls : path; - String url = getDubboURL(ip, group, version, method, port, protocol, path); + String url = getDubboURL(ip, group, version, method, port, protocol, path); - compServicesURLs.add(url); - } - } - } - } + compServicesURLs.add(url); + } + } + } + } - private String getDubboURL(String ip, String group, String version, String method, Integer localPort, - String protocol, String path) { + private String getDubboURL(String ip, String group, String version, String method, Integer localPort, + String protocol, String path) { - StringBuilder requestURL = new StringBuilder(); + StringBuilder requestURL = new StringBuilder(); - requestURL.append(protocol).append("://").append(ip).append(":").append(localPort); + requestURL.append(protocol).append("://").append(ip).append(":").append(localPort); - if (group != null) { - requestURL.append(":").append(group); - } + if (group != null) { + requestURL.append(":").append(group); + } - requestURL.append("/").append(path); + requestURL.append("/").append(path); - if (version != null) { - requestURL.append(".").append(version); - } + if (version != null) { + requestURL.append(".").append(version); + } - requestURL.append("/").append(method); + requestURL.append("/").append(method); - return requestURL.toString(); - } + return requestURL.toString(); + } - /** - * buildMSCPServiceComponents - * - * @param mdf - * @param pi - * @param appid - * @param compServices - */ - @SuppressWarnings("unchecked") - private void buildMSCPServiceComponents(MonitorDataFrame mdf, Map pi, String appid, - Map> compServices) { + /** + * buildMSCPServiceComponents + * + * @param mdf + * @param pi + * @param appid + * @param compServices + */ + @SuppressWarnings("unchecked") + private void buildMSCPServiceComponents(MonitorDataFrame mdf, Map pi, String appid, + Map> compServices) { - // http comp - Map mscpHttp = mdf.getElemInstValues(appid, "cpt", - "com.creditease.agent.spi.AbstractBaseHttpServComponent"); + // http comp + Map mscpHttp = mdf.getElemInstValues(appid, "cpt", + "com.creditease.agent.spi.AbstractBaseHttpServComponent"); - if (mscpHttp != null && mscpHttp.size() > 0) { + if (mscpHttp != null && mscpHttp.size() > 0) { - pi.put("cpt.mscp.http", JSONHelper.toString(mscpHttp)); + pi.put("cpt.mscp.http", JSONHelper.toString(mscpHttp)); - for (String mscpCompName : mscpHttp.keySet()) { - Map info = (Map) mscpHttp.get(mscpCompName); + for (String mscpCompName : mscpHttp.keySet()) { + Map info = (Map) mscpHttp.get(mscpCompName); - Set compServicesURLs = compServices.get(mscpCompName); + Set compServicesURLs = compServices.get(mscpCompName); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(mscpCompName, compServicesURLs); - } + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(mscpCompName, compServicesURLs); + } - String httpRootPath = (String) info.get("path"); + String httpRootPath = (String) info.get("path"); - Map handlers = (Map) info.get("handlers"); + Map handlers = (Map) info.get("handlers"); - for (String handlerName : handlers.keySet()) { + for (String handlerName : handlers.keySet()) { - Map handlerInfo = (Map) handlers.get(handlerName); + Map handlerInfo = (Map) handlers.get(handlerName); - String handlerPath = (String) handlerInfo.get("path"); + String handlerPath = (String) handlerInfo.get("path"); - String serviceURL = httpRootPath + handlerPath; + String serviceURL = httpRootPath + handlerPath; - compServicesURLs.add(serviceURL); - } - } - } + compServicesURLs.add(serviceURL); + } + } + } - // timer work - Map mscpTimeWork = mdf.getElemInstValues(appid, "cpt", - "com.creditease.agent.spi.AbstractTimerWork"); + // timer work + Map mscpTimeWork = mdf.getElemInstValues(appid, "cpt", + "com.creditease.agent.spi.AbstractTimerWork"); - if (mscpTimeWork != null && mscpTimeWork.size() > 0) { - pi.put("cpt.mscp.timework", JSONHelper.toString(mscpTimeWork)); - } - } + if (mscpTimeWork != null && mscpTimeWork.size() > 0) { + pi.put("cpt.mscp.timework", JSONHelper.toString(mscpTimeWork)); + } + } - /** - * buildJEEServiceComponents - * - * @param mdf - * @param pi - * @param appid - * @param appurl - * @param compServices - */ - private void buildJEEServiceComponents(MonitorDataFrame mdf, Map pi, String appid, String appurl, - Map> compServices) { + /** + * buildJEEServiceComponents + * + * @param mdf + * @param pi + * @param appid + * @param appurl + * @param compServices + */ + private void buildJEEServiceComponents(MonitorDataFrame mdf, Map pi, String appid, String appurl, + Map> compServices) { - Map filters = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebFilter"); + Map filters = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebFilter"); - Map listeners = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebListener"); + Map listeners = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebListener"); - pi.put("cpt.filters", JSONHelper.toString(filters)); + pi.put("cpt.filters", JSONHelper.toString(filters)); - pi.put("cpt.listeners", JSONHelper.toString(listeners)); + pi.put("cpt.listeners", JSONHelper.toString(listeners)); - Map servlets = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebServlet"); + Map servlets = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebServlet"); - // all servlet based tech - if (servlets == null || servlets.size() == 0) { - return; - } + // all servlet based tech + if (servlets == null || servlets.size() == 0) { + return; + } - // get servlets URLs - Map serviceServlets = getServletsURLs(appurl, compServices, servlets); + // get servlets URLs + Map serviceServlets = getServletsURLs(appurl, compServices, servlets); - Map jaxws = mdf.getElemInstValues(appid, "cpt", "javax.jws.WebService"); + Map jaxws = mdf.getElemInstValues(appid, "cpt", "javax.jws.WebService"); - String jaxwsBaseURL = serviceServlets.get("jaxws"); + String jaxwsBaseURL = serviceServlets.get("jaxws"); - // get jaxws URLs - getJAXWSURLs(compServices, jaxws, serviceServlets, appurl); + // get jaxws URLs + getJAXWSURLs(compServices, jaxws, serviceServlets, appurl); - Map jaxwsProviders = mdf.getElemInstValues(appid, "cpt", "javax.xml.ws.WebServiceProvider"); + Map jaxwsProviders = mdf.getElemInstValues(appid, "cpt", "javax.xml.ws.WebServiceProvider"); - // get jaxws provider urls - getJAXWSProviderURLs(jaxwsBaseURL, compServices, jaxwsProviders); + // get jaxws provider urls + getJAXWSProviderURLs(jaxwsBaseURL, compServices, jaxwsProviders); - Map jaxrs = mdf.getElemInstValues(appid, "cpt", "javax.ws.rs.Path"); + Map jaxrs = mdf.getElemInstValues(appid, "cpt", "javax.ws.rs.Path"); - // get jaxrs urls - String jaxrsBaseURL = serviceServlets.get("jaxrs"); + // get jaxrs urls + String jaxrsBaseURL = serviceServlets.get("jaxrs"); - getJAXRSURLs(jaxrsBaseURL, compServices, jaxrs); + getJAXRSURLs(jaxrsBaseURL, compServices, jaxrs); - Map springMVC = mdf.getElemInstValues(appid, "cpt", - "org.springframework.stereotype.Controller"); + Map springMVC = mdf.getElemInstValues(appid, "cpt", + "org.springframework.stereotype.Controller"); - Map springMVCRest = mdf.getElemInstValues(appid, "cpt", - "org.springframework.web.bind.annotation.RestController"); + Map springMVCRest = mdf.getElemInstValues(appid, "cpt", + "org.springframework.web.bind.annotation.RestController"); - // get spring mvc urls - String springmvcBaseURL = serviceServlets.get("springmvc"); + // get spring mvc urls + String springmvcBaseURL = serviceServlets.get("springmvc"); - getSpringMVCURLs(springmvcBaseURL, compServices, springMVC); + getSpringMVCURLs(springmvcBaseURL, compServices, springMVC); - getSpringMVCURLs(springmvcBaseURL, compServices, springMVCRest); + getSpringMVCURLs(springmvcBaseURL, compServices, springMVCRest); - pi.put("cpt.servlets", JSONHelper.toString(servlets)); + // get struts2 urls + Map strutsAction = mdf.getElemInstValues(appid, "cpt", "com.opensymphony.xwork2.Action"); + getStruts2URLs(appurl, compServices, strutsAction); - pi.put("cpt.jaxws", JSONHelper.toString(jaxws)); - pi.put("cpt.jaxwsP", JSONHelper.toString(jaxwsProviders)); - pi.put("cpt.jaxrs", JSONHelper.toString(jaxrs)); - pi.put("cpt.springmvc", JSONHelper.toString(springMVC)); - pi.put("cpt.springmvcRest", JSONHelper.toString(springMVCRest)); - } + pi.put("cpt.servlets", JSONHelper.toString(servlets)); + pi.put("cpt.jaxws", JSONHelper.toString(jaxws)); + pi.put("cpt.jaxwsP", JSONHelper.toString(jaxwsProviders)); + pi.put("cpt.jaxrs", JSONHelper.toString(jaxrs)); + pi.put("cpt.springmvc", JSONHelper.toString(springMVC)); + pi.put("cpt.springmvcRest", JSONHelper.toString(springMVCRest)); + pi.put("cpt.struts2", JSONHelper.toString(strutsAction)); + } - /** - * getJAXWSProviderURLs - * - * @param jaxwsBaseUrl - * @param compServices - * @param jaxws - */ - @SuppressWarnings("unchecked") - private void getJAXWSProviderURLs(String jaxwsBaseUrl, Map> compServices, - Map jaxws) { + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void getStruts2URLsByAnno(String appurl, Map> compServices, + Map strutsAction, String key, Set extSet) { - for (String compId : jaxws.keySet()) { + Set compServicesURLs = compServices.get(key); + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(key, compServicesURLs); + } - Map compInfo = (Map) jaxws.get(compId); + Map valueMap = (Map) strutsAction.get(key); - Set compServicesURLs = compServices.get(compId); + Map methodsMap = (Map) valueMap.get("methods"); + Map classAnnoMap = (Map) valueMap.get("anno"); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + // get namespaces + Set namespaces = new HashSet(); - /** - * NODE: provider may not support description style, so only process annotation - */ - if (compInfo.containsKey("anno")) { + if (classAnnoMap != null && classAnnoMap.size() > 0) { + for (Map.Entry classAnno : classAnnoMap.entrySet()) { - Map compDesInfo = (Map) compInfo.get("anno"); + String annoKey = classAnno.getKey(); + Object annoValue = classAnno.getValue(); - Map annoWebService = (Map) compDesInfo - .get("javax.xml.ws.WebServiceProvider"); + if ("org.apache.struts2.convention.annotation.Namespace".equals(annoKey)) { + namespaces.add((String) ((Map) annoValue).get("value")); + } - String serviceName = (String) annoWebService.get("serviceName"); + if ("org.apache.struts2.convention.annotation.Namespaces".equals(annoKey)) { - if (StringHelper.isEmpty(serviceName)) { + List aList = (List) ((Map) annoValue).get("value"); - String[] serviceImplClsInfo = compId.split("\\."); + for (Object obj : aList) { + namespaces.add((String) ((Map) obj).get("value")); + } + } - serviceName = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; - } + } + } else { + namespaces.add("/"); + } - String serviceURL = jaxwsBaseUrl + serviceName; - compServicesURLs.add(serviceURL); - } - } - } + // get actions + Set actionNames = new HashSet(); + if (methodsMap != null) { + for (Map.Entry method : methodsMap.entrySet()) { - /** - * getSpringMVCURLs - * - * @param springMVCBaseUrl - * @param compServices - * @param spring - */ - @SuppressWarnings("unchecked") - private void getSpringMVCURLs(String springMVCBaseUrl, Map> compServices, - Map spring) { + Map map = (Map) method.getValue(); + if (map.get("anno") == null) { + continue; + } - String realSpringMVCBaseUrl = null; - String suffix = ""; - if (springMVCBaseUrl != null) { + Map methodAnnoMap = (Map) map.get("anno"); - // NOTE: handle *.xxx,should remove *.xxx - realSpringMVCBaseUrl = springMVCBaseUrl; + for (Map.Entry methodAnno : methodAnnoMap.entrySet()) { - int allIndex = realSpringMVCBaseUrl.indexOf("*"); + String annoKey = methodAnno.getKey(); + Object annoValue = methodAnno.getValue(); - if (allIndex > -1) { + // if have Actions annotation ignore Action annotation + if ("org.apache.struts2.convention.annotation.Actions".equals(annoKey)) { - // check if there is suffix, such as *.do - if (allIndex != realSpringMVCBaseUrl.length() - 1) { - suffix = realSpringMVCBaseUrl.substring(allIndex + 1); - } + List aList = (List) ((Map) annoValue).get("value"); - // get the real access path - realSpringMVCBaseUrl = realSpringMVCBaseUrl.substring(0, allIndex); - } - } + for (Object obj : aList) { + actionNames.add((String) ((Map) obj).get("value")); + } - for (String compId : spring.keySet()) { + continue; + } - Map compInfo = (Map) spring.get(compId); + if ("org.apache.struts2.convention.annotation.Action".equals(annoKey) + && !methodAnnoMap.containsKey("org.apache.struts2.convention.annotation.Actions")) { + actionNames.add((String) ((Map) annoValue).get("value")); + } + } + } + } - Set compServicesURLs = compServices.get(compId); + Iterator nsIterator = namespaces.iterator(); + while (nsIterator.hasNext()) { + String ns = nsIterator.next(); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + if (!"/".equals(ns)) { + ns = ns + "/"; + } - if (!compInfo.containsKey("anno")) { - continue; - } + Iterator actionNamesIterator = actionNames.iterator(); + while (actionNamesIterator.hasNext()) { + String actionName = actionNamesIterator.next(); - // get resourceClass path - Map compDesInfo = (Map) compInfo.get("anno"); + Iterator extIterator = extSet.iterator(); + while (extIterator.hasNext()) { + String ext = extIterator.next(); + if (!"".equals(ext)) { + ext = "." + ext; + } + compServicesURLs.add(appurl.substring(0, appurl.length() - 1) + ns + actionName + ext); + } - List resourceClassRelativePaths = null; + } + } + } - /** - * NOTE: RequestMapping is optional to spring mvc resource class - */ + @SuppressWarnings("unchecked") + private void getStruts2URLsByDes(String appurl, Map> compServices, + Map strutsAction, String key, Set extSet) { - Map annoWebService = (Map) compDesInfo - .get("org.springframework.web.bind.annotation.RequestMapping"); + Set compServicesURLs = compServices.get(key); + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(key, compServicesURLs); + } - if (annoWebService != null) { + Map valueMap = (Map) strutsAction.get(key); - resourceClassRelativePaths = (List) annoWebService.get("value"); - } + // get action urls by des + List desList = (List) (valueMap.get("des")); + if (desList == null || desList.size() <= 0) { + return; + } - /** - * if there is no path on resource class, we take the path as "" - */ - if (resourceClassRelativePaths == null) { - resourceClassRelativePaths = new ArrayList(); - resourceClassRelativePaths.add(""); - } + Iterator extIterator = extSet.iterator(); + while (extIterator.hasNext()) { + String ext = extIterator.next(); + if (!"".equals(ext)) { + ext = "." + ext; + } - for (String resourceClassRelativePath : resourceClassRelativePaths) { + for (Object desObj : desList) { + Map aMap = (Map) desObj; - resourceClassRelativePath = formatRelativePath(resourceClassRelativePath); + String ns = (String) aMap.get("namespace"); - // get the resource class path - String resourceClassPath = realSpringMVCBaseUrl + resourceClassRelativePath; + if (!"/".equals(ns)) { + ns = ns + "/"; + } - // get methods path - Map compMethodInfo = (Map) compInfo.get("methods"); + compServicesURLs.add(appurl.substring(0, appurl.length() - 1) + ns + aMap.get("name") + ext); + } + } + } - for (String method : compMethodInfo.keySet()) { + private void getStruts2URLs(String appurl, Map> compServices, + Map strutsAction) { - Map methodInfo = (Map) compMethodInfo.get(method); + for (Map.Entry entry : strutsAction.entrySet()) { - if (!methodInfo.containsKey("anno")) { - continue; - } + String key = entry.getKey(); - Map methodAnnoInfo = (Map) methodInfo.get("anno"); + if ("com.opensymphony.xwork2.ActionSupport".equals(key)) { + continue; + } - String serviceURL = formatRelativePath(resourceClassPath); + Set extSet = getStruts2URLExtension(strutsAction); + getStruts2URLsByAnno(appurl, compServices, strutsAction, key, extSet); + getStruts2URLsByDes(appurl, compServices, strutsAction, key, extSet); - /** - * each method has Path info except only one - */ - if (methodAnnoInfo.containsKey("org.springframework.web.bind.annotation.RequestMapping")) { + } - Map pathAnnoInfo = (Map) methodAnnoInfo - .get("org.springframework.web.bind.annotation.RequestMapping"); + // ignore com.opensymphony.xwork2.ActionSupport + strutsAction.remove("com.opensymphony.xwork2.ActionSupport"); + } - List methodRelativePaths = (List) pathAnnoInfo.get("value"); + @SuppressWarnings("unchecked") + private Set getStruts2URLExtension(Map strutsAction) { - // FIX NPE - if (methodRelativePaths == null) { - compServicesURLs.add(serviceURL); - continue; - } + Set extSet = new HashSet(); - for (String methodRelativePath : methodRelativePaths) { + for (Map.Entry entry : strutsAction.entrySet()) { - methodRelativePath = formatRelativePath(methodRelativePath); + String key = entry.getKey(); + Object value = entry.getValue(); - String methodServiceURL; + if ("com.opensymphony.xwork2.ActionSupport".equals(key)) { + continue; + } - if (methodRelativePath.endsWith(suffix)) { + Map valueMap = (Map) value; - methodServiceURL = formatRelativePath(serviceURL + "/" + methodRelativePath); - } - else { - methodServiceURL = formatRelativePath(serviceURL + "/" + methodRelativePath + suffix); - } + List desList = (List) valueMap.get("des"); - compServicesURLs.add(methodServiceURL); - } - } - else { - compServicesURLs.add(serviceURL); - } - } + if (desList == null) { + continue; + } - } - } - } + for (Object desObj : desList) { + Map aMap = (Map) desObj; + Object extObj = aMap.get("extension"); + if (extObj == null) { + continue; + } - /** - * getJAXRSURLs - * - * @param jaxrsBaseUrl - * @param compServices - * @param jaxrs - */ - @SuppressWarnings("unchecked") - private void getJAXRSURLs(String jaxrsBaseUrl, Map> compServices, Map jaxrs) { + String[] extArr = ((String) extObj).split(","); - for (String compId : jaxrs.keySet()) { + List extList = Arrays.asList(extArr); - Map compInfo = (Map) jaxrs.get(compId); + extSet.addAll(extList); - Set compServicesURLs = compServices.get(compId); + return extSet; + } + } - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + if (extSet.size() <= 0) { + extSet.add("action"); + } - if (!compInfo.containsKey("anno")) { - continue; - } + return extSet; + } - // get resourceClass path - Map compDesInfo = (Map) compInfo.get("anno"); + /** + * getJAXWSProviderURLs + * + * @param jaxwsBaseUrl + * @param compServices + * @param jaxws + */ + @SuppressWarnings("unchecked") + private void getJAXWSProviderURLs(String jaxwsBaseUrl, Map> compServices, + Map jaxws) { - Map annoWebService = (Map) compDesInfo.get("javax.ws.rs.Path"); + for (String compId : jaxws.keySet()) { - String resourceClassRelativePath = (String) annoWebService.get("value"); + Map compInfo = (Map) jaxws.get(compId); - resourceClassRelativePath = formatRelativePath(resourceClassRelativePath); + Set compServicesURLs = compServices.get(compId); - // get the resource class path - String resourceClassPath = jaxrsBaseUrl + resourceClassRelativePath - + ("".equalsIgnoreCase(resourceClassRelativePath) ? "" : "/"); + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } - // get methods path - Map compMethodInfo = (Map) compInfo.get("methods"); + /** + * NODE: provider may not support description style, so only process + * annotation + */ + if (compInfo.containsKey("anno")) { - for (String method : compMethodInfo.keySet()) { + Map compDesInfo = (Map) compInfo.get("anno"); - Map methodInfo = (Map) compMethodInfo.get(method); + Map annoWebService = (Map) compDesInfo + .get("javax.xml.ws.WebServiceProvider"); - if (!methodInfo.containsKey("anno")) { - continue; - } + String serviceName = (String) annoWebService.get("serviceName"); - Map methodAnnoInfo = (Map) methodInfo.get("anno"); + if (StringHelper.isEmpty(serviceName)) { - String serviceURL = resourceClassPath; + String[] serviceImplClsInfo = compId.split("\\."); - /** - * each method has Path info except only one - */ - if (methodAnnoInfo.containsKey("javax.ws.rs.Path")) { - Map pathAnnoInfo = (Map) methodAnnoInfo.get("javax.ws.rs.Path"); + serviceName = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; + } - String methodRelativePath = (String) pathAnnoInfo.get("value"); + String serviceURL = jaxwsBaseUrl + serviceName; + compServicesURLs.add(serviceURL); + } + } + } - methodRelativePath = formatRelativePath(methodRelativePath); + /** + * getSpringMVCURLs + * + * @param springMVCBaseUrl + * @param compServices + * @param spring + */ + @SuppressWarnings("unchecked") + private void getSpringMVCURLs(String springMVCBaseUrl, Map> compServices, + Map spring) { - serviceURL += methodRelativePath; - } - else { - serviceURL = serviceURL.substring(0, serviceURL.length() - 1); - } + String realSpringMVCBaseUrl = null; + String suffix = ""; + if (springMVCBaseUrl != null) { - compServicesURLs.add(serviceURL); - } - } - } + // NOTE: handle *.xxx,should remove *.xxx + realSpringMVCBaseUrl = springMVCBaseUrl; - /** - * getJAXWSURLs - * - * @param jaxwsBaseUrl - * @param compServices - * @param jaxws - */ - @SuppressWarnings("unchecked") - private void getJAXWSURLs(Map> compServices, Map jaxws, - Map serviceServlets, String appurl) { + int allIndex = realSpringMVCBaseUrl.indexOf("*"); - String jaxwsBaseUrl = serviceServlets.get("jaxws"); + if (allIndex > -1) { - for (String compId : jaxws.keySet()) { + // check if there is suffix, such as *.do + if (allIndex != realSpringMVCBaseUrl.length() - 1) { + suffix = realSpringMVCBaseUrl.substring(allIndex + 1); + } - Map compInfo = (Map) jaxws.get(compId); + // get the real access path + realSpringMVCBaseUrl = realSpringMVCBaseUrl.substring(0, allIndex); + } + } - Set compServicesURLs = compServices.get(compId); + for (String compId : spring.keySet()) { - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + Map compInfo = (Map) spring.get(compId); - if (compInfo.containsKey("dyn")) { + Set compServicesURLs = compServices.get(compId); - Map compDesInfo = (Map) compInfo.get("dyn"); + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } - String url = (String) compDesInfo.get("url"); + if (!compInfo.containsKey("anno")) { + continue; + } - String serviceURL = null; + // get resourceClass path + Map compDesInfo = (Map) compInfo.get("anno"); - if (StringHelper.isEmpty(url)) { + List resourceClassRelativePaths = null; - String[] serviceImplClsInfo = compId.split("\\."); + /** + * NOTE: RequestMapping is optional to spring mvc resource class + */ - url = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; + Map annoWebService = (Map) compDesInfo + .get("org.springframework.web.bind.annotation.RequestMapping"); - serviceURL = jaxwsBaseUrl + url; + if (annoWebService != null) { - } - else if (url.startsWith("http")) { + resourceClassRelativePaths = (List) annoWebService.get("value"); + } - serviceURL = url; + /** + * if there is no path on resource class, we take the path as "" + */ + if (resourceClassRelativePaths == null) { + resourceClassRelativePaths = new ArrayList(); + resourceClassRelativePaths.add(""); + } - } - else { + for (String resourceClassRelativePath : resourceClassRelativePaths) { - url = this.formatRelativePath(url); - serviceURL = jaxwsBaseUrl + url; - } + resourceClassRelativePath = formatRelativePath(resourceClassRelativePath); - compServicesURLs.add(serviceURL); + // get the resource class path + String resourceClassPath = realSpringMVCBaseUrl + resourceClassRelativePath; - } - else if (compInfo.containsKey("des")) { + // get methods path + Map compMethodInfo = (Map) compInfo.get("methods"); - Map compDesInfo = (Map) compInfo.get("des"); + for (String method : compMethodInfo.keySet()) { - String url = (String) compDesInfo.get("address"); + Map methodInfo = (Map) compMethodInfo.get(method); - if (url == null) { - url = (String) compDesInfo.get("url-pattern"); - } + if (!methodInfo.containsKey("anno")) { + continue; + } - if ("".equals(url)) { - url = "@UNKOWN_SERVICE"; - } + Map methodAnnoInfo = (Map) methodInfo.get("anno"); - url = this.formatRelativePath(url); - String serviceURL = null; - if (compDesInfo.get("address") != null) { - serviceURL = jaxwsBaseUrl + url; - } - else if (compDesInfo.get("url-pattern") != null) { - serviceURL = appurl + url; - } + String serviceURL = formatRelativePath(resourceClassPath); - compServicesURLs.add(serviceURL); - } - else if (compInfo.containsKey("anno")) { + /** + * each method has Path info except only one + */ + if (methodAnnoInfo.containsKey("org.springframework.web.bind.annotation.RequestMapping")) { - Map compDesInfo = (Map) compInfo.get("anno"); + Map pathAnnoInfo = (Map) methodAnnoInfo + .get("org.springframework.web.bind.annotation.RequestMapping"); - Map annoWebService = (Map) compDesInfo.get("javax.jws.WebService"); + List methodRelativePaths = (List) pathAnnoInfo.get("value"); - String serviceName = (String) annoWebService.get("serviceName"); + // FIX NPE + if (methodRelativePaths == null) { + compServicesURLs.add(serviceURL); + continue; + } - if (StringHelper.isEmpty(serviceName)) { + for (String methodRelativePath : methodRelativePaths) { - String[] serviceImplClsInfo = compId.split("\\."); + methodRelativePath = formatRelativePath(methodRelativePath); - serviceName = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; - } + String methodServiceURL; - String serviceURL = jaxwsBaseUrl + serviceName; - compServicesURLs.add(serviceURL); - } - } - } + if (methodRelativePath.endsWith(suffix)) { - /** - * getServletsURLs - * - * @param appURL - * @param compServices - * @param servlets - * @return - */ - @SuppressWarnings("unchecked") - private Map getServletsURLs(String appURL, Map> compServices, - Map servlets) { + methodServiceURL = formatRelativePath(serviceURL + "/" + methodRelativePath); + } else { + methodServiceURL = formatRelativePath(serviceURL + "/" + methodRelativePath + suffix); + } - // temp store the service base url - Map serviceServlets = new LinkedHashMap(); + compServicesURLs.add(methodServiceURL); + } + } else { + compServicesURLs.add(serviceURL); + } + } - for (String compId : servlets.keySet()) { + } + } + } - Map compInfo = (Map) servlets.get(compId); + /** + * getJAXRSURLs + * + * @param jaxrsBaseUrl + * @param compServices + * @param jaxrs + */ + @SuppressWarnings("unchecked") + private void getJAXRSURLs(String jaxrsBaseUrl, Map> compServices, Map jaxrs) { - Set compServicesURLs = compServices.get(compId); + for (String compId : jaxrs.keySet()) { - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + Map compInfo = (Map) jaxrs.get(compId); - if (compInfo.containsKey("des")) { + Set compServicesURLs = compServices.get(compId); - Map compDesInfo = (Map) compInfo.get("des"); + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } - List urls = (List) compDesInfo.get("urlPatterns"); + if (!compInfo.containsKey("anno")) { + continue; + } - if (null == urls || urls.size() == 0) { - continue; - } + // get resourceClass path + Map compDesInfo = (Map) compInfo.get("anno"); - for (String url : urls) { + Map annoWebService = (Map) compDesInfo.get("javax.ws.rs.Path"); - // remove /* for better match, will not handle *.xxxx - if (url.lastIndexOf("*") == url.length() - 1) { - url = url.substring(0, url.length() - 1); - } + String resourceClassRelativePath = (String) annoWebService.get("value"); - url = formatRelativePath(url); + resourceClassRelativePath = formatRelativePath(resourceClassRelativePath); - String serviceURL = appURL + url; + // get the resource class path + String resourceClassPath = jaxrsBaseUrl + resourceClassRelativePath + + ("".equalsIgnoreCase(resourceClassRelativePath) ? "" : "/"); - if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { - serviceURL = serviceURL.substring(0, serviceURL.length() - 1); - } + // get methods path + Map compMethodInfo = (Map) compInfo.get("methods"); - findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); + for (String method : compMethodInfo.keySet()) { - compServicesURLs.add(serviceURL); - } - } - else if (compInfo.containsKey("dyn")) { + Map methodInfo = (Map) compMethodInfo.get(method); - Map compDesInfo = (Map) compInfo.get("dyn"); + if (!methodInfo.containsKey("anno")) { + continue; + } - List urls = (List) compDesInfo.get("urlPatterns"); + Map methodAnnoInfo = (Map) methodInfo.get("anno"); - if (null == urls || urls.size() == 0) { - continue; - } + String serviceURL = resourceClassPath; - for (String url : urls) { + /** + * each method has Path info except only one + */ + if (methodAnnoInfo.containsKey("javax.ws.rs.Path")) { + Map pathAnnoInfo = (Map) methodAnnoInfo.get("javax.ws.rs.Path"); - // remove /* for better match, will not handle *.xxxx - if (url.lastIndexOf("*") == url.length() - 1) { - url = url.substring(0, url.length() - 1); - } + String methodRelativePath = (String) pathAnnoInfo.get("value"); - url = formatRelativePath(url); + methodRelativePath = formatRelativePath(methodRelativePath); - String serviceURL = appURL + url; + serviceURL += methodRelativePath; + } else { + serviceURL = serviceURL.substring(0, serviceURL.length() - 1); + } - if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { - serviceURL = serviceURL.substring(0, serviceURL.length() - 1); - } + compServicesURLs.add(serviceURL); + } + } + } - findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); + /** + * getJAXWSURLs + * + * @param jaxwsBaseUrl + * @param compServices + * @param jaxws + */ + @SuppressWarnings("unchecked") + private void getJAXWSURLs(Map> compServices, Map jaxws, + Map serviceServlets, String appurl) { - compServicesURLs.add(serviceURL); - } - } - else if (compInfo.containsKey("anno")) { + String jaxwsBaseUrl = serviceServlets.get("jaxws"); - Map compDesInfo = (Map) compInfo.get("anno"); + for (String compId : jaxws.keySet()) { - for (String compDescId : compDesInfo.keySet()) { - Map compDescInfo = (Map) compDesInfo.get(compDescId); + Map compInfo = (Map) jaxws.get(compId); - List urls = (List) compDescInfo.get("urlPatterns"); + Set compServicesURLs = compServices.get(compId); - if (null == urls || urls.size() == 0) { - urls = (List) compDescInfo.get("value"); - } + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } - if (null == urls || urls.size() == 0) { - continue; - } + if (compInfo.containsKey("dyn")) { - for (String url : urls) { + Map compDesInfo = (Map) compInfo.get("dyn"); - // remove /* for better match, will not handle *.xxxx - if (url.lastIndexOf("*") == url.length() - 1) { - url = url.substring(0, url.length() - 1); - } + String url = (String) compDesInfo.get("url"); - url = formatRelativePath(url); + String serviceURL = null; - String serviceURL = appURL + url; + if (StringHelper.isEmpty(url)) { - if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { - serviceURL = serviceURL.substring(0, serviceURL.length() - 1); - } + String[] serviceImplClsInfo = compId.split("\\."); - findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); - - compServicesURLs.add(serviceURL); - } - } - - } - } - - /** - * we should figure out which JAXWS,JAXRS engine is used NOTE: this is barely by HUMAN, not 100% right, we need - * refine this part TODO: need refine - */ - // add axis2 - if (serviceServlets.containsKey("axis2")) { - serviceServlets.put("jaxws", serviceServlets.get("axis2") + "/"); - } - else if (serviceServlets.containsKey("xfire")) { - serviceServlets.put("jaxws", serviceServlets.get("xfire") + "/"); - } - else if (serviceServlets.containsKey("cxf")) { - - serviceServlets.put("jaxws", serviceServlets.get("cxf") + "/"); - } - else if (serviceServlets.containsKey("jaxws-ri")) { - - serviceServlets.put("jaxws", serviceServlets.get("jaxws-ri") + "/"); - } - - // add wink - if (serviceServlets.containsKey("wink")) { - serviceServlets.put("jaxrs", serviceServlets.get("wink") + "/"); - } - else if (serviceServlets.containsKey("jersey")) { - serviceServlets.put("jaxrs", serviceServlets.get("jersey") + "/"); - } - else if (serviceServlets.containsKey("cxf")) { - serviceServlets.put("jaxrs", serviceServlets.get("cxf") + "/"); - } - // add hession - else if (serviceServlets.containsKey("hession")) { - serviceServlets.put("jaxrs", serviceServlets.get("hession") + "/"); - } - - if (serviceServlets.containsKey("springmvc")) { - serviceServlets.put("springmvc", serviceServlets.get("springmvc") + "/"); - } - - return serviceServlets; - } - - /** - * findoutAppFrameworkServlets - * - * @param serviceServlets - * @param compId - * @param serviceURL - */ - private void findoutAppFrameworkServlets(Map serviceServlets, Map compInfo, - String serviceURL) { - - if (!compInfo.containsKey("engine")) { - return; - } - - String engine = (String) compInfo.get("engine"); - - if (engine.indexOf("cxf") > -1) { - serviceServlets.put("cxf", serviceURL); - } - else if (engine.indexOf("jersey") > -1) { - serviceServlets.put("jersey", serviceURL); - } - else if (engine.indexOf("springmvc") > -1) { - serviceServlets.put("springmvc", serviceURL); - } - else if (engine.indexOf("jaxws-ri") > -1) { - serviceServlets.put("jaxws-ri", serviceURL); - } - } - - /** - * formatRelativePath - * - * @param resourceClassRelativePath - * @return - */ - private String formatRelativePath(String resourceClassRelativePath) { - - // remove first / - if (resourceClassRelativePath.indexOf("/") == 0) { - - if (resourceClassRelativePath.length() == 1) { - resourceClassRelativePath = ""; - } - else { - resourceClassRelativePath = resourceClassRelativePath.substring(1); - } - } - - // remove last / - if (resourceClassRelativePath.lastIndexOf("/") == resourceClassRelativePath.length() - 1) { - - if (resourceClassRelativePath.length() == 1) { - resourceClassRelativePath = ""; - } - else if (resourceClassRelativePath.length() > 1) { - resourceClassRelativePath = resourceClassRelativePath.substring(0, - resourceClassRelativePath.length() - 1); - } - } - return resourceClassRelativePath; - } + url = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; + + serviceURL = jaxwsBaseUrl + url; + + } else if (url.startsWith("http")) { + + serviceURL = url; + + } else { + + url = this.formatRelativePath(url); + serviceURL = jaxwsBaseUrl + url; + } + + compServicesURLs.add(serviceURL); + + } else if (compInfo.containsKey("des")) { + + Map compDesInfo = (Map) compInfo.get("des"); + + String url = (String) compDesInfo.get("address"); + + if (url == null) { + url = (String) compDesInfo.get("url-pattern"); + } + + if ("".equals(url)) { + url = "@UNKOWN_SERVICE"; + } + + url = this.formatRelativePath(url); + String serviceURL = null; + if (compDesInfo.get("address") != null) { + serviceURL = jaxwsBaseUrl + url; + } else if (compDesInfo.get("url-pattern") != null) { + serviceURL = appurl + url; + } + + compServicesURLs.add(serviceURL); + } else if (compInfo.containsKey("anno")) { + + Map compDesInfo = (Map) compInfo.get("anno"); + + Map annoWebService = (Map) compDesInfo.get("javax.jws.WebService"); + + String serviceName = (String) annoWebService.get("serviceName"); + + if (StringHelper.isEmpty(serviceName)) { + + String[] serviceImplClsInfo = compId.split("\\."); + + serviceName = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; + } + + String serviceURL = jaxwsBaseUrl + serviceName; + compServicesURLs.add(serviceURL); + } + } + } + + /** + * getServletsURLs + * + * @param appURL + * @param compServices + * @param servlets + * @return + */ + @SuppressWarnings("unchecked") + private Map getServletsURLs(String appURL, Map> compServices, + Map servlets) { + + // temp store the service base url + Map serviceServlets = new LinkedHashMap(); + + for (String compId : servlets.keySet()) { + + Map compInfo = (Map) servlets.get(compId); + + Set compServicesURLs = compServices.get(compId); + + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } + + if (compInfo.containsKey("des")) { + + Map compDesInfo = (Map) compInfo.get("des"); + + List urls = (List) compDesInfo.get("urlPatterns"); + + if (null == urls || urls.size() == 0) { + continue; + } + + for (String url : urls) { + + // remove /* for better match, will not handle *.xxxx + if (url.lastIndexOf("*") == url.length() - 1) { + url = url.substring(0, url.length() - 1); + } + + url = formatRelativePath(url); + + String serviceURL = appURL + url; + + if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { + serviceURL = serviceURL.substring(0, serviceURL.length() - 1); + } + + findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); + + compServicesURLs.add(serviceURL); + } + } else if (compInfo.containsKey("dyn")) { + + Map compDesInfo = (Map) compInfo.get("dyn"); + + List urls = (List) compDesInfo.get("urlPatterns"); + + if (null == urls || urls.size() == 0) { + continue; + } + + for (String url : urls) { + + // remove /* for better match, will not handle *.xxxx + if (url.lastIndexOf("*") == url.length() - 1) { + url = url.substring(0, url.length() - 1); + } + + url = formatRelativePath(url); + + String serviceURL = appURL + url; + + if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { + serviceURL = serviceURL.substring(0, serviceURL.length() - 1); + } + + findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); + + compServicesURLs.add(serviceURL); + } + } else if (compInfo.containsKey("anno")) { + + Map compDesInfo = (Map) compInfo.get("anno"); + + for (String compDescId : compDesInfo.keySet()) { + Map compDescInfo = (Map) compDesInfo.get(compDescId); + + List urls = (List) compDescInfo.get("urlPatterns"); + + if (null == urls || urls.size() == 0) { + urls = (List) compDescInfo.get("value"); + } + + if (null == urls || urls.size() == 0) { + continue; + } + + for (String url : urls) { + + // remove /* for better match, will not handle *.xxxx + if (url.lastIndexOf("*") == url.length() - 1) { + url = url.substring(0, url.length() - 1); + } + + url = formatRelativePath(url); + + String serviceURL = appURL + url; + + if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { + serviceURL = serviceURL.substring(0, serviceURL.length() - 1); + } + + findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); + + compServicesURLs.add(serviceURL); + } + } + + } + } + + /** + * we should figure out which JAXWS,JAXRS engine is used NOTE: this is + * barely by HUMAN, not 100% right, we need refine this part TODO: need + * refine + */ + // add axis2 + if (serviceServlets.containsKey("axis2")) { + serviceServlets.put("jaxws", serviceServlets.get("axis2") + "/"); + } else if (serviceServlets.containsKey("xfire")) { + serviceServlets.put("jaxws", serviceServlets.get("xfire") + "/"); + } else if (serviceServlets.containsKey("cxf")) { + + serviceServlets.put("jaxws", serviceServlets.get("cxf") + "/"); + } else if (serviceServlets.containsKey("jaxws-ri")) { + + serviceServlets.put("jaxws", serviceServlets.get("jaxws-ri") + "/"); + } + + // add wink + if (serviceServlets.containsKey("wink")) { + serviceServlets.put("jaxrs", serviceServlets.get("wink") + "/"); + } else if (serviceServlets.containsKey("jersey")) { + serviceServlets.put("jaxrs", serviceServlets.get("jersey") + "/"); + } else if (serviceServlets.containsKey("cxf")) { + serviceServlets.put("jaxrs", serviceServlets.get("cxf") + "/"); + } + // add hession + else if (serviceServlets.containsKey("hession")) { + serviceServlets.put("jaxrs", serviceServlets.get("hession") + "/"); + } + + if (serviceServlets.containsKey("springmvc")) { + serviceServlets.put("springmvc", serviceServlets.get("springmvc") + "/"); + } + + return serviceServlets; + } + + /** + * findoutAppFrameworkServlets + * + * @param serviceServlets + * @param compId + * @param serviceURL + */ + private void findoutAppFrameworkServlets(Map serviceServlets, Map compInfo, + String serviceURL) { + + if (!compInfo.containsKey("engine")) { + return; + } + + String engine = (String) compInfo.get("engine"); + + if (engine.indexOf("cxf") > -1) { + serviceServlets.put("cxf", serviceURL); + } else if (engine.indexOf("jersey") > -1) { + serviceServlets.put("jersey", serviceURL); + } else if (engine.indexOf("springmvc") > -1) { + serviceServlets.put("springmvc", serviceURL); + } else if (engine.indexOf("jaxws-ri") > -1) { + serviceServlets.put("jaxws-ri", serviceURL); + } + } + + /** + * formatRelativePath + * + * @param resourceClassRelativePath + * @return + */ + private String formatRelativePath(String resourceClassRelativePath) { + + // remove first / + if (resourceClassRelativePath.indexOf("/") == 0) { + + if (resourceClassRelativePath.length() == 1) { + resourceClassRelativePath = ""; + } else { + resourceClassRelativePath = resourceClassRelativePath.substring(1); + } + } + + // remove last / + if (resourceClassRelativePath.lastIndexOf("/") == resourceClassRelativePath.length() - 1) { + + if (resourceClassRelativePath.length() == 1) { + resourceClassRelativePath = ""; + } else if (resourceClassRelativePath.length() > 1) { + resourceClassRelativePath = resourceClassRelativePath.substring(0, + resourceClassRelativePath.length() - 1); + } + } + return resourceClassRelativePath; + } } diff --git a/com.creditease.uav.monitorframework/src/main/java/com/creditease/uav/profiling/handlers/ComponentProfileHandler.java b/com.creditease.uav.monitorframework/src/main/java/com/creditease/uav/profiling/handlers/ComponentProfileHandler.java index fdef0ac9..f138ec2a 100644 --- a/com.creditease.uav.monitorframework/src/main/java/com/creditease/uav/profiling/handlers/ComponentProfileHandler.java +++ b/com.creditease.uav.monitorframework/src/main/java/com/creditease/uav/profiling/handlers/ComponentProfileHandler.java @@ -27,10 +27,12 @@ import java.lang.reflect.Method; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; @@ -52,6 +54,7 @@ import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +import com.creditease.agent.helpers.JSONHelper; import com.creditease.agent.helpers.NetworkHelper; import com.creditease.agent.helpers.ReflectHelper; import com.creditease.agent.helpers.StringHelper; @@ -1045,7 +1048,9 @@ public void loadInfo(String sKey, String sKeyRawValue, Map sInfo } }; } - else if ("/web-app/display-name".equals(xpath)) { + else if ("/web-app/display-name".equals(xpath)) + + { // get display-name as the application name ic = new DescriptorCollector() { @@ -1135,33 +1140,167 @@ protected List getDescriptorFileLocations(String webAppRoot) { } - // ----------------------------------------------annotation based component - // processor------------------------------------------------------------- - /** - * ComponentAnnotationProcessor is the interface to process component class to get the info via annotations * - * @author zhen zhang + * struts2.xml descriptor * */ - private static abstract class ComponentAnnotationProcessor { + public static class Struts2XmlProcessor extends DescriptorProcessor { - public final static String DEFAULT_VALUE = "_default_value"; + public Struts2XmlProcessor(ProfileContext context) { + super(context); + } - @SuppressWarnings("rawtypes") - public abstract Map process(Class annoCls, Class comCls, ProfileContext context); + @Override + public DescriptorCollector selectDescriptorCollector(String xpath) { - @SuppressWarnings({ "unchecked", "rawtypes" }) - protected void putAnnoValue(Class c, Class annoCls, String configName, Class configCls, - String keyName, Map info) { + DescriptorCollector ic = null; - T value = (T) ReflectHelper.getAnnotationValue(c, annoCls, configName); + if ("/struts/package/action".equals(xpath)) { - if (null == value || DEFAULT_VALUE.equals(value)) { - return; + // get actions + ic = new DescriptorCollector() { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void loadInfo(String sKey, String sKeyRawValue, Map sInfo) { + + Map elementMap = getProfileElement().getValues(); + + List desList = null; + if (elementMap.containsKey(sKey)) { + Map annoValueMap = (Map) elementMap.get(sKey); + desList = (List) annoValueMap.get("des"); + if (desList == null) { + desList = new ArrayList(); + } + desList.add(sInfo); + annoValueMap.put("des", desList); + } + else { + Map aMap = new HashMap(); + desList = new ArrayList(); + desList.add(sInfo); + aMap.put("des", desList); + elementMap.put(sKey, aMap); + } + } + }; } + return ic; + } + + @Override + protected List getDescriptorFileLocations(String webAppRoot) { + + List files = new ArrayList(); + + Document doc = null; + NodeList nodes = null; + + String webAppClasspath = webAppRoot + File.separator + "WEB-INF" + File.separator + "classes" + + File.separator; + String fileName = "struts.xml"; + File file = new File(webAppClasspath + fileName); + + if (!file.exists()) { + return files; + } + + files.add(webAppClasspath + fileName); + + try { + doc = this.getDocumentBuilder().parse(file); + nodes = (NodeList) this.xpath.evaluate("/struts/include/@file", doc, XPathConstants.NODESET); + } + catch (IOException e) { + if (this.logger.isLogEnabled()) { + this.logger.warn("Load DescriptorFile[" + file.getPath() + "] FAILs.", e); + } + } + catch (SAXException e) { + if (this.logger.isLogEnabled()) { + this.logger.warn("Load DescriptorFile[" + file.getPath() + "] FAILs.", e); + } + } + catch (XPathExpressionException e) { + if (this.logger.isLogEnabled()) { + this.logger.warn("Load DescriptorFile[" + file.getPath() + "] FAILs.", e); + } + } + + if (nodes != null) { + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + files.add(webAppClasspath + node.getTextContent()); + } + } + + return files; + } + + @Override + public void parseToPEI(final ProfileElementInstance inst, String webAppRoot, String xpath, + XMLNodeType... xmlNodeTypes) { + + final DescriptorProcessor dp = this; + + XMLParseHandler handler = new XMLParseHandler() { + + @Override + public boolean parse(DescriptorCollector dc, Node node) { + + Node extensionNode = dp.selectXMLNode("/struts/constant[@name='struts.action.extension']/@value"); + String extensionStr = "action"; + + if (extensionNode != null) { + extensionStr = extensionNode.getNodeValue(); + } + + Node pNode = node.getParentNode(); + + Node namespaceNode = pNode.getAttributes().getNamedItem("namespace"); + String namespaceStr = ""; + if (null != namespaceNode) { + namespaceStr = namespaceNode.getNodeValue(); + } + + Node nameNode = node.getAttributes().getNamedItem("name"); + Node methodNode = node.getAttributes().getNamedItem("method"); + Node classNode = node.getAttributes().getNamedItem("class"); + if (classNode == null) { + return true; + } + + String methodStr = "execute"; + String nameStr = nameNode.getNodeValue(); + String classStr = classNode.getNodeValue(); + + if (methodNode != null) { + methodStr = methodNode.getNodeValue(); + } + + Map actionMap = new HashMap(); + + actionMap.put("namespace", namespaceStr); + actionMap.put("name", nameStr); + actionMap.put("method", methodStr); + actionMap.put("class", classStr); + actionMap.put("extension", extensionStr); + + dc.setProfileElement(inst).loadInfo(classStr, "", actionMap); + + return true; + } + + }; + + this.parse(webAppRoot, xpath, handler, xmlNodeTypes); } + } + + private static abstract class ComponentProcessor { @SuppressWarnings("rawtypes") protected Class[] loadAnnoClasses(ProfileContext context, String... classNames) { @@ -1190,9 +1329,93 @@ protected Class[] loadAnnoClasses(ProfileContext context, String... classNames) return annoClasses; } + } + + // ----------------------------------------------Interface based component + // processor------------------------------------------------------------- + + private static abstract class ComponentInterfaceProcessor extends ComponentProcessor { + + public abstract Map process(Class comCls, ProfileContext context); } + private static class Struts2ActionInfoProcessor extends ComponentInterfaceProcessor { + + @SuppressWarnings("rawtypes") + @Override + public Map process(Class comCls, ProfileContext context) { + + Map info = new LinkedHashMap(); + + Class[] annoClasses = this.loadAnnoClasses(context, + new String[] { "org.apache.struts2.convention.annotation.Namespace", + "org.apache.struts2.convention.annotation.Namespaces", + "org.apache.struts2.convention.annotation.Action", + "org.apache.struts2.convention.annotation.Actions" }); + + if (null == annoClasses || annoClasses.length == 0) { + return info; + } + + getClassAnnoInfo(comCls, info, annoClasses[0], annoClasses[1]); + + // get method info + getMethodInfo(comCls, info, annoClasses[2], annoClasses[3]); + + // 这里是一处special处理,替换注解中的转义字符 + return encodeAnnoInfo(info); + } + + /** + * 将类似下面的注解信息中的带转义引号(\")替换为单引号 + * + * @Action(value = "downloadModel", results = { @Result(type = "stream", params = {"inputName", "inputStream", + * "contentDisposition", "attachment;filename=\"${downloadFileName}\"","bufferSize", "512" }) }) + * + * @param annoInfo + * @return + */ + @SuppressWarnings("unchecked") + private Map encodeAnnoInfo(Map annoInfo) { + + String annoInfoJSON = JSONHelper.toString(annoInfo); + + annoInfoJSON = annoInfoJSON.replace("\\\"", "'"); + + return JSONHelper.toObject(annoInfoJSON, Map.class); + } + } + + // ----------------------------------------------annotation based component + // processor------------------------------------------------------------- + + /** + * ComponentAnnotationProcessor is the interface to process component class to get the info via annotations + * + * @author zhen zhang + * + */ + private static abstract class ComponentAnnotationProcessor extends ComponentProcessor { + + public final static String DEFAULT_VALUE = "_default_value"; + + @SuppressWarnings("rawtypes") + public abstract Map process(Class annoCls, Class comCls, ProfileContext context); + + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected void putAnnoValue(Class c, Class annoCls, String configName, Class configCls, + String keyName, Map info) { + + T value = (T) ReflectHelper.getAnnotationValue(c, annoCls, configName); + + if (null == value || DEFAULT_VALUE.equals(value)) { + return; + } + + } + } + /** * @WebSerice * @@ -1654,6 +1877,10 @@ public Map process(Class annoCls, Class c, ProfileContext con }; + private static final String[] componentInterfaceNames = new String[] { + // struts2 + "com.opensymphony.xwork2.Action" }; + /** * we should exclude the methods from Object */ @@ -1662,9 +1889,11 @@ public Map process(Class annoCls, Class c, ProfileContext con private static final Map annoProcessors = new HashMap(); + private static final Map interfaceProcessors = new HashMap(); + private static final Map> xpathProcessors = new LinkedHashMap>(); - private static final Map anno2xpath = new HashMap(); + private static final Map component2xpath = new HashMap(); private static final Map methodBlackListMap = new HashMap(); @@ -1675,11 +1904,13 @@ public Map process(Class annoCls, Class c, ProfileContext con /** * init annotation to descriptor's xpath */ - anno2xpath.put("javax.servlet.annotation.WebServlet", new String[] { "/web-app/servlet/servlet-class" }); - anno2xpath.put("javax.servlet.annotation.WebFilter", new String[] { "/web-app/filter/filter-class" }); - anno2xpath.put("javax.servlet.annotation.WebListener", new String[] { "/web-app/listener/listener-class" }); - anno2xpath.put("javax.jws.WebService", + component2xpath.put("javax.servlet.annotation.WebServlet", new String[] { "/web-app/servlet/servlet-class" }); + component2xpath.put("javax.servlet.annotation.WebFilter", new String[] { "/web-app/filter/filter-class" }); + component2xpath.put("javax.servlet.annotation.WebListener", + new String[] { "/web-app/listener/listener-class" }); + component2xpath.put("javax.jws.WebService", new String[] { "/beans/endpoint/@id", "/beans/server/@id", "/endpoints/endpoint/@implementation" }); + component2xpath.put("com.opensymphony.xwork2.Action", new String[] { "/struts/package/action" }); /** * init the mapping of anno class to their info processor @@ -1693,6 +1924,12 @@ public Map process(Class annoCls, Class c, ProfileContext con annoProcessors.put("org.springframework.stereotype.Controller", new SpringMVCInfoProcessor()); annoProcessors.put("org.springframework.web.bind.annotation.RestController", new SpringMVCInfoProcessor()); annoProcessors.put("org.springframework.context.annotation.ImportResource", new SpringResourceInfoProcessor()); + + /** + * init the mapping of interface class to their info processor + */ + interfaceProcessors.put("com.opensymphony.xwork2.Action", new Struts2ActionInfoProcessor()); + /** * init xpath processors */ @@ -1703,6 +1940,7 @@ public Map process(Class annoCls, Class c, ProfileContext con xpathProcessors.put("/beans/endpoint/@id", SpringXmlProcessor.class); xpathProcessors.put("/beans/server/@id", SpringXmlProcessor.class); xpathProcessors.put("/endpoints/endpoint/@implementation", SunJaxWSXmlProcessor.class); + xpathProcessors.put("/struts/package/action", Struts2XmlProcessor.class); /** * init methodBlackListMap @@ -1777,6 +2015,25 @@ public void doProfiling(ProfileElement elem, ProfileContext context) { } } + /** + * 2.1 load available interface classes + */ + Map> interfaceAvailableClasses = new HashMap>(); + + for (String interfaceClsName : componentInterfaceNames) { + try { + Class c = webappclsLoader.loadClass(interfaceClsName); + interfaceAvailableClasses.put(interfaceClsName, c); + } + catch (ClassNotFoundException e) { + // ignore + if (this.logger.isDebugable()) { + this.logger.warn("Interface Class [" + interfaceClsName + "] is not found in web application [" + + elem.getRepository().getProfile().getId() + "]", e); + } + } + } + /** * 3. see what kind of components we could get via annotations */ @@ -1802,7 +2059,7 @@ public void doProfiling(ProfileElement elem, ProfileContext context) { else { scanPackage[0] = ""; } - + FastClasspathScanner fcs = new FastClasspathScanner(classLoaders, scanPackage); fcs.scan(); // store FastClasspathScanner instance into ProfileContext @@ -1826,6 +2083,27 @@ public void doProfiling(ProfileElement elem, ProfileContext context) { // load componentsByAnno first loadComponentsByAnno(context, webappclsLoader, fcs, annoAvailableClasses, componentClassName, inst); + } + + for (String componentClassName : componentInterfaceNames) { + + // set the instance id = simple name of the annotation class + ProfileElementInstance inst = elem.getInstance(componentClassName); + + // load componentsByInterface + loadComponentsByInterface(context, webappclsLoader, fcs, interfaceAvailableClasses, componentClassName, + inst); + } + + String[] allComponentNames = new String[componentClassNames.length + componentInterfaceNames.length]; + System.arraycopy(componentClassNames, 0, allComponentNames, 0, componentClassNames.length); + System.arraycopy(componentInterfaceNames, 0, allComponentNames, componentClassNames.length, + componentInterfaceNames.length); + + for (String componentClassName : allComponentNames) { + + ProfileElementInstance inst = elem.getInstance(componentClassName); + // try to load componentsByDescriptor loadComponentsByDescriptor(dpInstances, webAppRoot, context, componentClassName, inst); @@ -1839,6 +2117,7 @@ public void doProfiling(ProfileElement elem, ProfileContext context) { if (componentClassName.equalsIgnoreCase("javax.servlet.annotation.WebServlet")) { collectServletInfoForMonitor(inst); + } /** @@ -1916,9 +2195,209 @@ else if (componentClassName.equalsIgnoreCase("org.springframework.stereotype.Con "org.springframework.web.bind.annotation.RequestMapping", "value", "org.springframework.web.bind.annotation.RequestMapping", false); } + // Struts2 + else if (componentClassName.equalsIgnoreCase("com.opensymphony.xwork2.Action")) { + addStruts2URLMapBinding(smgr, inst, appid, className, classInfo); + } + } + } + + @SuppressWarnings("unchecked") + private Set getStruts2URLExtension(Map strutsAction) { + + Set extSet = new HashSet(); + + for (Map.Entry entry : strutsAction.entrySet()) { + + String key = entry.getKey(); + Object value = entry.getValue(); + + if ("com.opensymphony.xwork2.ActionSupport".equals(key)) { + continue; + } + + Map valueMap = (Map) value; + + List desList = (List) valueMap.get("des"); + + if (desList == null) { + continue; + } + + for (Object desObj : desList) { + Map aMap = (Map) desObj; + Object extObj = aMap.get("extension"); + if (extObj == null) { + continue; + } + + String[] extArr = ((String) extObj).split(","); + + List extList = Arrays.asList(extArr); + + extSet.addAll(extList); + + return extSet; + } + } + + if (extSet.size() <= 0) { + extSet.add("action"); + } + + return extSet; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void addStruts2URLMapBindingByAnno(ProfileServiceMapMgr smgr, String appid, String className, + Map classInfo, Set extension) { + + Map methodsMap = (Map) classInfo.get("methods"); + Map classAnnoMap = (Map) classInfo.get("anno"); + + // get namespaces + Set namespaces = new HashSet(); + + if (classAnnoMap != null && classAnnoMap.size() > 0) { + for (Map.Entry classAnno : classAnnoMap.entrySet()) { + + String annoKey = classAnno.getKey(); + Object annoValue = classAnno.getValue(); + + if ("org.apache.struts2.convention.annotation.Namespaces".equals(annoKey)) { + + List aList = (List) ((Map) annoValue).get("value"); + + for (Object obj : aList) { + namespaces.add((String) ((Map) obj).get("value")); + } + + } + + if ("org.apache.struts2.convention.annotation.Namespace".equals(annoKey)) { + namespaces.add((String) ((Map) annoValue).get("value")); + } + + } + } + else { + namespaces.add("/"); + } + + // add moitor urls + HashSet murls = (HashSet) UAVServer.instance().getServerInfo("monitor.urls"); + murls.addAll(namespaces); + + // get actions + Set actionNames = new HashSet(); + + if (methodsMap != null) { + for (Map.Entry methodEntry : methodsMap.entrySet()) { + + Map map = (Map) methodEntry.getValue(); + if (map.get("anno") == null) { + continue; + } + + Map methodAnnoMap = (Map) map.get("anno"); + for (Map.Entry methodAnno : methodAnnoMap.entrySet()) { + + String annoKey = methodAnno.getKey(); + Object annoValue = methodAnno.getValue(); + + // if have Actions annotation ignore Action annotation + if ("org.apache.struts2.convention.annotation.Actions".equals(annoKey)) { + + List aList = (List) ((Map) annoValue).get("value"); + + for (Object obj : aList) { + actionNames.add((String) ((Map) obj).get("value")); + } + + } + + if ("org.apache.struts2.convention.annotation.Action".equals(annoKey) + && !methodAnnoMap.containsKey("org.apache.struts2.convention.annotation.Actions")) { + actionNames.add((String) ((Map) annoValue).get("value")); + } + } + + Set urlPSet = new HashSet(); + Iterator nsIterator = namespaces.iterator(); + while (nsIterator.hasNext()) { + String ns = nsIterator.next(); + + if (!"/".equals(ns)) { + ns = ns + "/"; + } + + Iterator actionNamesIterator = actionNames.iterator(); + while (actionNamesIterator.hasNext()) { + String actionName = actionNamesIterator.next(); + + Iterator extIterator = extension.iterator(); + while (extIterator.hasNext()) { + String ext = extIterator.next(); + if (!"".equals(ext)) { + ext = "." + ext; + } + urlPSet.add(ns + actionName + ext); + } + } + } + + smgr.addServiceMapBinding(appid, className, methodEntry.getKey(), urlPSet, 0, false); + } + } + } + + @SuppressWarnings("unchecked") + private void addStruts2URLMapBindingByDes(ProfileServiceMapMgr smgr, String appid, String className, + Map classInfo, Set extension) { + + Map valueMap = classInfo; + + List desList = (List) (valueMap.get("des")); + if (desList == null || desList.size() <= 0) { + return; + } + + Iterator extIterator = extension.iterator(); + while (extIterator.hasNext()) { + String ext = extIterator.next(); + if (!"".equals(ext)) { + ext = "." + ext; + } + + for (Object desObj : desList) { + Map aMap = (Map) desObj; + + String ns = (String) aMap.get("namespace"); + + if (!"/".equals(ns)) { + ns = ns + "/"; + } + + Set urlPSet = new HashSet(); + urlPSet.add(ns + aMap.get("name") + ext); + smgr.addServiceMapBinding(appid, className, (String) aMap.get("method"), urlPSet, 0, false); + } } } + private void addStruts2URLMapBinding(ProfileServiceMapMgr smgr, ProfileElementInstance inst, String appid, + String className, Map classInfo) { + + if (className.equalsIgnoreCase("com.opensymphony.xwork2.ActionSupport")) { + return; + } + + Map strutsAction = inst.getValues(); + Set extSet = getStruts2URLExtension(strutsAction); + addStruts2URLMapBindingByAnno(smgr, appid, className, classInfo, extSet); + addStruts2URLMapBindingByDes(smgr, appid, className, classInfo, extSet); + } + /** * * @param smgr @@ -2399,7 +2878,7 @@ private String getServiceURI(String contextpath) { protected void loadComponentsByDescriptor(Map dpInstances, String webAppRoot, ProfileContext context, String componentClassName, ProfileElementInstance inst) { - String[] xpaths = anno2xpath.get(componentClassName); + String[] xpaths = component2xpath.get(componentClassName); if (null == xpaths) { return; @@ -2442,6 +2921,10 @@ protected void loadComponentsByDescriptor(Map dpIns if (SunJaxWSXmlProcessor.class.isAssignableFrom(dpClass)) { context.put(SunJaxWSXmlProcessor.class, (SunJaxWSXmlProcessor) dpInst); } + // put struts.xml processor into profile context + if (Struts2XmlProcessor.class.isAssignableFrom(dpClass)) { + context.put(Struts2XmlProcessor.class, (Struts2XmlProcessor) dpInst); + } } else { dpInst = dpInstances.get(dpClass.getName()); @@ -2502,20 +2985,15 @@ protected void loadComponentsByAnno(ProfileContext context, ClassLoader webappcl continue; } catch (NoClassDefFoundError e) { - // ignore - if (this.logger.isDebugable()) { - this.logger.warn("Component Class [" + com + "] is not found in web application [" - + inst.getProfileElement().getRepository().getProfile().getId() + "]", e); } - continue; - } + try { // get the info of the target component class Map info = cip.process(annoClass, comCls, context); @@ -2533,4 +3011,61 @@ protected void loadComponentsByAnno(ProfileContext context, ClassLoader webappcl } + protected void loadComponentsByInterface(ProfileContext context, ClassLoader webappclsLoader, + FastClasspathScanner fcs, Map> interfaceAvailableClasses, String componentClassName, + ProfileElementInstance inst) { + + if (!interfaceAvailableClasses.containsKey(componentClassName)) { + return; + } + + Class interfaceClass = interfaceAvailableClasses.get(componentClassName); + + // get all classes with the target annotations + List coms = fcs.getNamesOfClassesImplementing(interfaceClass); + + if (null == coms || coms.isEmpty()) { + + return; + } + + // get the ComponentInfoProcessor + ComponentInterfaceProcessor cip = interfaceProcessors.get(interfaceClass.getName()); + + // set the instance values, key=class found,value=info of the class + for (String com : coms) { + + Class comCls = null; + try { + comCls = webappclsLoader.loadClass(com); + } + catch (ClassNotFoundException e) { + // ignore + if (this.logger.isDebugable()) { + this.logger.warn("Component Class [" + com + "] is not found in web application [" + + inst.getProfileElement().getRepository().getProfile().getId() + "]", e); + } + continue; + } + catch (NoClassDefFoundError e) { + // ignore + if (this.logger.isDebugable()) { + this.logger.warn("Component Class [" + com + "] is not found in web application [" + + inst.getProfileElement().getRepository().getProfile().getId() + "]", e); + + } + continue; + } + + try { + // get the info of the target component class + Map info = cip.process(comCls, context); + inst.setValue(com, info); + } + catch (RuntimeException e) { + // ignore + } + } + } + } From e8bdf2bb5ea1987e672cd5eb2d09b4b50d1c61b5 Mon Sep 17 00:00:00 2001 From: longxiao2 Date: Tue, 10 Oct 2017 19:13:29 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=E4=BF=AE=E6=94=B9code=20style?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../handlers/ProfileDataMessageHandler.java | 2053 +++++++++-------- .../handlers/ComponentProfileHandler.java | 31 +- 2 files changed, 1056 insertions(+), 1028 deletions(-) diff --git a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/healthmanager/messaging/handlers/ProfileDataMessageHandler.java b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/healthmanager/messaging/handlers/ProfileDataMessageHandler.java index c8201112..60eb28be 100644 --- a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/healthmanager/messaging/handlers/ProfileDataMessageHandler.java +++ b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/healthmanager/messaging/handlers/ProfileDataMessageHandler.java @@ -43,1311 +43,1330 @@ public class ProfileDataMessageHandler extends AbstractMessageHandler { - @Override - public void handle(Message msg) { + @Override + public void handle(Message msg) { - // push the latest profile data to cache - List newMDFs = pushLatestProfileDataToCacheCenter(msg.getParam(getMsgTypeName())); + // push the latest profile data to cache + List newMDFs = pushLatestProfileDataToCacheCenter(msg.getParam(getMsgTypeName())); - if (newMDFs.size() > 0) { - // set the new MDFs into msg - msg.setParam(getMsgTypeName(), JSONHelper.toString(newMDFs)); - // store profile data - super.handle(msg); - } - } + if (newMDFs.size() > 0) { + // set the new MDFs into msg + msg.setParam(getMsgTypeName(), JSONHelper.toString(newMDFs)); + // store profile data + super.handle(msg); + } + } - @Override - public String getMsgTypeName() { - - return MonitorDataFrame.MessageType.Profile.toString(); - } - - @Override - protected void preInsert(DataStoreMsg dsMsg) { - - // set target collection - dsMsg.put(DataStoreProtocol.MONGO_COLLECTION_NAME, HealthManagerConstants.MONGO_COLLECTION_PROFILE); - } - - /** - * 推送最新的ProfileData到缓存中心 - * - * @param profileString - */ - @SuppressWarnings({ "rawtypes" }) - private List pushLatestProfileDataToCacheCenter(String profileString) { - - CacheManager cm = (CacheManager) ConfigurationManager.getInstance().getComponent("healthmanager", - "HMCacheManager"); - - cm.beginBatch(); - - List monitorDataFrames = JSONHelper.toObjectArray(profileString, String.class); - - List newMDFs = new ArrayList(); - - for (String mdfStr : monitorDataFrames) { - MonitorDataFrame mdf = new MonitorDataFrame(mdfStr); - - String tag = mdf.getTag(); - - /** - * note: only tag==P means this MDF is the new MDF, otherwise this - * MDF is just for heartbeat - */ - if (tag.equalsIgnoreCase("P")) { - newMDFs.add(mdfStr); - } - - /** - * Step 1: build all profile node info - */ - Map> frames = mdf.getDatas(); - for (String appid : frames.keySet()) { - - Map appProfile = new LinkedHashMap(); - - /** - * 1.1 basic info of the application - */ - Map values = mdf.getElemInstValues(appid, "cpt", "webapp"); - - String appurl = (String) values.get("appurl"); - - /** - * appgroup - */ - String appgroup = ""; - - if (values.containsKey("appgroup")) { - appgroup = (String) values.get("appgroup"); - } - - /** - * appdes from web.xml's description {org:"owner info"} - */ - String appdes = ""; - - if (values.containsKey("appdes")) { - appdes = (String) values.get("appdes"); - } - - /** - * appmetrics - */ - String appmetrics = ""; - - if (values.containsKey("appmetrics")) { - appmetrics = JSONHelper.toString(values.get("appmetrics")); - } - - /** - * appName - */ - String appName = (String) values.get("appname"); - - /** - * app root - */ - String appRoot = (String) values.get("webapproot"); - - /** - * MOF metadata - */ - String mofMeta = ""; - - if (values.containsKey("mofmeta")) { - mofMeta = JSONHelper.toString(values.get("mofmeta")); - } - - appProfile.put("appid", appid); - appProfile.put("ip", mdf.getIP()); - appProfile.put("svrid", mdf.getServerId()); - appProfile.put("host", mdf.getHost()); - appProfile.put("time", mdf.getTimeFlag()); - appProfile.put("appname", appName); - appProfile.put("appdes", appdes); - appProfile.put("appmetrics", appmetrics); - appProfile.put("appgroup", appgroup); - appProfile.put("webapproot", appRoot); - appProfile.put("appurl", appurl); - appProfile.put("mofmeta", mofMeta); - - /** - * step 1.2: cache the application clients profile data - */ - String clientsJSONstr = cacheAppClientProfileData(cm, mdf, appid, appurl, appgroup); - - /** - * Step 1.3 cache the application profile data - */ - cacheAppProfileData(cm, mdf, appProfile, clientsJSONstr, appid, appurl, appgroup); - - /** - * step 1.4: cache application ip_link & access data - */ - cacheAppIPLinkProfileData(cm, mdf, appid, appurl, appgroup); - } - } - - cm.submitBatch(); - - return newMDFs; - } - - /** - * cacheAppIPLinkProfileData - * - * @param cm - * @param mdf - * @param appid - * @param appurl - * @param appgroup - */ - @SuppressWarnings("rawtypes") - private void cacheAppIPLinkProfileData(CacheManager cm, MonitorDataFrame mdf, String appid, String appurl, - String appgroup) { - - List iplinks = mdf.getElemInstances(appid, "iplnk"); - - Map appIpLnkMap = new HashMap(); - - for (Map iplink : iplinks) { - String iplnk_id = (String) iplink.get("id"); - @SuppressWarnings("unchecked") - Map iplnk_values = (Map) iplink.get("values"); - appIpLnkMap.put(iplnk_id, JSONHelper.toString(iplnk_values)); - appIpLnkMap.put(iplnk_id + "-ts", String.valueOf(iplnk_values.get("ts"))); - } - - String iplnkfieldKey = "LNK@" + appgroup + "@" + appurl; - - cm.putHash(HealthManagerConstants.STORE_REGION_UAV, iplnkfieldKey, appIpLnkMap); - } - - /** - * cacheAppClientProfileData - * - * @param cm - * @param mdf - * @param appid - * @param appurl - * @param appgroup - */ - @SuppressWarnings("rawtypes") - private String cacheAppClientProfileData(CacheManager cm, MonitorDataFrame mdf, String appid, String appurl, - String appgroup) { - - List clients = mdf.getElemInstances(appid, "clients"); - - long checkTime = System.currentTimeMillis(); - - long expireTime = 60000; - - for (int i = 0; i < clients.size(); i++) { - - Map client = clients.get(i); - - @SuppressWarnings("unchecked") - Map cVals = (Map) client.get("values"); - - Long client_ts = (Long) cVals.get("ts"); - - if (client_ts == null) { - continue; - } - - long client_timeout = checkTime - client_ts; - - if (client_timeout < expireTime) { - cVals.put("state", "1"); - } else if (client_timeout >= expireTime && client_timeout < expireTime * 2) { - cVals.put("state", "0"); - } else if (client_timeout >= expireTime * 2) { - cVals.put("state", "-1"); - } - } - - String fieldKey = "C@" + appgroup + "@" + appurl; - - String clientsStr = JSONHelper.toString(clients); - - cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO_APPCLIENT, - fieldKey, clientsStr); - - return clientsStr; - } - - /** - * cache the application profile data - * - * @param cm - * @param mdf - * @param appid - */ - private void cacheAppProfileData(CacheManager cm, MonitorDataFrame mdf, Map pi, - String clientsJSONstr, String appid, String appurl, String appgroup) { + @Override + public String getMsgTypeName() { - /** - * client - */ - pi.put("cpt.clients", clientsJSONstr); + return MonitorDataFrame.MessageType.Profile.toString(); + } + + @Override + protected void preInsert(DataStoreMsg dsMsg) { + + // set target collection + dsMsg.put(DataStoreProtocol.MONGO_COLLECTION_NAME, HealthManagerConstants.MONGO_COLLECTION_PROFILE); + } + + /** + * 推送最新的ProfileData到缓存中心 + * + * @param profileString + */ + @SuppressWarnings({ "rawtypes" }) + private List pushLatestProfileDataToCacheCenter(String profileString) { + + CacheManager cm = (CacheManager) ConfigurationManager.getInstance().getComponent("healthmanager", + "HMCacheManager"); + + cm.beginBatch(); + + List monitorDataFrames = JSONHelper.toObjectArray(profileString, String.class); + + List newMDFs = new ArrayList(); + + for (String mdfStr : monitorDataFrames) { + MonitorDataFrame mdf = new MonitorDataFrame(mdfStr); + + String tag = mdf.getTag(); + + /** + * note: only tag==P means this MDF is the new MDF, otherwise this MDF is just for heartbeat + */ + if (tag.equalsIgnoreCase("P")) { + newMDFs.add(mdfStr); + } + + /** + * Step 1: build all profile node info + */ + Map> frames = mdf.getDatas(); + for (String appid : frames.keySet()) { + + Map appProfile = new LinkedHashMap(); + + /** + * 1.1 basic info of the application + */ + Map values = mdf.getElemInstValues(appid, "cpt", "webapp"); + + String appurl = (String) values.get("appurl"); + + /** + * appgroup + */ + String appgroup = ""; + + if (values.containsKey("appgroup")) { + appgroup = (String) values.get("appgroup"); + } + + /** + * appdes from web.xml's description {org:"owner info"} + */ + String appdes = ""; + + if (values.containsKey("appdes")) { + appdes = (String) values.get("appdes"); + } + + /** + * appmetrics + */ + String appmetrics = ""; + + if (values.containsKey("appmetrics")) { + appmetrics = JSONHelper.toString(values.get("appmetrics")); + } + + /** + * appName + */ + String appName = (String) values.get("appname"); + + /** + * app root + */ + String appRoot = (String) values.get("webapproot"); + + /** + * MOF metadata + */ + String mofMeta = ""; + + if (values.containsKey("mofmeta")) { + mofMeta = JSONHelper.toString(values.get("mofmeta")); + } + + appProfile.put("appid", appid); + appProfile.put("ip", mdf.getIP()); + appProfile.put("svrid", mdf.getServerId()); + appProfile.put("host", mdf.getHost()); + appProfile.put("time", mdf.getTimeFlag()); + appProfile.put("appname", appName); + appProfile.put("appdes", appdes); + appProfile.put("appmetrics", appmetrics); + appProfile.put("appgroup", appgroup); + appProfile.put("webapproot", appRoot); + appProfile.put("appurl", appurl); + appProfile.put("mofmeta", mofMeta); + + /** + * step 1.2: cache the application clients profile data + */ + String clientsJSONstr = cacheAppClientProfileData(cm, mdf, appid, appurl, appgroup); + + /** + * Step 1.3 cache the application profile data + */ + cacheAppProfileData(cm, mdf, appProfile, clientsJSONstr, appid, appurl, appgroup); + + /** + * step 1.4: cache application ip_link & access data + */ + cacheAppIPLinkProfileData(cm, mdf, appid, appurl, appgroup); + } + } + + cm.submitBatch(); + + return newMDFs; + } + + /** + * cacheAppIPLinkProfileData + * + * @param cm + * @param mdf + * @param appid + * @param appurl + * @param appgroup + */ + @SuppressWarnings("rawtypes") + private void cacheAppIPLinkProfileData(CacheManager cm, MonitorDataFrame mdf, String appid, String appurl, + String appgroup) { + + List iplinks = mdf.getElemInstances(appid, "iplnk"); + + Map appIpLnkMap = new HashMap(); + + for (Map iplink : iplinks) { + String iplnk_id = (String) iplink.get("id"); + @SuppressWarnings("unchecked") + Map iplnk_values = (Map) iplink.get("values"); + appIpLnkMap.put(iplnk_id, JSONHelper.toString(iplnk_values)); + appIpLnkMap.put(iplnk_id + "-ts", String.valueOf(iplnk_values.get("ts"))); + } + + String iplnkfieldKey = "LNK@" + appgroup + "@" + appurl; + + cm.putHash(HealthManagerConstants.STORE_REGION_UAV, iplnkfieldKey, appIpLnkMap); + } + + /** + * cacheAppClientProfileData + * + * @param cm + * @param mdf + * @param appid + * @param appurl + * @param appgroup + */ + @SuppressWarnings("rawtypes") + private String cacheAppClientProfileData(CacheManager cm, MonitorDataFrame mdf, String appid, String appurl, + String appgroup) { + + List clients = mdf.getElemInstances(appid, "clients"); + + long checkTime = System.currentTimeMillis(); + + long expireTime = 60000; + + for (int i = 0; i < clients.size(); i++) { + + Map client = clients.get(i); + + @SuppressWarnings("unchecked") + Map cVals = (Map) client.get("values"); + + Long client_ts = (Long) cVals.get("ts"); + + if (client_ts == null) { + continue; + } + + long client_timeout = checkTime - client_ts; + + if (client_timeout < expireTime) { + cVals.put("state", "1"); + } + else if (client_timeout >= expireTime && client_timeout < expireTime * 2) { + cVals.put("state", "0"); + } + else if (client_timeout >= expireTime * 2) { + cVals.put("state", "-1"); + } + } + + String fieldKey = "C@" + appgroup + "@" + appurl; + + String clientsStr = JSONHelper.toString(clients); + + cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO_APPCLIENT, + fieldKey, clientsStr); + + return clientsStr; + } + + /** + * cache the application profile data + * + * @param cm + * @param mdf + * @param appid + */ + private void cacheAppProfileData(CacheManager cm, MonitorDataFrame mdf, Map pi, + String clientsJSONstr, String appid, String appurl, String appgroup) { - /** - * lib - */ - Map libs = mdf.getElemInstValues(appid, "jars", "lib"); + /** + * client + */ + pi.put("cpt.clients", clientsJSONstr); - pi.put("jars.lib", "@LAZY"); + /** + * lib + */ + Map libs = mdf.getElemInstValues(appid, "jars", "lib"); - /** - * NOTE:独立存储,延迟加载 - */ - String jarLib = JSONHelper.toString(libs); + pi.put("jars.lib", "@LAZY"); - /** - * logs - */ - Map logs = mdf.getElemInstValues(appid, "logs", "log4j"); + /** + * NOTE:独立存储,延迟加载 + */ + String jarLib = JSONHelper.toString(libs); - pi.put("logs.log4j", JSONHelper.toString(logs)); + /** + * logs + */ + Map logs = mdf.getElemInstValues(appid, "logs", "log4j"); - /** - * components - */ - Map> compServices = new LinkedHashMap>(); + pi.put("logs.log4j", JSONHelper.toString(logs)); - // JEE Service Components - buildJEEServiceComponents(mdf, pi, appid, appurl, compServices); + /** + * components + */ + Map> compServices = new LinkedHashMap>(); - // MSCP Service Components - buildMSCPServiceComponents(mdf, pi, appid, compServices); + // JEE Service Components + buildJEEServiceComponents(mdf, pi, appid, appurl, compServices); - // Dubbo Components - buildDubboServiceComponents(mdf, pi, appid, compServices); + // MSCP Service Components + buildMSCPServiceComponents(mdf, pi, appid, compServices); - pi.put("cpt.services", JSONHelper.toString(compServices)); + // Dubbo Components + buildDubboServiceComponents(mdf, pi, appid, compServices); - pi.put("state", "1"); + pi.put("cpt.services", JSONHelper.toString(compServices)); - /** - * use appgroup + appurl as the cache key, then we can get profile data - * by appgroup - */ - String fieldKey = appgroup + "@" + appurl; + pi.put("state", "1"); - cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO, fieldKey, - JSONHelper.toString(pi)); + /** + * use appgroup + appurl as the cache key, then we can get profile data by appgroup + */ + String fieldKey = appgroup + "@" + appurl; - /** - * NOTE: 独立存储类库,这样可以减少profile的数据量,提升加载速度,需要读取类库时再读取 - */ - cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO_JARLIB, - fieldKey, jarLib); - } + cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO, fieldKey, + JSONHelper.toString(pi)); - /** - * buildDubboServiceComponents - * - * @param mdf - * @param pi - * @param appid - * @param compServices - */ - @SuppressWarnings("unchecked") - private void buildDubboServiceComponents(MonitorDataFrame mdf, Map pi, String appid, - Map> compServices) { + /** + * NOTE: 独立存储类库,这样可以减少profile的数据量,提升加载速度,需要读取类库时再读取 + */ + cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO_JARLIB, + fieldKey, jarLib); + } - Map comps = mdf.getElemInstValues(appid, "cpt", "com.alibaba.dubbo.config.spring.ServiceBean"); + /** + * buildDubboServiceComponents + * + * @param mdf + * @param pi + * @param appid + * @param compServices + */ + @SuppressWarnings("unchecked") + private void buildDubboServiceComponents(MonitorDataFrame mdf, Map pi, String appid, + Map> compServices) { - // 获取dubbo provider的ip - String ip = mdf.getIP(); - if (comps == null || comps.size() == 0) { - return; - } + Map comps = mdf.getElemInstValues(appid, "cpt", "com.alibaba.dubbo.config.spring.ServiceBean"); - pi.put("cpt.dubbo.provider", JSONHelper.toString(comps)); + // 获取dubbo provider的ip + String ip = mdf.getIP(); + if (comps == null || comps.size() == 0) { + return; + } - for (String compName : comps.keySet()) { + pi.put("cpt.dubbo.provider", JSONHelper.toString(comps)); - Map info = (Map) comps.get(compName); + for (String compName : comps.keySet()) { - Set compServicesURLs = compServices.get(compName); + Map info = (Map) comps.get(compName); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compName, compServicesURLs); - } + Set compServicesURLs = compServices.get(compName); - String group = (String) info.get("group"); - String version = (String) info.get("version"); - String servcls = (String) info.get("servcls"); + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compName, compServicesURLs); + } - Map compMethodInfo = (Map) info.get("methods"); + String group = (String) info.get("group"); + String version = (String) info.get("version"); + String servcls = (String) info.get("servcls"); - if (compMethodInfo == null || compMethodInfo.size() == 0) { - continue; - } + Map compMethodInfo = (Map) info.get("methods"); - Map protocols = (Map) info.get("protocols"); + if (compMethodInfo == null || compMethodInfo.size() == 0) { + continue; + } - if (protocols == null || protocols.size() == 0) { - continue; - } + Map protocols = (Map) info.get("protocols"); - for (String method : compMethodInfo.keySet()) { + if (protocols == null || protocols.size() == 0) { + continue; + } - for (String protocol : protocols.keySet()) { + for (String method : compMethodInfo.keySet()) { - Map pAttrs = (Map) protocols.get(protocol); + for (String protocol : protocols.keySet()) { - Integer port = (Integer) pAttrs.get("port"); - String path = (String) pAttrs.get("path"); + Map pAttrs = (Map) protocols.get(protocol); - path = (StringHelper.isEmpty(path)) ? servcls : path; + Integer port = (Integer) pAttrs.get("port"); + String path = (String) pAttrs.get("path"); - String url = getDubboURL(ip, group, version, method, port, protocol, path); + path = (StringHelper.isEmpty(path)) ? servcls : path; - compServicesURLs.add(url); - } - } - } - } + String url = getDubboURL(ip, group, version, method, port, protocol, path); - private String getDubboURL(String ip, String group, String version, String method, Integer localPort, - String protocol, String path) { + compServicesURLs.add(url); + } + } + } + } - StringBuilder requestURL = new StringBuilder(); + private String getDubboURL(String ip, String group, String version, String method, Integer localPort, + String protocol, String path) { - requestURL.append(protocol).append("://").append(ip).append(":").append(localPort); + StringBuilder requestURL = new StringBuilder(); - if (group != null) { - requestURL.append(":").append(group); - } + requestURL.append(protocol).append("://").append(ip).append(":").append(localPort); - requestURL.append("/").append(path); + if (group != null) { + requestURL.append(":").append(group); + } - if (version != null) { - requestURL.append(".").append(version); - } + requestURL.append("/").append(path); - requestURL.append("/").append(method); + if (version != null) { + requestURL.append(".").append(version); + } - return requestURL.toString(); - } + requestURL.append("/").append(method); - /** - * buildMSCPServiceComponents - * - * @param mdf - * @param pi - * @param appid - * @param compServices - */ - @SuppressWarnings("unchecked") - private void buildMSCPServiceComponents(MonitorDataFrame mdf, Map pi, String appid, - Map> compServices) { + return requestURL.toString(); + } - // http comp - Map mscpHttp = mdf.getElemInstValues(appid, "cpt", - "com.creditease.agent.spi.AbstractBaseHttpServComponent"); + /** + * buildMSCPServiceComponents + * + * @param mdf + * @param pi + * @param appid + * @param compServices + */ + @SuppressWarnings("unchecked") + private void buildMSCPServiceComponents(MonitorDataFrame mdf, Map pi, String appid, + Map> compServices) { - if (mscpHttp != null && mscpHttp.size() > 0) { + // http comp + Map mscpHttp = mdf.getElemInstValues(appid, "cpt", + "com.creditease.agent.spi.AbstractBaseHttpServComponent"); - pi.put("cpt.mscp.http", JSONHelper.toString(mscpHttp)); + if (mscpHttp != null && mscpHttp.size() > 0) { - for (String mscpCompName : mscpHttp.keySet()) { - Map info = (Map) mscpHttp.get(mscpCompName); + pi.put("cpt.mscp.http", JSONHelper.toString(mscpHttp)); - Set compServicesURLs = compServices.get(mscpCompName); + for (String mscpCompName : mscpHttp.keySet()) { + Map info = (Map) mscpHttp.get(mscpCompName); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(mscpCompName, compServicesURLs); - } + Set compServicesURLs = compServices.get(mscpCompName); - String httpRootPath = (String) info.get("path"); + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(mscpCompName, compServicesURLs); + } - Map handlers = (Map) info.get("handlers"); + String httpRootPath = (String) info.get("path"); - for (String handlerName : handlers.keySet()) { + Map handlers = (Map) info.get("handlers"); - Map handlerInfo = (Map) handlers.get(handlerName); + for (String handlerName : handlers.keySet()) { - String handlerPath = (String) handlerInfo.get("path"); + Map handlerInfo = (Map) handlers.get(handlerName); - String serviceURL = httpRootPath + handlerPath; + String handlerPath = (String) handlerInfo.get("path"); - compServicesURLs.add(serviceURL); - } - } - } + String serviceURL = httpRootPath + handlerPath; - // timer work - Map mscpTimeWork = mdf.getElemInstValues(appid, "cpt", - "com.creditease.agent.spi.AbstractTimerWork"); + compServicesURLs.add(serviceURL); + } + } + } - if (mscpTimeWork != null && mscpTimeWork.size() > 0) { - pi.put("cpt.mscp.timework", JSONHelper.toString(mscpTimeWork)); - } - } + // timer work + Map mscpTimeWork = mdf.getElemInstValues(appid, "cpt", + "com.creditease.agent.spi.AbstractTimerWork"); - /** - * buildJEEServiceComponents - * - * @param mdf - * @param pi - * @param appid - * @param appurl - * @param compServices - */ - private void buildJEEServiceComponents(MonitorDataFrame mdf, Map pi, String appid, String appurl, - Map> compServices) { + if (mscpTimeWork != null && mscpTimeWork.size() > 0) { + pi.put("cpt.mscp.timework", JSONHelper.toString(mscpTimeWork)); + } + } - Map filters = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebFilter"); + /** + * buildJEEServiceComponents + * + * @param mdf + * @param pi + * @param appid + * @param appurl + * @param compServices + */ + private void buildJEEServiceComponents(MonitorDataFrame mdf, Map pi, String appid, String appurl, + Map> compServices) { - Map listeners = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebListener"); + Map filters = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebFilter"); - pi.put("cpt.filters", JSONHelper.toString(filters)); + Map listeners = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebListener"); - pi.put("cpt.listeners", JSONHelper.toString(listeners)); + pi.put("cpt.filters", JSONHelper.toString(filters)); - Map servlets = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebServlet"); + pi.put("cpt.listeners", JSONHelper.toString(listeners)); - // all servlet based tech - if (servlets == null || servlets.size() == 0) { - return; - } + Map servlets = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebServlet"); - // get servlets URLs - Map serviceServlets = getServletsURLs(appurl, compServices, servlets); + // all servlet based tech + if (servlets == null || servlets.size() == 0) { + return; + } - Map jaxws = mdf.getElemInstValues(appid, "cpt", "javax.jws.WebService"); + // get servlets URLs + Map serviceServlets = getServletsURLs(appurl, compServices, servlets); - String jaxwsBaseURL = serviceServlets.get("jaxws"); + Map jaxws = mdf.getElemInstValues(appid, "cpt", "javax.jws.WebService"); - // get jaxws URLs - getJAXWSURLs(compServices, jaxws, serviceServlets, appurl); + String jaxwsBaseURL = serviceServlets.get("jaxws"); - Map jaxwsProviders = mdf.getElemInstValues(appid, "cpt", "javax.xml.ws.WebServiceProvider"); + // get jaxws URLs + getJAXWSURLs(compServices, jaxws, serviceServlets, appurl); - // get jaxws provider urls - getJAXWSProviderURLs(jaxwsBaseURL, compServices, jaxwsProviders); + Map jaxwsProviders = mdf.getElemInstValues(appid, "cpt", "javax.xml.ws.WebServiceProvider"); - Map jaxrs = mdf.getElemInstValues(appid, "cpt", "javax.ws.rs.Path"); + // get jaxws provider urls + getJAXWSProviderURLs(jaxwsBaseURL, compServices, jaxwsProviders); - // get jaxrs urls - String jaxrsBaseURL = serviceServlets.get("jaxrs"); + Map jaxrs = mdf.getElemInstValues(appid, "cpt", "javax.ws.rs.Path"); - getJAXRSURLs(jaxrsBaseURL, compServices, jaxrs); + // get jaxrs urls + String jaxrsBaseURL = serviceServlets.get("jaxrs"); - Map springMVC = mdf.getElemInstValues(appid, "cpt", - "org.springframework.stereotype.Controller"); + getJAXRSURLs(jaxrsBaseURL, compServices, jaxrs); - Map springMVCRest = mdf.getElemInstValues(appid, "cpt", - "org.springframework.web.bind.annotation.RestController"); + Map springMVC = mdf.getElemInstValues(appid, "cpt", + "org.springframework.stereotype.Controller"); - // get spring mvc urls - String springmvcBaseURL = serviceServlets.get("springmvc"); + Map springMVCRest = mdf.getElemInstValues(appid, "cpt", + "org.springframework.web.bind.annotation.RestController"); - getSpringMVCURLs(springmvcBaseURL, compServices, springMVC); + // get spring mvc urls + String springmvcBaseURL = serviceServlets.get("springmvc"); - getSpringMVCURLs(springmvcBaseURL, compServices, springMVCRest); + getSpringMVCURLs(springmvcBaseURL, compServices, springMVC); - // get struts2 urls - Map strutsAction = mdf.getElemInstValues(appid, "cpt", "com.opensymphony.xwork2.Action"); - getStruts2URLs(appurl, compServices, strutsAction); + getSpringMVCURLs(springmvcBaseURL, compServices, springMVCRest); - pi.put("cpt.servlets", JSONHelper.toString(servlets)); - pi.put("cpt.jaxws", JSONHelper.toString(jaxws)); - pi.put("cpt.jaxwsP", JSONHelper.toString(jaxwsProviders)); - pi.put("cpt.jaxrs", JSONHelper.toString(jaxrs)); - pi.put("cpt.springmvc", JSONHelper.toString(springMVC)); - pi.put("cpt.springmvcRest", JSONHelper.toString(springMVCRest)); - pi.put("cpt.struts2", JSONHelper.toString(strutsAction)); - } + // get struts2 urls + Map strutsAction = mdf.getElemInstValues(appid, "cpt", "com.opensymphony.xwork2.Action"); + getStruts2URLs(appurl, compServices, strutsAction); - @SuppressWarnings({ "unchecked", "rawtypes" }) - private void getStruts2URLsByAnno(String appurl, Map> compServices, - Map strutsAction, String key, Set extSet) { + pi.put("cpt.servlets", JSONHelper.toString(servlets)); + pi.put("cpt.jaxws", JSONHelper.toString(jaxws)); + pi.put("cpt.jaxwsP", JSONHelper.toString(jaxwsProviders)); + pi.put("cpt.jaxrs", JSONHelper.toString(jaxrs)); + pi.put("cpt.springmvc", JSONHelper.toString(springMVC)); + pi.put("cpt.springmvcRest", JSONHelper.toString(springMVCRest)); + pi.put("cpt.struts2", JSONHelper.toString(strutsAction)); + } - Set compServicesURLs = compServices.get(key); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(key, compServicesURLs); - } + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void getStruts2URLsByAnno(String appurl, Map> compServices, + Map strutsAction, String key, Set extSet) { - Map valueMap = (Map) strutsAction.get(key); + Set compServicesURLs = compServices.get(key); + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(key, compServicesURLs); + } - Map methodsMap = (Map) valueMap.get("methods"); - Map classAnnoMap = (Map) valueMap.get("anno"); + Map valueMap = (Map) strutsAction.get(key); - // get namespaces - Set namespaces = new HashSet(); + Map methodsMap = (Map) valueMap.get("methods"); + Map classAnnoMap = (Map) valueMap.get("anno"); - if (classAnnoMap != null && classAnnoMap.size() > 0) { - for (Map.Entry classAnno : classAnnoMap.entrySet()) { + // get namespaces + Set namespaces = new HashSet(); - String annoKey = classAnno.getKey(); - Object annoValue = classAnno.getValue(); + if (classAnnoMap != null && classAnnoMap.size() > 0) { + for (Map.Entry classAnno : classAnnoMap.entrySet()) { - if ("org.apache.struts2.convention.annotation.Namespace".equals(annoKey)) { - namespaces.add((String) ((Map) annoValue).get("value")); - } + String annoKey = classAnno.getKey(); + Object annoValue = classAnno.getValue(); - if ("org.apache.struts2.convention.annotation.Namespaces".equals(annoKey)) { + if ("org.apache.struts2.convention.annotation.Namespace".equals(annoKey)) { + namespaces.add((String) ((Map) annoValue).get("value")); + } - List aList = (List) ((Map) annoValue).get("value"); + if ("org.apache.struts2.convention.annotation.Namespaces".equals(annoKey)) { - for (Object obj : aList) { - namespaces.add((String) ((Map) obj).get("value")); - } - } + List aList = (List) ((Map) annoValue).get("value"); - } - } else { - namespaces.add("/"); - } + for (Object obj : aList) { + namespaces.add((String) ((Map) obj).get("value")); + } + } - // get actions - Set actionNames = new HashSet(); - if (methodsMap != null) { - for (Map.Entry method : methodsMap.entrySet()) { + } + } + else { + namespaces.add("/"); + } - Map map = (Map) method.getValue(); - if (map.get("anno") == null) { - continue; - } + // get actions + Set actionNames = new HashSet(); + if (methodsMap != null) { + for (Map.Entry method : methodsMap.entrySet()) { - Map methodAnnoMap = (Map) map.get("anno"); + Map map = (Map) method.getValue(); + if (map.get("anno") == null) { + continue; + } - for (Map.Entry methodAnno : methodAnnoMap.entrySet()) { + Map methodAnnoMap = (Map) map.get("anno"); - String annoKey = methodAnno.getKey(); - Object annoValue = methodAnno.getValue(); + for (Map.Entry methodAnno : methodAnnoMap.entrySet()) { - // if have Actions annotation ignore Action annotation - if ("org.apache.struts2.convention.annotation.Actions".equals(annoKey)) { + String annoKey = methodAnno.getKey(); + Object annoValue = methodAnno.getValue(); - List aList = (List) ((Map) annoValue).get("value"); + // if have Actions annotation ignore Action annotation + if ("org.apache.struts2.convention.annotation.Actions".equals(annoKey)) { - for (Object obj : aList) { - actionNames.add((String) ((Map) obj).get("value")); - } + List aList = (List) ((Map) annoValue).get("value"); - continue; - } + for (Object obj : aList) { + actionNames.add((String) ((Map) obj).get("value")); + } - if ("org.apache.struts2.convention.annotation.Action".equals(annoKey) - && !methodAnnoMap.containsKey("org.apache.struts2.convention.annotation.Actions")) { - actionNames.add((String) ((Map) annoValue).get("value")); - } - } - } - } + continue; + } - Iterator nsIterator = namespaces.iterator(); - while (nsIterator.hasNext()) { - String ns = nsIterator.next(); + if ("org.apache.struts2.convention.annotation.Action".equals(annoKey) + && !methodAnnoMap.containsKey("org.apache.struts2.convention.annotation.Actions")) { + actionNames.add((String) ((Map) annoValue).get("value")); + } + } + } + } - if (!"/".equals(ns)) { - ns = ns + "/"; - } + Iterator nsIterator = namespaces.iterator(); + while (nsIterator.hasNext()) { + String ns = nsIterator.next(); - Iterator actionNamesIterator = actionNames.iterator(); - while (actionNamesIterator.hasNext()) { - String actionName = actionNamesIterator.next(); + if (!"/".equals(ns)) { + ns = ns + "/"; + } - Iterator extIterator = extSet.iterator(); - while (extIterator.hasNext()) { - String ext = extIterator.next(); - if (!"".equals(ext)) { - ext = "." + ext; - } - compServicesURLs.add(appurl.substring(0, appurl.length() - 1) + ns + actionName + ext); - } + Iterator actionNamesIterator = actionNames.iterator(); + while (actionNamesIterator.hasNext()) { + String actionName = actionNamesIterator.next(); - } - } - } + Iterator extIterator = extSet.iterator(); + while (extIterator.hasNext()) { + String ext = extIterator.next(); + if (!"".equals(ext)) { + ext = "." + ext; + } + compServicesURLs.add(appurl.substring(0, appurl.length() - 1) + ns + actionName + ext); + } - @SuppressWarnings("unchecked") - private void getStruts2URLsByDes(String appurl, Map> compServices, - Map strutsAction, String key, Set extSet) { + } + } + } - Set compServicesURLs = compServices.get(key); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(key, compServicesURLs); - } + @SuppressWarnings("unchecked") + private void getStruts2URLsByDes(String appurl, Map> compServices, + Map strutsAction, String key, Set extSet) { - Map valueMap = (Map) strutsAction.get(key); + Set compServicesURLs = compServices.get(key); + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(key, compServicesURLs); + } - // get action urls by des - List desList = (List) (valueMap.get("des")); - if (desList == null || desList.size() <= 0) { - return; - } + Map valueMap = (Map) strutsAction.get(key); - Iterator extIterator = extSet.iterator(); - while (extIterator.hasNext()) { - String ext = extIterator.next(); - if (!"".equals(ext)) { - ext = "." + ext; - } + // get action urls by des + List desList = (List) (valueMap.get("des")); + if (desList == null || desList.size() <= 0) { + return; + } - for (Object desObj : desList) { - Map aMap = (Map) desObj; + Iterator extIterator = extSet.iterator(); + while (extIterator.hasNext()) { + String ext = extIterator.next(); + if (!"".equals(ext)) { + ext = "." + ext; + } - String ns = (String) aMap.get("namespace"); + for (Object desObj : desList) { + Map aMap = (Map) desObj; - if (!"/".equals(ns)) { - ns = ns + "/"; - } + String ns = (String) aMap.get("namespace"); - compServicesURLs.add(appurl.substring(0, appurl.length() - 1) + ns + aMap.get("name") + ext); - } - } - } + if (!"/".equals(ns)) { + ns = ns + "/"; + } - private void getStruts2URLs(String appurl, Map> compServices, - Map strutsAction) { + compServicesURLs.add(appurl.substring(0, appurl.length() - 1) + ns + aMap.get("name") + ext); + } + } + } - for (Map.Entry entry : strutsAction.entrySet()) { + private void getStruts2URLs(String appurl, Map> compServices, + Map strutsAction) { - String key = entry.getKey(); + for (Map.Entry entry : strutsAction.entrySet()) { - if ("com.opensymphony.xwork2.ActionSupport".equals(key)) { - continue; - } + String key = entry.getKey(); - Set extSet = getStruts2URLExtension(strutsAction); - getStruts2URLsByAnno(appurl, compServices, strutsAction, key, extSet); - getStruts2URLsByDes(appurl, compServices, strutsAction, key, extSet); + if ("com.opensymphony.xwork2.ActionSupport".equals(key)) { + continue; + } - } + Set extSet = getStruts2URLExtension(strutsAction); + getStruts2URLsByAnno(appurl, compServices, strutsAction, key, extSet); + getStruts2URLsByDes(appurl, compServices, strutsAction, key, extSet); - // ignore com.opensymphony.xwork2.ActionSupport - strutsAction.remove("com.opensymphony.xwork2.ActionSupport"); - } + } - @SuppressWarnings("unchecked") - private Set getStruts2URLExtension(Map strutsAction) { + // ignore com.opensymphony.xwork2.ActionSupport + strutsAction.remove("com.opensymphony.xwork2.ActionSupport"); + } - Set extSet = new HashSet(); + @SuppressWarnings("unchecked") + private Set getStruts2URLExtension(Map strutsAction) { - for (Map.Entry entry : strutsAction.entrySet()) { + Set extSet = new HashSet(); - String key = entry.getKey(); - Object value = entry.getValue(); + for (Map.Entry entry : strutsAction.entrySet()) { - if ("com.opensymphony.xwork2.ActionSupport".equals(key)) { - continue; - } + String key = entry.getKey(); + Object value = entry.getValue(); - Map valueMap = (Map) value; + if ("com.opensymphony.xwork2.ActionSupport".equals(key)) { + continue; + } - List desList = (List) valueMap.get("des"); + Map valueMap = (Map) value; - if (desList == null) { - continue; - } + List desList = (List) valueMap.get("des"); - for (Object desObj : desList) { - Map aMap = (Map) desObj; - Object extObj = aMap.get("extension"); - if (extObj == null) { - continue; - } + if (desList == null) { + continue; + } - String[] extArr = ((String) extObj).split(","); + for (Object desObj : desList) { + Map aMap = (Map) desObj; + Object extObj = aMap.get("extension"); + if (extObj == null) { + continue; + } - List extList = Arrays.asList(extArr); + String[] extArr = ((String) extObj).split(","); - extSet.addAll(extList); + List extList = Arrays.asList(extArr); - return extSet; - } - } + extSet.addAll(extList); - if (extSet.size() <= 0) { - extSet.add("action"); - } + return extSet; + } + } - return extSet; - } + if (extSet.size() <= 0) { + extSet.add("action"); + } - /** - * getJAXWSProviderURLs - * - * @param jaxwsBaseUrl - * @param compServices - * @param jaxws - */ - @SuppressWarnings("unchecked") - private void getJAXWSProviderURLs(String jaxwsBaseUrl, Map> compServices, - Map jaxws) { + return extSet; + } - for (String compId : jaxws.keySet()) { + /** + * getJAXWSProviderURLs + * + * @param jaxwsBaseUrl + * @param compServices + * @param jaxws + */ + @SuppressWarnings("unchecked") + private void getJAXWSProviderURLs(String jaxwsBaseUrl, Map> compServices, + Map jaxws) { - Map compInfo = (Map) jaxws.get(compId); + for (String compId : jaxws.keySet()) { - Set compServicesURLs = compServices.get(compId); + Map compInfo = (Map) jaxws.get(compId); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + Set compServicesURLs = compServices.get(compId); - /** - * NODE: provider may not support description style, so only process - * annotation - */ - if (compInfo.containsKey("anno")) { + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } - Map compDesInfo = (Map) compInfo.get("anno"); + /** + * NODE: provider may not support description style, so only process annotation + */ + if (compInfo.containsKey("anno")) { - Map annoWebService = (Map) compDesInfo - .get("javax.xml.ws.WebServiceProvider"); + Map compDesInfo = (Map) compInfo.get("anno"); - String serviceName = (String) annoWebService.get("serviceName"); + Map annoWebService = (Map) compDesInfo + .get("javax.xml.ws.WebServiceProvider"); - if (StringHelper.isEmpty(serviceName)) { + String serviceName = (String) annoWebService.get("serviceName"); - String[] serviceImplClsInfo = compId.split("\\."); + if (StringHelper.isEmpty(serviceName)) { - serviceName = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; - } + String[] serviceImplClsInfo = compId.split("\\."); - String serviceURL = jaxwsBaseUrl + serviceName; - compServicesURLs.add(serviceURL); - } - } - } + serviceName = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; + } - /** - * getSpringMVCURLs - * - * @param springMVCBaseUrl - * @param compServices - * @param spring - */ - @SuppressWarnings("unchecked") - private void getSpringMVCURLs(String springMVCBaseUrl, Map> compServices, - Map spring) { + String serviceURL = jaxwsBaseUrl + serviceName; + compServicesURLs.add(serviceURL); + } + } + } - String realSpringMVCBaseUrl = null; - String suffix = ""; - if (springMVCBaseUrl != null) { + /** + * getSpringMVCURLs + * + * @param springMVCBaseUrl + * @param compServices + * @param spring + */ + @SuppressWarnings("unchecked") + private void getSpringMVCURLs(String springMVCBaseUrl, Map> compServices, + Map spring) { - // NOTE: handle *.xxx,should remove *.xxx - realSpringMVCBaseUrl = springMVCBaseUrl; + String realSpringMVCBaseUrl = null; + String suffix = ""; + if (springMVCBaseUrl != null) { - int allIndex = realSpringMVCBaseUrl.indexOf("*"); + // NOTE: handle *.xxx,should remove *.xxx + realSpringMVCBaseUrl = springMVCBaseUrl; - if (allIndex > -1) { + int allIndex = realSpringMVCBaseUrl.indexOf("*"); - // check if there is suffix, such as *.do - if (allIndex != realSpringMVCBaseUrl.length() - 1) { - suffix = realSpringMVCBaseUrl.substring(allIndex + 1); - } + if (allIndex > -1) { - // get the real access path - realSpringMVCBaseUrl = realSpringMVCBaseUrl.substring(0, allIndex); - } - } + // check if there is suffix, such as *.do + if (allIndex != realSpringMVCBaseUrl.length() - 1) { + suffix = realSpringMVCBaseUrl.substring(allIndex + 1); + } - for (String compId : spring.keySet()) { + // get the real access path + realSpringMVCBaseUrl = realSpringMVCBaseUrl.substring(0, allIndex); + } + } - Map compInfo = (Map) spring.get(compId); + for (String compId : spring.keySet()) { - Set compServicesURLs = compServices.get(compId); + Map compInfo = (Map) spring.get(compId); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + Set compServicesURLs = compServices.get(compId); - if (!compInfo.containsKey("anno")) { - continue; - } + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } - // get resourceClass path - Map compDesInfo = (Map) compInfo.get("anno"); + if (!compInfo.containsKey("anno")) { + continue; + } - List resourceClassRelativePaths = null; + // get resourceClass path + Map compDesInfo = (Map) compInfo.get("anno"); - /** - * NOTE: RequestMapping is optional to spring mvc resource class - */ + List resourceClassRelativePaths = null; - Map annoWebService = (Map) compDesInfo - .get("org.springframework.web.bind.annotation.RequestMapping"); + /** + * NOTE: RequestMapping is optional to spring mvc resource class + */ - if (annoWebService != null) { + Map annoWebService = (Map) compDesInfo + .get("org.springframework.web.bind.annotation.RequestMapping"); - resourceClassRelativePaths = (List) annoWebService.get("value"); - } + if (annoWebService != null) { - /** - * if there is no path on resource class, we take the path as "" - */ - if (resourceClassRelativePaths == null) { - resourceClassRelativePaths = new ArrayList(); - resourceClassRelativePaths.add(""); - } + resourceClassRelativePaths = (List) annoWebService.get("value"); + } - for (String resourceClassRelativePath : resourceClassRelativePaths) { + /** + * if there is no path on resource class, we take the path as "" + */ + if (resourceClassRelativePaths == null) { + resourceClassRelativePaths = new ArrayList(); + resourceClassRelativePaths.add(""); + } - resourceClassRelativePath = formatRelativePath(resourceClassRelativePath); + for (String resourceClassRelativePath : resourceClassRelativePaths) { - // get the resource class path - String resourceClassPath = realSpringMVCBaseUrl + resourceClassRelativePath; + resourceClassRelativePath = formatRelativePath(resourceClassRelativePath); - // get methods path - Map compMethodInfo = (Map) compInfo.get("methods"); + // get the resource class path + String resourceClassPath = realSpringMVCBaseUrl + resourceClassRelativePath; - for (String method : compMethodInfo.keySet()) { + // get methods path + Map compMethodInfo = (Map) compInfo.get("methods"); - Map methodInfo = (Map) compMethodInfo.get(method); + for (String method : compMethodInfo.keySet()) { - if (!methodInfo.containsKey("anno")) { - continue; - } + Map methodInfo = (Map) compMethodInfo.get(method); - Map methodAnnoInfo = (Map) methodInfo.get("anno"); + if (!methodInfo.containsKey("anno")) { + continue; + } - String serviceURL = formatRelativePath(resourceClassPath); + Map methodAnnoInfo = (Map) methodInfo.get("anno"); - /** - * each method has Path info except only one - */ - if (methodAnnoInfo.containsKey("org.springframework.web.bind.annotation.RequestMapping")) { + String serviceURL = formatRelativePath(resourceClassPath); - Map pathAnnoInfo = (Map) methodAnnoInfo - .get("org.springframework.web.bind.annotation.RequestMapping"); + /** + * each method has Path info except only one + */ + if (methodAnnoInfo.containsKey("org.springframework.web.bind.annotation.RequestMapping")) { - List methodRelativePaths = (List) pathAnnoInfo.get("value"); + Map pathAnnoInfo = (Map) methodAnnoInfo + .get("org.springframework.web.bind.annotation.RequestMapping"); - // FIX NPE - if (methodRelativePaths == null) { - compServicesURLs.add(serviceURL); - continue; - } + List methodRelativePaths = (List) pathAnnoInfo.get("value"); - for (String methodRelativePath : methodRelativePaths) { + // FIX NPE + if (methodRelativePaths == null) { + compServicesURLs.add(serviceURL); + continue; + } - methodRelativePath = formatRelativePath(methodRelativePath); + for (String methodRelativePath : methodRelativePaths) { - String methodServiceURL; + methodRelativePath = formatRelativePath(methodRelativePath); - if (methodRelativePath.endsWith(suffix)) { + String methodServiceURL; - methodServiceURL = formatRelativePath(serviceURL + "/" + methodRelativePath); - } else { - methodServiceURL = formatRelativePath(serviceURL + "/" + methodRelativePath + suffix); - } + if (methodRelativePath.endsWith(suffix)) { - compServicesURLs.add(methodServiceURL); - } - } else { - compServicesURLs.add(serviceURL); - } - } + methodServiceURL = formatRelativePath(serviceURL + "/" + methodRelativePath); + } + else { + methodServiceURL = formatRelativePath(serviceURL + "/" + methodRelativePath + suffix); + } - } - } - } + compServicesURLs.add(methodServiceURL); + } + } + else { + compServicesURLs.add(serviceURL); + } + } - /** - * getJAXRSURLs - * - * @param jaxrsBaseUrl - * @param compServices - * @param jaxrs - */ - @SuppressWarnings("unchecked") - private void getJAXRSURLs(String jaxrsBaseUrl, Map> compServices, Map jaxrs) { + } + } + } - for (String compId : jaxrs.keySet()) { + /** + * getJAXRSURLs + * + * @param jaxrsBaseUrl + * @param compServices + * @param jaxrs + */ + @SuppressWarnings("unchecked") + private void getJAXRSURLs(String jaxrsBaseUrl, Map> compServices, Map jaxrs) { - Map compInfo = (Map) jaxrs.get(compId); + for (String compId : jaxrs.keySet()) { - Set compServicesURLs = compServices.get(compId); + Map compInfo = (Map) jaxrs.get(compId); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + Set compServicesURLs = compServices.get(compId); - if (!compInfo.containsKey("anno")) { - continue; - } + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } - // get resourceClass path - Map compDesInfo = (Map) compInfo.get("anno"); + if (!compInfo.containsKey("anno")) { + continue; + } - Map annoWebService = (Map) compDesInfo.get("javax.ws.rs.Path"); + // get resourceClass path + Map compDesInfo = (Map) compInfo.get("anno"); - String resourceClassRelativePath = (String) annoWebService.get("value"); + Map annoWebService = (Map) compDesInfo.get("javax.ws.rs.Path"); - resourceClassRelativePath = formatRelativePath(resourceClassRelativePath); + String resourceClassRelativePath = (String) annoWebService.get("value"); - // get the resource class path - String resourceClassPath = jaxrsBaseUrl + resourceClassRelativePath - + ("".equalsIgnoreCase(resourceClassRelativePath) ? "" : "/"); + resourceClassRelativePath = formatRelativePath(resourceClassRelativePath); - // get methods path - Map compMethodInfo = (Map) compInfo.get("methods"); + // get the resource class path + String resourceClassPath = jaxrsBaseUrl + resourceClassRelativePath + + ("".equalsIgnoreCase(resourceClassRelativePath) ? "" : "/"); - for (String method : compMethodInfo.keySet()) { + // get methods path + Map compMethodInfo = (Map) compInfo.get("methods"); - Map methodInfo = (Map) compMethodInfo.get(method); + for (String method : compMethodInfo.keySet()) { - if (!methodInfo.containsKey("anno")) { - continue; - } + Map methodInfo = (Map) compMethodInfo.get(method); - Map methodAnnoInfo = (Map) methodInfo.get("anno"); + if (!methodInfo.containsKey("anno")) { + continue; + } - String serviceURL = resourceClassPath; + Map methodAnnoInfo = (Map) methodInfo.get("anno"); - /** - * each method has Path info except only one - */ - if (methodAnnoInfo.containsKey("javax.ws.rs.Path")) { - Map pathAnnoInfo = (Map) methodAnnoInfo.get("javax.ws.rs.Path"); + String serviceURL = resourceClassPath; - String methodRelativePath = (String) pathAnnoInfo.get("value"); + /** + * each method has Path info except only one + */ + if (methodAnnoInfo.containsKey("javax.ws.rs.Path")) { + Map pathAnnoInfo = (Map) methodAnnoInfo.get("javax.ws.rs.Path"); - methodRelativePath = formatRelativePath(methodRelativePath); + String methodRelativePath = (String) pathAnnoInfo.get("value"); - serviceURL += methodRelativePath; - } else { - serviceURL = serviceURL.substring(0, serviceURL.length() - 1); - } + methodRelativePath = formatRelativePath(methodRelativePath); - compServicesURLs.add(serviceURL); - } - } - } + serviceURL += methodRelativePath; + } + else { + serviceURL = serviceURL.substring(0, serviceURL.length() - 1); + } - /** - * getJAXWSURLs - * - * @param jaxwsBaseUrl - * @param compServices - * @param jaxws - */ - @SuppressWarnings("unchecked") - private void getJAXWSURLs(Map> compServices, Map jaxws, - Map serviceServlets, String appurl) { + compServicesURLs.add(serviceURL); + } + } + } - String jaxwsBaseUrl = serviceServlets.get("jaxws"); + /** + * getJAXWSURLs + * + * @param jaxwsBaseUrl + * @param compServices + * @param jaxws + */ + @SuppressWarnings("unchecked") + private void getJAXWSURLs(Map> compServices, Map jaxws, + Map serviceServlets, String appurl) { - for (String compId : jaxws.keySet()) { + String jaxwsBaseUrl = serviceServlets.get("jaxws"); - Map compInfo = (Map) jaxws.get(compId); + for (String compId : jaxws.keySet()) { - Set compServicesURLs = compServices.get(compId); + Map compInfo = (Map) jaxws.get(compId); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + Set compServicesURLs = compServices.get(compId); - if (compInfo.containsKey("dyn")) { + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } - Map compDesInfo = (Map) compInfo.get("dyn"); + if (compInfo.containsKey("dyn")) { - String url = (String) compDesInfo.get("url"); + Map compDesInfo = (Map) compInfo.get("dyn"); - String serviceURL = null; + String url = (String) compDesInfo.get("url"); - if (StringHelper.isEmpty(url)) { + String serviceURL = null; - String[] serviceImplClsInfo = compId.split("\\."); + if (StringHelper.isEmpty(url)) { - url = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; + String[] serviceImplClsInfo = compId.split("\\."); - serviceURL = jaxwsBaseUrl + url; + url = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; - } else if (url.startsWith("http")) { + serviceURL = jaxwsBaseUrl + url; - serviceURL = url; + } + else if (url.startsWith("http")) { - } else { + serviceURL = url; - url = this.formatRelativePath(url); - serviceURL = jaxwsBaseUrl + url; - } + } + else { - compServicesURLs.add(serviceURL); + url = this.formatRelativePath(url); + serviceURL = jaxwsBaseUrl + url; + } - } else if (compInfo.containsKey("des")) { + compServicesURLs.add(serviceURL); - Map compDesInfo = (Map) compInfo.get("des"); + } + else if (compInfo.containsKey("des")) { - String url = (String) compDesInfo.get("address"); + Map compDesInfo = (Map) compInfo.get("des"); - if (url == null) { - url = (String) compDesInfo.get("url-pattern"); - } + String url = (String) compDesInfo.get("address"); - if ("".equals(url)) { - url = "@UNKOWN_SERVICE"; - } + if (url == null) { + url = (String) compDesInfo.get("url-pattern"); + } - url = this.formatRelativePath(url); - String serviceURL = null; - if (compDesInfo.get("address") != null) { - serviceURL = jaxwsBaseUrl + url; - } else if (compDesInfo.get("url-pattern") != null) { - serviceURL = appurl + url; - } + if ("".equals(url)) { + url = "@UNKOWN_SERVICE"; + } - compServicesURLs.add(serviceURL); - } else if (compInfo.containsKey("anno")) { + url = this.formatRelativePath(url); + String serviceURL = null; + if (compDesInfo.get("address") != null) { + serviceURL = jaxwsBaseUrl + url; + } + else if (compDesInfo.get("url-pattern") != null) { + serviceURL = appurl + url; + } - Map compDesInfo = (Map) compInfo.get("anno"); + compServicesURLs.add(serviceURL); + } + else if (compInfo.containsKey("anno")) { - Map annoWebService = (Map) compDesInfo.get("javax.jws.WebService"); + Map compDesInfo = (Map) compInfo.get("anno"); - String serviceName = (String) annoWebService.get("serviceName"); + Map annoWebService = (Map) compDesInfo.get("javax.jws.WebService"); - if (StringHelper.isEmpty(serviceName)) { + String serviceName = (String) annoWebService.get("serviceName"); - String[] serviceImplClsInfo = compId.split("\\."); + if (StringHelper.isEmpty(serviceName)) { - serviceName = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; - } + String[] serviceImplClsInfo = compId.split("\\."); - String serviceURL = jaxwsBaseUrl + serviceName; - compServicesURLs.add(serviceURL); - } - } - } + serviceName = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; + } - /** - * getServletsURLs - * - * @param appURL - * @param compServices - * @param servlets - * @return - */ - @SuppressWarnings("unchecked") - private Map getServletsURLs(String appURL, Map> compServices, - Map servlets) { + String serviceURL = jaxwsBaseUrl + serviceName; + compServicesURLs.add(serviceURL); + } + } + } - // temp store the service base url - Map serviceServlets = new LinkedHashMap(); + /** + * getServletsURLs + * + * @param appURL + * @param compServices + * @param servlets + * @return + */ + @SuppressWarnings("unchecked") + private Map getServletsURLs(String appURL, Map> compServices, + Map servlets) { - for (String compId : servlets.keySet()) { + // temp store the service base url + Map serviceServlets = new LinkedHashMap(); - Map compInfo = (Map) servlets.get(compId); + for (String compId : servlets.keySet()) { - Set compServicesURLs = compServices.get(compId); + Map compInfo = (Map) servlets.get(compId); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + Set compServicesURLs = compServices.get(compId); - if (compInfo.containsKey("des")) { + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } - Map compDesInfo = (Map) compInfo.get("des"); + if (compInfo.containsKey("des")) { - List urls = (List) compDesInfo.get("urlPatterns"); + Map compDesInfo = (Map) compInfo.get("des"); - if (null == urls || urls.size() == 0) { - continue; - } + List urls = (List) compDesInfo.get("urlPatterns"); - for (String url : urls) { + if (null == urls || urls.size() == 0) { + continue; + } - // remove /* for better match, will not handle *.xxxx - if (url.lastIndexOf("*") == url.length() - 1) { - url = url.substring(0, url.length() - 1); - } + for (String url : urls) { - url = formatRelativePath(url); + // remove /* for better match, will not handle *.xxxx + if (url.lastIndexOf("*") == url.length() - 1) { + url = url.substring(0, url.length() - 1); + } - String serviceURL = appURL + url; + url = formatRelativePath(url); - if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { - serviceURL = serviceURL.substring(0, serviceURL.length() - 1); - } + String serviceURL = appURL + url; - findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); + if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { + serviceURL = serviceURL.substring(0, serviceURL.length() - 1); + } - compServicesURLs.add(serviceURL); - } - } else if (compInfo.containsKey("dyn")) { + findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); - Map compDesInfo = (Map) compInfo.get("dyn"); + compServicesURLs.add(serviceURL); + } + } + else if (compInfo.containsKey("dyn")) { - List urls = (List) compDesInfo.get("urlPatterns"); + Map compDesInfo = (Map) compInfo.get("dyn"); - if (null == urls || urls.size() == 0) { - continue; - } + List urls = (List) compDesInfo.get("urlPatterns"); - for (String url : urls) { + if (null == urls || urls.size() == 0) { + continue; + } - // remove /* for better match, will not handle *.xxxx - if (url.lastIndexOf("*") == url.length() - 1) { - url = url.substring(0, url.length() - 1); - } + for (String url : urls) { - url = formatRelativePath(url); + // remove /* for better match, will not handle *.xxxx + if (url.lastIndexOf("*") == url.length() - 1) { + url = url.substring(0, url.length() - 1); + } - String serviceURL = appURL + url; + url = formatRelativePath(url); - if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { - serviceURL = serviceURL.substring(0, serviceURL.length() - 1); - } + String serviceURL = appURL + url; - findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); + if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { + serviceURL = serviceURL.substring(0, serviceURL.length() - 1); + } - compServicesURLs.add(serviceURL); - } - } else if (compInfo.containsKey("anno")) { + findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); - Map compDesInfo = (Map) compInfo.get("anno"); + compServicesURLs.add(serviceURL); + } + } + else if (compInfo.containsKey("anno")) { - for (String compDescId : compDesInfo.keySet()) { - Map compDescInfo = (Map) compDesInfo.get(compDescId); + Map compDesInfo = (Map) compInfo.get("anno"); - List urls = (List) compDescInfo.get("urlPatterns"); + for (String compDescId : compDesInfo.keySet()) { + Map compDescInfo = (Map) compDesInfo.get(compDescId); - if (null == urls || urls.size() == 0) { - urls = (List) compDescInfo.get("value"); - } + List urls = (List) compDescInfo.get("urlPatterns"); - if (null == urls || urls.size() == 0) { - continue; - } + if (null == urls || urls.size() == 0) { + urls = (List) compDescInfo.get("value"); + } - for (String url : urls) { + if (null == urls || urls.size() == 0) { + continue; + } - // remove /* for better match, will not handle *.xxxx - if (url.lastIndexOf("*") == url.length() - 1) { - url = url.substring(0, url.length() - 1); - } + for (String url : urls) { - url = formatRelativePath(url); + // remove /* for better match, will not handle *.xxxx + if (url.lastIndexOf("*") == url.length() - 1) { + url = url.substring(0, url.length() - 1); + } - String serviceURL = appURL + url; + url = formatRelativePath(url); - if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { - serviceURL = serviceURL.substring(0, serviceURL.length() - 1); - } + String serviceURL = appURL + url; - findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); + if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { + serviceURL = serviceURL.substring(0, serviceURL.length() - 1); + } - compServicesURLs.add(serviceURL); - } - } - - } - } - - /** - * we should figure out which JAXWS,JAXRS engine is used NOTE: this is - * barely by HUMAN, not 100% right, we need refine this part TODO: need - * refine - */ - // add axis2 - if (serviceServlets.containsKey("axis2")) { - serviceServlets.put("jaxws", serviceServlets.get("axis2") + "/"); - } else if (serviceServlets.containsKey("xfire")) { - serviceServlets.put("jaxws", serviceServlets.get("xfire") + "/"); - } else if (serviceServlets.containsKey("cxf")) { - - serviceServlets.put("jaxws", serviceServlets.get("cxf") + "/"); - } else if (serviceServlets.containsKey("jaxws-ri")) { - - serviceServlets.put("jaxws", serviceServlets.get("jaxws-ri") + "/"); - } - - // add wink - if (serviceServlets.containsKey("wink")) { - serviceServlets.put("jaxrs", serviceServlets.get("wink") + "/"); - } else if (serviceServlets.containsKey("jersey")) { - serviceServlets.put("jaxrs", serviceServlets.get("jersey") + "/"); - } else if (serviceServlets.containsKey("cxf")) { - serviceServlets.put("jaxrs", serviceServlets.get("cxf") + "/"); - } - // add hession - else if (serviceServlets.containsKey("hession")) { - serviceServlets.put("jaxrs", serviceServlets.get("hession") + "/"); - } - - if (serviceServlets.containsKey("springmvc")) { - serviceServlets.put("springmvc", serviceServlets.get("springmvc") + "/"); - } - - return serviceServlets; - } - - /** - * findoutAppFrameworkServlets - * - * @param serviceServlets - * @param compId - * @param serviceURL - */ - private void findoutAppFrameworkServlets(Map serviceServlets, Map compInfo, - String serviceURL) { - - if (!compInfo.containsKey("engine")) { - return; - } - - String engine = (String) compInfo.get("engine"); - - if (engine.indexOf("cxf") > -1) { - serviceServlets.put("cxf", serviceURL); - } else if (engine.indexOf("jersey") > -1) { - serviceServlets.put("jersey", serviceURL); - } else if (engine.indexOf("springmvc") > -1) { - serviceServlets.put("springmvc", serviceURL); - } else if (engine.indexOf("jaxws-ri") > -1) { - serviceServlets.put("jaxws-ri", serviceURL); - } - } - - /** - * formatRelativePath - * - * @param resourceClassRelativePath - * @return - */ - private String formatRelativePath(String resourceClassRelativePath) { - - // remove first / - if (resourceClassRelativePath.indexOf("/") == 0) { - - if (resourceClassRelativePath.length() == 1) { - resourceClassRelativePath = ""; - } else { - resourceClassRelativePath = resourceClassRelativePath.substring(1); - } - } - - // remove last / - if (resourceClassRelativePath.lastIndexOf("/") == resourceClassRelativePath.length() - 1) { - - if (resourceClassRelativePath.length() == 1) { - resourceClassRelativePath = ""; - } else if (resourceClassRelativePath.length() > 1) { - resourceClassRelativePath = resourceClassRelativePath.substring(0, - resourceClassRelativePath.length() - 1); - } - } - return resourceClassRelativePath; - } + findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); + + compServicesURLs.add(serviceURL); + } + } + + } + } + + /** + * we should figure out which JAXWS,JAXRS engine is used NOTE: this is barely by HUMAN, not 100% right, we need + * refine this part TODO: need refine + */ + // add axis2 + if (serviceServlets.containsKey("axis2")) { + serviceServlets.put("jaxws", serviceServlets.get("axis2") + "/"); + } + else if (serviceServlets.containsKey("xfire")) { + serviceServlets.put("jaxws", serviceServlets.get("xfire") + "/"); + } + else if (serviceServlets.containsKey("cxf")) { + + serviceServlets.put("jaxws", serviceServlets.get("cxf") + "/"); + } + else if (serviceServlets.containsKey("jaxws-ri")) { + + serviceServlets.put("jaxws", serviceServlets.get("jaxws-ri") + "/"); + } + + // add wink + if (serviceServlets.containsKey("wink")) { + serviceServlets.put("jaxrs", serviceServlets.get("wink") + "/"); + } + else if (serviceServlets.containsKey("jersey")) { + serviceServlets.put("jaxrs", serviceServlets.get("jersey") + "/"); + } + else if (serviceServlets.containsKey("cxf")) { + serviceServlets.put("jaxrs", serviceServlets.get("cxf") + "/"); + } + // add hession + else if (serviceServlets.containsKey("hession")) { + serviceServlets.put("jaxrs", serviceServlets.get("hession") + "/"); + } + + if (serviceServlets.containsKey("springmvc")) { + serviceServlets.put("springmvc", serviceServlets.get("springmvc") + "/"); + } + + return serviceServlets; + } + + /** + * findoutAppFrameworkServlets + * + * @param serviceServlets + * @param compId + * @param serviceURL + */ + private void findoutAppFrameworkServlets(Map serviceServlets, Map compInfo, + String serviceURL) { + + if (!compInfo.containsKey("engine")) { + return; + } + + String engine = (String) compInfo.get("engine"); + + if (engine.indexOf("cxf") > -1) { + serviceServlets.put("cxf", serviceURL); + } + else if (engine.indexOf("jersey") > -1) { + serviceServlets.put("jersey", serviceURL); + } + else if (engine.indexOf("springmvc") > -1) { + serviceServlets.put("springmvc", serviceURL); + } + else if (engine.indexOf("jaxws-ri") > -1) { + serviceServlets.put("jaxws-ri", serviceURL); + } + } + + /** + * formatRelativePath + * + * @param resourceClassRelativePath + * @return + */ + private String formatRelativePath(String resourceClassRelativePath) { + + // remove first / + if (resourceClassRelativePath.indexOf("/") == 0) { + + if (resourceClassRelativePath.length() == 1) { + resourceClassRelativePath = ""; + } + else { + resourceClassRelativePath = resourceClassRelativePath.substring(1); + } + } + + // remove last / + if (resourceClassRelativePath.lastIndexOf("/") == resourceClassRelativePath.length() - 1) { + + if (resourceClassRelativePath.length() == 1) { + resourceClassRelativePath = ""; + } + else if (resourceClassRelativePath.length() > 1) { + resourceClassRelativePath = resourceClassRelativePath.substring(0, + resourceClassRelativePath.length() - 1); + } + } + return resourceClassRelativePath; + } } diff --git a/com.creditease.uav.monitorframework/src/main/java/com/creditease/uav/profiling/handlers/ComponentProfileHandler.java b/com.creditease.uav.monitorframework/src/main/java/com/creditease/uav/profiling/handlers/ComponentProfileHandler.java index f138ec2a..3d8592df 100644 --- a/com.creditease.uav.monitorframework/src/main/java/com/creditease/uav/profiling/handlers/ComponentProfileHandler.java +++ b/com.creditease.uav.monitorframework/src/main/java/com/creditease/uav/profiling/handlers/ComponentProfileHandler.java @@ -201,7 +201,8 @@ public static List getMethodParamInfo(Method m) { return pinfos; } - // -------------------------------------------Deployment Descriptor Processor------------------------------------ + // -------------------------------------------Deployment Descriptor + // Processor------------------------------------ /** * DescriptorProcessor is the basic class to handle the deployment descriptor file such as * web.xml,spring-context.xml... @@ -805,7 +806,8 @@ private String getImplClassAsKey(String key, Node jaxws, ClassLoader cl, String try { Class c = cl.loadClass(sClass); - // step 1.1: we need see serviceBean|implementor if is interface + // step 1.1: we need see serviceBean|implementor + // if is interface if (c.isInterface() == true) { if (logger.isDebugable()) { logger.debug( @@ -814,14 +816,16 @@ private String getImplClassAsKey(String key, Node jaxws, ClassLoader cl, String null); } } - // step 1.2: if this class is not interface, we assume it is the impl class, because + // step 1.2: if this class is not interface, we + // assume it is the impl class, because // maybe this is a wrong class else { return sClass; } } catch (ClassNotFoundException e) { - // step 1.3: that means this is a unknown class, we need see serviceBean|implementor + // step 1.3: that means this is a unknown class, + // we need see serviceBean|implementor if (logger.isDebugable()) { logger.debug("LOAD JAXWS Impl class[" + sClass + "] FAIL from SPRING ConfigXml Element Attribute[" + serviceClass + "].", @@ -1044,7 +1048,8 @@ else if ("/web-app/listener/listener-class".equals(xpath)) { @Override public void loadInfo(String sKey, String sKeyRawValue, Map sInfo) { - // doing nothing as no thing need being collected for listeners + // doing nothing as no thing need being collected for + // listeners } }; } @@ -1057,7 +1062,8 @@ else if ("/web-app/display-name".equals(xpath)) @Override public void loadInfo(String sKey, String sKeyRawValue, Map sInfo) { - // doing nothing as no thing need being collected for display-name + // doing nothing as no thing need being collected for + // display-name } }; } @@ -1371,7 +1377,7 @@ public Map process(Class comCls, ProfileContext context) { * 将类似下面的注解信息中的带转义引号(\")替换为单引号 * * @Action(value = "downloadModel", results = { @Result(type = "stream", params = {"inputName", "inputStream", - * "contentDisposition", "attachment;filename=\"${downloadFileName}\"","bufferSize", "512" }) }) + * "contentDisposition", "attachment;filename=\"${downloadFileName}\"", "bufferSize", "512" }) }) * * @param annoInfo * @return @@ -2107,7 +2113,8 @@ public void doProfiling(ProfileElement elem, ProfileContext context) { // try to load componentsByDescriptor loadComponentsByDescriptor(dpInstances, webAppRoot, context, componentClassName, inst); - // try to load componentsByDynamic Creation, currently is for servlet 3.x and webservice + // try to load componentsByDynamic Creation, currently is for + // servlet 3.x and webservice loadComponentsByDynamic(itContext, componentClassName, inst, context, annoAvailableClasses, fcs); /** @@ -2521,7 +2528,7 @@ else if (isJAXWS == true && value != null) { for (String methodPath : methodPaths) { /** - * NOTE:支持方法级的模糊匹配,只要有一个方法的URL是带*的,该方法所有url都支持模糊匹配(有点小limitation) + * NOTE:支持方法级的模糊匹配,只要有一个方法的URL是带*的,该方法所有url都支持模糊匹配( 有点小limitation) */ /** * option 1: /aaa/* @@ -2843,7 +2850,8 @@ private void getAppGroup(ProfileElementInstance inst) { // // // add metricName to customizedMetrics // if (metricsArray.length == 3) { - // metrics.put(metricsArray[1], JSONHelper.toObject(metricsArray[2], Map.class)); + // metrics.put(metricsArray[1], JSONHelper.toObject(metricsArray[2], + // Map.class)); // } // else { // metrics.put(metricsArray[1], Collections.emptyMap()); @@ -2930,7 +2938,8 @@ protected void loadComponentsByDescriptor(Map dpIns dpInst = dpInstances.get(dpClass.getName()); } - // load componentsByDescriptor then the descriptors have a chance to override the anno, this is match the + // load componentsByDescriptor then the descriptors have a chance to + // override the anno, this is match the // JEE // SPEC or Common Sense if (dpInst != null) { From 7b44e08af101247a2c6a875fd0e2339fbb70ec0a Mon Sep 17 00:00:00 2001 From: longxiao2 Date: Tue, 10 Oct 2017 19:13:29 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=E4=BF=AE=E6=94=B9code=20style?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../handlers/ProfileDataMessageHandler.java | 2053 +++++++++-------- 1 file changed, 1036 insertions(+), 1017 deletions(-) diff --git a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/healthmanager/messaging/handlers/ProfileDataMessageHandler.java b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/healthmanager/messaging/handlers/ProfileDataMessageHandler.java index c8201112..60eb28be 100644 --- a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/healthmanager/messaging/handlers/ProfileDataMessageHandler.java +++ b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/healthmanager/messaging/handlers/ProfileDataMessageHandler.java @@ -43,1311 +43,1330 @@ public class ProfileDataMessageHandler extends AbstractMessageHandler { - @Override - public void handle(Message msg) { + @Override + public void handle(Message msg) { - // push the latest profile data to cache - List newMDFs = pushLatestProfileDataToCacheCenter(msg.getParam(getMsgTypeName())); + // push the latest profile data to cache + List newMDFs = pushLatestProfileDataToCacheCenter(msg.getParam(getMsgTypeName())); - if (newMDFs.size() > 0) { - // set the new MDFs into msg - msg.setParam(getMsgTypeName(), JSONHelper.toString(newMDFs)); - // store profile data - super.handle(msg); - } - } + if (newMDFs.size() > 0) { + // set the new MDFs into msg + msg.setParam(getMsgTypeName(), JSONHelper.toString(newMDFs)); + // store profile data + super.handle(msg); + } + } - @Override - public String getMsgTypeName() { - - return MonitorDataFrame.MessageType.Profile.toString(); - } - - @Override - protected void preInsert(DataStoreMsg dsMsg) { - - // set target collection - dsMsg.put(DataStoreProtocol.MONGO_COLLECTION_NAME, HealthManagerConstants.MONGO_COLLECTION_PROFILE); - } - - /** - * 推送最新的ProfileData到缓存中心 - * - * @param profileString - */ - @SuppressWarnings({ "rawtypes" }) - private List pushLatestProfileDataToCacheCenter(String profileString) { - - CacheManager cm = (CacheManager) ConfigurationManager.getInstance().getComponent("healthmanager", - "HMCacheManager"); - - cm.beginBatch(); - - List monitorDataFrames = JSONHelper.toObjectArray(profileString, String.class); - - List newMDFs = new ArrayList(); - - for (String mdfStr : monitorDataFrames) { - MonitorDataFrame mdf = new MonitorDataFrame(mdfStr); - - String tag = mdf.getTag(); - - /** - * note: only tag==P means this MDF is the new MDF, otherwise this - * MDF is just for heartbeat - */ - if (tag.equalsIgnoreCase("P")) { - newMDFs.add(mdfStr); - } - - /** - * Step 1: build all profile node info - */ - Map> frames = mdf.getDatas(); - for (String appid : frames.keySet()) { - - Map appProfile = new LinkedHashMap(); - - /** - * 1.1 basic info of the application - */ - Map values = mdf.getElemInstValues(appid, "cpt", "webapp"); - - String appurl = (String) values.get("appurl"); - - /** - * appgroup - */ - String appgroup = ""; - - if (values.containsKey("appgroup")) { - appgroup = (String) values.get("appgroup"); - } - - /** - * appdes from web.xml's description {org:"owner info"} - */ - String appdes = ""; - - if (values.containsKey("appdes")) { - appdes = (String) values.get("appdes"); - } - - /** - * appmetrics - */ - String appmetrics = ""; - - if (values.containsKey("appmetrics")) { - appmetrics = JSONHelper.toString(values.get("appmetrics")); - } - - /** - * appName - */ - String appName = (String) values.get("appname"); - - /** - * app root - */ - String appRoot = (String) values.get("webapproot"); - - /** - * MOF metadata - */ - String mofMeta = ""; - - if (values.containsKey("mofmeta")) { - mofMeta = JSONHelper.toString(values.get("mofmeta")); - } - - appProfile.put("appid", appid); - appProfile.put("ip", mdf.getIP()); - appProfile.put("svrid", mdf.getServerId()); - appProfile.put("host", mdf.getHost()); - appProfile.put("time", mdf.getTimeFlag()); - appProfile.put("appname", appName); - appProfile.put("appdes", appdes); - appProfile.put("appmetrics", appmetrics); - appProfile.put("appgroup", appgroup); - appProfile.put("webapproot", appRoot); - appProfile.put("appurl", appurl); - appProfile.put("mofmeta", mofMeta); - - /** - * step 1.2: cache the application clients profile data - */ - String clientsJSONstr = cacheAppClientProfileData(cm, mdf, appid, appurl, appgroup); - - /** - * Step 1.3 cache the application profile data - */ - cacheAppProfileData(cm, mdf, appProfile, clientsJSONstr, appid, appurl, appgroup); - - /** - * step 1.4: cache application ip_link & access data - */ - cacheAppIPLinkProfileData(cm, mdf, appid, appurl, appgroup); - } - } - - cm.submitBatch(); - - return newMDFs; - } - - /** - * cacheAppIPLinkProfileData - * - * @param cm - * @param mdf - * @param appid - * @param appurl - * @param appgroup - */ - @SuppressWarnings("rawtypes") - private void cacheAppIPLinkProfileData(CacheManager cm, MonitorDataFrame mdf, String appid, String appurl, - String appgroup) { - - List iplinks = mdf.getElemInstances(appid, "iplnk"); - - Map appIpLnkMap = new HashMap(); - - for (Map iplink : iplinks) { - String iplnk_id = (String) iplink.get("id"); - @SuppressWarnings("unchecked") - Map iplnk_values = (Map) iplink.get("values"); - appIpLnkMap.put(iplnk_id, JSONHelper.toString(iplnk_values)); - appIpLnkMap.put(iplnk_id + "-ts", String.valueOf(iplnk_values.get("ts"))); - } - - String iplnkfieldKey = "LNK@" + appgroup + "@" + appurl; - - cm.putHash(HealthManagerConstants.STORE_REGION_UAV, iplnkfieldKey, appIpLnkMap); - } - - /** - * cacheAppClientProfileData - * - * @param cm - * @param mdf - * @param appid - * @param appurl - * @param appgroup - */ - @SuppressWarnings("rawtypes") - private String cacheAppClientProfileData(CacheManager cm, MonitorDataFrame mdf, String appid, String appurl, - String appgroup) { - - List clients = mdf.getElemInstances(appid, "clients"); - - long checkTime = System.currentTimeMillis(); - - long expireTime = 60000; - - for (int i = 0; i < clients.size(); i++) { - - Map client = clients.get(i); - - @SuppressWarnings("unchecked") - Map cVals = (Map) client.get("values"); - - Long client_ts = (Long) cVals.get("ts"); - - if (client_ts == null) { - continue; - } - - long client_timeout = checkTime - client_ts; - - if (client_timeout < expireTime) { - cVals.put("state", "1"); - } else if (client_timeout >= expireTime && client_timeout < expireTime * 2) { - cVals.put("state", "0"); - } else if (client_timeout >= expireTime * 2) { - cVals.put("state", "-1"); - } - } - - String fieldKey = "C@" + appgroup + "@" + appurl; - - String clientsStr = JSONHelper.toString(clients); - - cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO_APPCLIENT, - fieldKey, clientsStr); - - return clientsStr; - } - - /** - * cache the application profile data - * - * @param cm - * @param mdf - * @param appid - */ - private void cacheAppProfileData(CacheManager cm, MonitorDataFrame mdf, Map pi, - String clientsJSONstr, String appid, String appurl, String appgroup) { + @Override + public String getMsgTypeName() { - /** - * client - */ - pi.put("cpt.clients", clientsJSONstr); + return MonitorDataFrame.MessageType.Profile.toString(); + } + + @Override + protected void preInsert(DataStoreMsg dsMsg) { + + // set target collection + dsMsg.put(DataStoreProtocol.MONGO_COLLECTION_NAME, HealthManagerConstants.MONGO_COLLECTION_PROFILE); + } + + /** + * 推送最新的ProfileData到缓存中心 + * + * @param profileString + */ + @SuppressWarnings({ "rawtypes" }) + private List pushLatestProfileDataToCacheCenter(String profileString) { + + CacheManager cm = (CacheManager) ConfigurationManager.getInstance().getComponent("healthmanager", + "HMCacheManager"); + + cm.beginBatch(); + + List monitorDataFrames = JSONHelper.toObjectArray(profileString, String.class); + + List newMDFs = new ArrayList(); + + for (String mdfStr : monitorDataFrames) { + MonitorDataFrame mdf = new MonitorDataFrame(mdfStr); + + String tag = mdf.getTag(); + + /** + * note: only tag==P means this MDF is the new MDF, otherwise this MDF is just for heartbeat + */ + if (tag.equalsIgnoreCase("P")) { + newMDFs.add(mdfStr); + } + + /** + * Step 1: build all profile node info + */ + Map> frames = mdf.getDatas(); + for (String appid : frames.keySet()) { + + Map appProfile = new LinkedHashMap(); + + /** + * 1.1 basic info of the application + */ + Map values = mdf.getElemInstValues(appid, "cpt", "webapp"); + + String appurl = (String) values.get("appurl"); + + /** + * appgroup + */ + String appgroup = ""; + + if (values.containsKey("appgroup")) { + appgroup = (String) values.get("appgroup"); + } + + /** + * appdes from web.xml's description {org:"owner info"} + */ + String appdes = ""; + + if (values.containsKey("appdes")) { + appdes = (String) values.get("appdes"); + } + + /** + * appmetrics + */ + String appmetrics = ""; + + if (values.containsKey("appmetrics")) { + appmetrics = JSONHelper.toString(values.get("appmetrics")); + } + + /** + * appName + */ + String appName = (String) values.get("appname"); + + /** + * app root + */ + String appRoot = (String) values.get("webapproot"); + + /** + * MOF metadata + */ + String mofMeta = ""; + + if (values.containsKey("mofmeta")) { + mofMeta = JSONHelper.toString(values.get("mofmeta")); + } + + appProfile.put("appid", appid); + appProfile.put("ip", mdf.getIP()); + appProfile.put("svrid", mdf.getServerId()); + appProfile.put("host", mdf.getHost()); + appProfile.put("time", mdf.getTimeFlag()); + appProfile.put("appname", appName); + appProfile.put("appdes", appdes); + appProfile.put("appmetrics", appmetrics); + appProfile.put("appgroup", appgroup); + appProfile.put("webapproot", appRoot); + appProfile.put("appurl", appurl); + appProfile.put("mofmeta", mofMeta); + + /** + * step 1.2: cache the application clients profile data + */ + String clientsJSONstr = cacheAppClientProfileData(cm, mdf, appid, appurl, appgroup); + + /** + * Step 1.3 cache the application profile data + */ + cacheAppProfileData(cm, mdf, appProfile, clientsJSONstr, appid, appurl, appgroup); + + /** + * step 1.4: cache application ip_link & access data + */ + cacheAppIPLinkProfileData(cm, mdf, appid, appurl, appgroup); + } + } + + cm.submitBatch(); + + return newMDFs; + } + + /** + * cacheAppIPLinkProfileData + * + * @param cm + * @param mdf + * @param appid + * @param appurl + * @param appgroup + */ + @SuppressWarnings("rawtypes") + private void cacheAppIPLinkProfileData(CacheManager cm, MonitorDataFrame mdf, String appid, String appurl, + String appgroup) { + + List iplinks = mdf.getElemInstances(appid, "iplnk"); + + Map appIpLnkMap = new HashMap(); + + for (Map iplink : iplinks) { + String iplnk_id = (String) iplink.get("id"); + @SuppressWarnings("unchecked") + Map iplnk_values = (Map) iplink.get("values"); + appIpLnkMap.put(iplnk_id, JSONHelper.toString(iplnk_values)); + appIpLnkMap.put(iplnk_id + "-ts", String.valueOf(iplnk_values.get("ts"))); + } + + String iplnkfieldKey = "LNK@" + appgroup + "@" + appurl; + + cm.putHash(HealthManagerConstants.STORE_REGION_UAV, iplnkfieldKey, appIpLnkMap); + } + + /** + * cacheAppClientProfileData + * + * @param cm + * @param mdf + * @param appid + * @param appurl + * @param appgroup + */ + @SuppressWarnings("rawtypes") + private String cacheAppClientProfileData(CacheManager cm, MonitorDataFrame mdf, String appid, String appurl, + String appgroup) { + + List clients = mdf.getElemInstances(appid, "clients"); + + long checkTime = System.currentTimeMillis(); + + long expireTime = 60000; + + for (int i = 0; i < clients.size(); i++) { + + Map client = clients.get(i); + + @SuppressWarnings("unchecked") + Map cVals = (Map) client.get("values"); + + Long client_ts = (Long) cVals.get("ts"); + + if (client_ts == null) { + continue; + } + + long client_timeout = checkTime - client_ts; + + if (client_timeout < expireTime) { + cVals.put("state", "1"); + } + else if (client_timeout >= expireTime && client_timeout < expireTime * 2) { + cVals.put("state", "0"); + } + else if (client_timeout >= expireTime * 2) { + cVals.put("state", "-1"); + } + } + + String fieldKey = "C@" + appgroup + "@" + appurl; + + String clientsStr = JSONHelper.toString(clients); + + cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO_APPCLIENT, + fieldKey, clientsStr); + + return clientsStr; + } + + /** + * cache the application profile data + * + * @param cm + * @param mdf + * @param appid + */ + private void cacheAppProfileData(CacheManager cm, MonitorDataFrame mdf, Map pi, + String clientsJSONstr, String appid, String appurl, String appgroup) { - /** - * lib - */ - Map libs = mdf.getElemInstValues(appid, "jars", "lib"); + /** + * client + */ + pi.put("cpt.clients", clientsJSONstr); - pi.put("jars.lib", "@LAZY"); + /** + * lib + */ + Map libs = mdf.getElemInstValues(appid, "jars", "lib"); - /** - * NOTE:独立存储,延迟加载 - */ - String jarLib = JSONHelper.toString(libs); + pi.put("jars.lib", "@LAZY"); - /** - * logs - */ - Map logs = mdf.getElemInstValues(appid, "logs", "log4j"); + /** + * NOTE:独立存储,延迟加载 + */ + String jarLib = JSONHelper.toString(libs); - pi.put("logs.log4j", JSONHelper.toString(logs)); + /** + * logs + */ + Map logs = mdf.getElemInstValues(appid, "logs", "log4j"); - /** - * components - */ - Map> compServices = new LinkedHashMap>(); + pi.put("logs.log4j", JSONHelper.toString(logs)); - // JEE Service Components - buildJEEServiceComponents(mdf, pi, appid, appurl, compServices); + /** + * components + */ + Map> compServices = new LinkedHashMap>(); - // MSCP Service Components - buildMSCPServiceComponents(mdf, pi, appid, compServices); + // JEE Service Components + buildJEEServiceComponents(mdf, pi, appid, appurl, compServices); - // Dubbo Components - buildDubboServiceComponents(mdf, pi, appid, compServices); + // MSCP Service Components + buildMSCPServiceComponents(mdf, pi, appid, compServices); - pi.put("cpt.services", JSONHelper.toString(compServices)); + // Dubbo Components + buildDubboServiceComponents(mdf, pi, appid, compServices); - pi.put("state", "1"); + pi.put("cpt.services", JSONHelper.toString(compServices)); - /** - * use appgroup + appurl as the cache key, then we can get profile data - * by appgroup - */ - String fieldKey = appgroup + "@" + appurl; + pi.put("state", "1"); - cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO, fieldKey, - JSONHelper.toString(pi)); + /** + * use appgroup + appurl as the cache key, then we can get profile data by appgroup + */ + String fieldKey = appgroup + "@" + appurl; - /** - * NOTE: 独立存储类库,这样可以减少profile的数据量,提升加载速度,需要读取类库时再读取 - */ - cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO_JARLIB, - fieldKey, jarLib); - } + cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO, fieldKey, + JSONHelper.toString(pi)); - /** - * buildDubboServiceComponents - * - * @param mdf - * @param pi - * @param appid - * @param compServices - */ - @SuppressWarnings("unchecked") - private void buildDubboServiceComponents(MonitorDataFrame mdf, Map pi, String appid, - Map> compServices) { + /** + * NOTE: 独立存储类库,这样可以减少profile的数据量,提升加载速度,需要读取类库时再读取 + */ + cm.putHash(HealthManagerConstants.STORE_REGION_UAV, HealthManagerConstants.STORE_KEY_PROFILEINFO_JARLIB, + fieldKey, jarLib); + } - Map comps = mdf.getElemInstValues(appid, "cpt", "com.alibaba.dubbo.config.spring.ServiceBean"); + /** + * buildDubboServiceComponents + * + * @param mdf + * @param pi + * @param appid + * @param compServices + */ + @SuppressWarnings("unchecked") + private void buildDubboServiceComponents(MonitorDataFrame mdf, Map pi, String appid, + Map> compServices) { - // 获取dubbo provider的ip - String ip = mdf.getIP(); - if (comps == null || comps.size() == 0) { - return; - } + Map comps = mdf.getElemInstValues(appid, "cpt", "com.alibaba.dubbo.config.spring.ServiceBean"); - pi.put("cpt.dubbo.provider", JSONHelper.toString(comps)); + // 获取dubbo provider的ip + String ip = mdf.getIP(); + if (comps == null || comps.size() == 0) { + return; + } - for (String compName : comps.keySet()) { + pi.put("cpt.dubbo.provider", JSONHelper.toString(comps)); - Map info = (Map) comps.get(compName); + for (String compName : comps.keySet()) { - Set compServicesURLs = compServices.get(compName); + Map info = (Map) comps.get(compName); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compName, compServicesURLs); - } + Set compServicesURLs = compServices.get(compName); - String group = (String) info.get("group"); - String version = (String) info.get("version"); - String servcls = (String) info.get("servcls"); + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compName, compServicesURLs); + } - Map compMethodInfo = (Map) info.get("methods"); + String group = (String) info.get("group"); + String version = (String) info.get("version"); + String servcls = (String) info.get("servcls"); - if (compMethodInfo == null || compMethodInfo.size() == 0) { - continue; - } + Map compMethodInfo = (Map) info.get("methods"); - Map protocols = (Map) info.get("protocols"); + if (compMethodInfo == null || compMethodInfo.size() == 0) { + continue; + } - if (protocols == null || protocols.size() == 0) { - continue; - } + Map protocols = (Map) info.get("protocols"); - for (String method : compMethodInfo.keySet()) { + if (protocols == null || protocols.size() == 0) { + continue; + } - for (String protocol : protocols.keySet()) { + for (String method : compMethodInfo.keySet()) { - Map pAttrs = (Map) protocols.get(protocol); + for (String protocol : protocols.keySet()) { - Integer port = (Integer) pAttrs.get("port"); - String path = (String) pAttrs.get("path"); + Map pAttrs = (Map) protocols.get(protocol); - path = (StringHelper.isEmpty(path)) ? servcls : path; + Integer port = (Integer) pAttrs.get("port"); + String path = (String) pAttrs.get("path"); - String url = getDubboURL(ip, group, version, method, port, protocol, path); + path = (StringHelper.isEmpty(path)) ? servcls : path; - compServicesURLs.add(url); - } - } - } - } + String url = getDubboURL(ip, group, version, method, port, protocol, path); - private String getDubboURL(String ip, String group, String version, String method, Integer localPort, - String protocol, String path) { + compServicesURLs.add(url); + } + } + } + } - StringBuilder requestURL = new StringBuilder(); + private String getDubboURL(String ip, String group, String version, String method, Integer localPort, + String protocol, String path) { - requestURL.append(protocol).append("://").append(ip).append(":").append(localPort); + StringBuilder requestURL = new StringBuilder(); - if (group != null) { - requestURL.append(":").append(group); - } + requestURL.append(protocol).append("://").append(ip).append(":").append(localPort); - requestURL.append("/").append(path); + if (group != null) { + requestURL.append(":").append(group); + } - if (version != null) { - requestURL.append(".").append(version); - } + requestURL.append("/").append(path); - requestURL.append("/").append(method); + if (version != null) { + requestURL.append(".").append(version); + } - return requestURL.toString(); - } + requestURL.append("/").append(method); - /** - * buildMSCPServiceComponents - * - * @param mdf - * @param pi - * @param appid - * @param compServices - */ - @SuppressWarnings("unchecked") - private void buildMSCPServiceComponents(MonitorDataFrame mdf, Map pi, String appid, - Map> compServices) { + return requestURL.toString(); + } - // http comp - Map mscpHttp = mdf.getElemInstValues(appid, "cpt", - "com.creditease.agent.spi.AbstractBaseHttpServComponent"); + /** + * buildMSCPServiceComponents + * + * @param mdf + * @param pi + * @param appid + * @param compServices + */ + @SuppressWarnings("unchecked") + private void buildMSCPServiceComponents(MonitorDataFrame mdf, Map pi, String appid, + Map> compServices) { - if (mscpHttp != null && mscpHttp.size() > 0) { + // http comp + Map mscpHttp = mdf.getElemInstValues(appid, "cpt", + "com.creditease.agent.spi.AbstractBaseHttpServComponent"); - pi.put("cpt.mscp.http", JSONHelper.toString(mscpHttp)); + if (mscpHttp != null && mscpHttp.size() > 0) { - for (String mscpCompName : mscpHttp.keySet()) { - Map info = (Map) mscpHttp.get(mscpCompName); + pi.put("cpt.mscp.http", JSONHelper.toString(mscpHttp)); - Set compServicesURLs = compServices.get(mscpCompName); + for (String mscpCompName : mscpHttp.keySet()) { + Map info = (Map) mscpHttp.get(mscpCompName); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(mscpCompName, compServicesURLs); - } + Set compServicesURLs = compServices.get(mscpCompName); - String httpRootPath = (String) info.get("path"); + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(mscpCompName, compServicesURLs); + } - Map handlers = (Map) info.get("handlers"); + String httpRootPath = (String) info.get("path"); - for (String handlerName : handlers.keySet()) { + Map handlers = (Map) info.get("handlers"); - Map handlerInfo = (Map) handlers.get(handlerName); + for (String handlerName : handlers.keySet()) { - String handlerPath = (String) handlerInfo.get("path"); + Map handlerInfo = (Map) handlers.get(handlerName); - String serviceURL = httpRootPath + handlerPath; + String handlerPath = (String) handlerInfo.get("path"); - compServicesURLs.add(serviceURL); - } - } - } + String serviceURL = httpRootPath + handlerPath; - // timer work - Map mscpTimeWork = mdf.getElemInstValues(appid, "cpt", - "com.creditease.agent.spi.AbstractTimerWork"); + compServicesURLs.add(serviceURL); + } + } + } - if (mscpTimeWork != null && mscpTimeWork.size() > 0) { - pi.put("cpt.mscp.timework", JSONHelper.toString(mscpTimeWork)); - } - } + // timer work + Map mscpTimeWork = mdf.getElemInstValues(appid, "cpt", + "com.creditease.agent.spi.AbstractTimerWork"); - /** - * buildJEEServiceComponents - * - * @param mdf - * @param pi - * @param appid - * @param appurl - * @param compServices - */ - private void buildJEEServiceComponents(MonitorDataFrame mdf, Map pi, String appid, String appurl, - Map> compServices) { + if (mscpTimeWork != null && mscpTimeWork.size() > 0) { + pi.put("cpt.mscp.timework", JSONHelper.toString(mscpTimeWork)); + } + } - Map filters = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebFilter"); + /** + * buildJEEServiceComponents + * + * @param mdf + * @param pi + * @param appid + * @param appurl + * @param compServices + */ + private void buildJEEServiceComponents(MonitorDataFrame mdf, Map pi, String appid, String appurl, + Map> compServices) { - Map listeners = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebListener"); + Map filters = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebFilter"); - pi.put("cpt.filters", JSONHelper.toString(filters)); + Map listeners = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebListener"); - pi.put("cpt.listeners", JSONHelper.toString(listeners)); + pi.put("cpt.filters", JSONHelper.toString(filters)); - Map servlets = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebServlet"); + pi.put("cpt.listeners", JSONHelper.toString(listeners)); - // all servlet based tech - if (servlets == null || servlets.size() == 0) { - return; - } + Map servlets = mdf.getElemInstValues(appid, "cpt", "javax.servlet.annotation.WebServlet"); - // get servlets URLs - Map serviceServlets = getServletsURLs(appurl, compServices, servlets); + // all servlet based tech + if (servlets == null || servlets.size() == 0) { + return; + } - Map jaxws = mdf.getElemInstValues(appid, "cpt", "javax.jws.WebService"); + // get servlets URLs + Map serviceServlets = getServletsURLs(appurl, compServices, servlets); - String jaxwsBaseURL = serviceServlets.get("jaxws"); + Map jaxws = mdf.getElemInstValues(appid, "cpt", "javax.jws.WebService"); - // get jaxws URLs - getJAXWSURLs(compServices, jaxws, serviceServlets, appurl); + String jaxwsBaseURL = serviceServlets.get("jaxws"); - Map jaxwsProviders = mdf.getElemInstValues(appid, "cpt", "javax.xml.ws.WebServiceProvider"); + // get jaxws URLs + getJAXWSURLs(compServices, jaxws, serviceServlets, appurl); - // get jaxws provider urls - getJAXWSProviderURLs(jaxwsBaseURL, compServices, jaxwsProviders); + Map jaxwsProviders = mdf.getElemInstValues(appid, "cpt", "javax.xml.ws.WebServiceProvider"); - Map jaxrs = mdf.getElemInstValues(appid, "cpt", "javax.ws.rs.Path"); + // get jaxws provider urls + getJAXWSProviderURLs(jaxwsBaseURL, compServices, jaxwsProviders); - // get jaxrs urls - String jaxrsBaseURL = serviceServlets.get("jaxrs"); + Map jaxrs = mdf.getElemInstValues(appid, "cpt", "javax.ws.rs.Path"); - getJAXRSURLs(jaxrsBaseURL, compServices, jaxrs); + // get jaxrs urls + String jaxrsBaseURL = serviceServlets.get("jaxrs"); - Map springMVC = mdf.getElemInstValues(appid, "cpt", - "org.springframework.stereotype.Controller"); + getJAXRSURLs(jaxrsBaseURL, compServices, jaxrs); - Map springMVCRest = mdf.getElemInstValues(appid, "cpt", - "org.springframework.web.bind.annotation.RestController"); + Map springMVC = mdf.getElemInstValues(appid, "cpt", + "org.springframework.stereotype.Controller"); - // get spring mvc urls - String springmvcBaseURL = serviceServlets.get("springmvc"); + Map springMVCRest = mdf.getElemInstValues(appid, "cpt", + "org.springframework.web.bind.annotation.RestController"); - getSpringMVCURLs(springmvcBaseURL, compServices, springMVC); + // get spring mvc urls + String springmvcBaseURL = serviceServlets.get("springmvc"); - getSpringMVCURLs(springmvcBaseURL, compServices, springMVCRest); + getSpringMVCURLs(springmvcBaseURL, compServices, springMVC); - // get struts2 urls - Map strutsAction = mdf.getElemInstValues(appid, "cpt", "com.opensymphony.xwork2.Action"); - getStruts2URLs(appurl, compServices, strutsAction); + getSpringMVCURLs(springmvcBaseURL, compServices, springMVCRest); - pi.put("cpt.servlets", JSONHelper.toString(servlets)); - pi.put("cpt.jaxws", JSONHelper.toString(jaxws)); - pi.put("cpt.jaxwsP", JSONHelper.toString(jaxwsProviders)); - pi.put("cpt.jaxrs", JSONHelper.toString(jaxrs)); - pi.put("cpt.springmvc", JSONHelper.toString(springMVC)); - pi.put("cpt.springmvcRest", JSONHelper.toString(springMVCRest)); - pi.put("cpt.struts2", JSONHelper.toString(strutsAction)); - } + // get struts2 urls + Map strutsAction = mdf.getElemInstValues(appid, "cpt", "com.opensymphony.xwork2.Action"); + getStruts2URLs(appurl, compServices, strutsAction); - @SuppressWarnings({ "unchecked", "rawtypes" }) - private void getStruts2URLsByAnno(String appurl, Map> compServices, - Map strutsAction, String key, Set extSet) { + pi.put("cpt.servlets", JSONHelper.toString(servlets)); + pi.put("cpt.jaxws", JSONHelper.toString(jaxws)); + pi.put("cpt.jaxwsP", JSONHelper.toString(jaxwsProviders)); + pi.put("cpt.jaxrs", JSONHelper.toString(jaxrs)); + pi.put("cpt.springmvc", JSONHelper.toString(springMVC)); + pi.put("cpt.springmvcRest", JSONHelper.toString(springMVCRest)); + pi.put("cpt.struts2", JSONHelper.toString(strutsAction)); + } - Set compServicesURLs = compServices.get(key); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(key, compServicesURLs); - } + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void getStruts2URLsByAnno(String appurl, Map> compServices, + Map strutsAction, String key, Set extSet) { - Map valueMap = (Map) strutsAction.get(key); + Set compServicesURLs = compServices.get(key); + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(key, compServicesURLs); + } - Map methodsMap = (Map) valueMap.get("methods"); - Map classAnnoMap = (Map) valueMap.get("anno"); + Map valueMap = (Map) strutsAction.get(key); - // get namespaces - Set namespaces = new HashSet(); + Map methodsMap = (Map) valueMap.get("methods"); + Map classAnnoMap = (Map) valueMap.get("anno"); - if (classAnnoMap != null && classAnnoMap.size() > 0) { - for (Map.Entry classAnno : classAnnoMap.entrySet()) { + // get namespaces + Set namespaces = new HashSet(); - String annoKey = classAnno.getKey(); - Object annoValue = classAnno.getValue(); + if (classAnnoMap != null && classAnnoMap.size() > 0) { + for (Map.Entry classAnno : classAnnoMap.entrySet()) { - if ("org.apache.struts2.convention.annotation.Namespace".equals(annoKey)) { - namespaces.add((String) ((Map) annoValue).get("value")); - } + String annoKey = classAnno.getKey(); + Object annoValue = classAnno.getValue(); - if ("org.apache.struts2.convention.annotation.Namespaces".equals(annoKey)) { + if ("org.apache.struts2.convention.annotation.Namespace".equals(annoKey)) { + namespaces.add((String) ((Map) annoValue).get("value")); + } - List aList = (List) ((Map) annoValue).get("value"); + if ("org.apache.struts2.convention.annotation.Namespaces".equals(annoKey)) { - for (Object obj : aList) { - namespaces.add((String) ((Map) obj).get("value")); - } - } + List aList = (List) ((Map) annoValue).get("value"); - } - } else { - namespaces.add("/"); - } + for (Object obj : aList) { + namespaces.add((String) ((Map) obj).get("value")); + } + } - // get actions - Set actionNames = new HashSet(); - if (methodsMap != null) { - for (Map.Entry method : methodsMap.entrySet()) { + } + } + else { + namespaces.add("/"); + } - Map map = (Map) method.getValue(); - if (map.get("anno") == null) { - continue; - } + // get actions + Set actionNames = new HashSet(); + if (methodsMap != null) { + for (Map.Entry method : methodsMap.entrySet()) { - Map methodAnnoMap = (Map) map.get("anno"); + Map map = (Map) method.getValue(); + if (map.get("anno") == null) { + continue; + } - for (Map.Entry methodAnno : methodAnnoMap.entrySet()) { + Map methodAnnoMap = (Map) map.get("anno"); - String annoKey = methodAnno.getKey(); - Object annoValue = methodAnno.getValue(); + for (Map.Entry methodAnno : methodAnnoMap.entrySet()) { - // if have Actions annotation ignore Action annotation - if ("org.apache.struts2.convention.annotation.Actions".equals(annoKey)) { + String annoKey = methodAnno.getKey(); + Object annoValue = methodAnno.getValue(); - List aList = (List) ((Map) annoValue).get("value"); + // if have Actions annotation ignore Action annotation + if ("org.apache.struts2.convention.annotation.Actions".equals(annoKey)) { - for (Object obj : aList) { - actionNames.add((String) ((Map) obj).get("value")); - } + List aList = (List) ((Map) annoValue).get("value"); - continue; - } + for (Object obj : aList) { + actionNames.add((String) ((Map) obj).get("value")); + } - if ("org.apache.struts2.convention.annotation.Action".equals(annoKey) - && !methodAnnoMap.containsKey("org.apache.struts2.convention.annotation.Actions")) { - actionNames.add((String) ((Map) annoValue).get("value")); - } - } - } - } + continue; + } - Iterator nsIterator = namespaces.iterator(); - while (nsIterator.hasNext()) { - String ns = nsIterator.next(); + if ("org.apache.struts2.convention.annotation.Action".equals(annoKey) + && !methodAnnoMap.containsKey("org.apache.struts2.convention.annotation.Actions")) { + actionNames.add((String) ((Map) annoValue).get("value")); + } + } + } + } - if (!"/".equals(ns)) { - ns = ns + "/"; - } + Iterator nsIterator = namespaces.iterator(); + while (nsIterator.hasNext()) { + String ns = nsIterator.next(); - Iterator actionNamesIterator = actionNames.iterator(); - while (actionNamesIterator.hasNext()) { - String actionName = actionNamesIterator.next(); + if (!"/".equals(ns)) { + ns = ns + "/"; + } - Iterator extIterator = extSet.iterator(); - while (extIterator.hasNext()) { - String ext = extIterator.next(); - if (!"".equals(ext)) { - ext = "." + ext; - } - compServicesURLs.add(appurl.substring(0, appurl.length() - 1) + ns + actionName + ext); - } + Iterator actionNamesIterator = actionNames.iterator(); + while (actionNamesIterator.hasNext()) { + String actionName = actionNamesIterator.next(); - } - } - } + Iterator extIterator = extSet.iterator(); + while (extIterator.hasNext()) { + String ext = extIterator.next(); + if (!"".equals(ext)) { + ext = "." + ext; + } + compServicesURLs.add(appurl.substring(0, appurl.length() - 1) + ns + actionName + ext); + } - @SuppressWarnings("unchecked") - private void getStruts2URLsByDes(String appurl, Map> compServices, - Map strutsAction, String key, Set extSet) { + } + } + } - Set compServicesURLs = compServices.get(key); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(key, compServicesURLs); - } + @SuppressWarnings("unchecked") + private void getStruts2URLsByDes(String appurl, Map> compServices, + Map strutsAction, String key, Set extSet) { - Map valueMap = (Map) strutsAction.get(key); + Set compServicesURLs = compServices.get(key); + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(key, compServicesURLs); + } - // get action urls by des - List desList = (List) (valueMap.get("des")); - if (desList == null || desList.size() <= 0) { - return; - } + Map valueMap = (Map) strutsAction.get(key); - Iterator extIterator = extSet.iterator(); - while (extIterator.hasNext()) { - String ext = extIterator.next(); - if (!"".equals(ext)) { - ext = "." + ext; - } + // get action urls by des + List desList = (List) (valueMap.get("des")); + if (desList == null || desList.size() <= 0) { + return; + } - for (Object desObj : desList) { - Map aMap = (Map) desObj; + Iterator extIterator = extSet.iterator(); + while (extIterator.hasNext()) { + String ext = extIterator.next(); + if (!"".equals(ext)) { + ext = "." + ext; + } - String ns = (String) aMap.get("namespace"); + for (Object desObj : desList) { + Map aMap = (Map) desObj; - if (!"/".equals(ns)) { - ns = ns + "/"; - } + String ns = (String) aMap.get("namespace"); - compServicesURLs.add(appurl.substring(0, appurl.length() - 1) + ns + aMap.get("name") + ext); - } - } - } + if (!"/".equals(ns)) { + ns = ns + "/"; + } - private void getStruts2URLs(String appurl, Map> compServices, - Map strutsAction) { + compServicesURLs.add(appurl.substring(0, appurl.length() - 1) + ns + aMap.get("name") + ext); + } + } + } - for (Map.Entry entry : strutsAction.entrySet()) { + private void getStruts2URLs(String appurl, Map> compServices, + Map strutsAction) { - String key = entry.getKey(); + for (Map.Entry entry : strutsAction.entrySet()) { - if ("com.opensymphony.xwork2.ActionSupport".equals(key)) { - continue; - } + String key = entry.getKey(); - Set extSet = getStruts2URLExtension(strutsAction); - getStruts2URLsByAnno(appurl, compServices, strutsAction, key, extSet); - getStruts2URLsByDes(appurl, compServices, strutsAction, key, extSet); + if ("com.opensymphony.xwork2.ActionSupport".equals(key)) { + continue; + } - } + Set extSet = getStruts2URLExtension(strutsAction); + getStruts2URLsByAnno(appurl, compServices, strutsAction, key, extSet); + getStruts2URLsByDes(appurl, compServices, strutsAction, key, extSet); - // ignore com.opensymphony.xwork2.ActionSupport - strutsAction.remove("com.opensymphony.xwork2.ActionSupport"); - } + } - @SuppressWarnings("unchecked") - private Set getStruts2URLExtension(Map strutsAction) { + // ignore com.opensymphony.xwork2.ActionSupport + strutsAction.remove("com.opensymphony.xwork2.ActionSupport"); + } - Set extSet = new HashSet(); + @SuppressWarnings("unchecked") + private Set getStruts2URLExtension(Map strutsAction) { - for (Map.Entry entry : strutsAction.entrySet()) { + Set extSet = new HashSet(); - String key = entry.getKey(); - Object value = entry.getValue(); + for (Map.Entry entry : strutsAction.entrySet()) { - if ("com.opensymphony.xwork2.ActionSupport".equals(key)) { - continue; - } + String key = entry.getKey(); + Object value = entry.getValue(); - Map valueMap = (Map) value; + if ("com.opensymphony.xwork2.ActionSupport".equals(key)) { + continue; + } - List desList = (List) valueMap.get("des"); + Map valueMap = (Map) value; - if (desList == null) { - continue; - } + List desList = (List) valueMap.get("des"); - for (Object desObj : desList) { - Map aMap = (Map) desObj; - Object extObj = aMap.get("extension"); - if (extObj == null) { - continue; - } + if (desList == null) { + continue; + } - String[] extArr = ((String) extObj).split(","); + for (Object desObj : desList) { + Map aMap = (Map) desObj; + Object extObj = aMap.get("extension"); + if (extObj == null) { + continue; + } - List extList = Arrays.asList(extArr); + String[] extArr = ((String) extObj).split(","); - extSet.addAll(extList); + List extList = Arrays.asList(extArr); - return extSet; - } - } + extSet.addAll(extList); - if (extSet.size() <= 0) { - extSet.add("action"); - } + return extSet; + } + } - return extSet; - } + if (extSet.size() <= 0) { + extSet.add("action"); + } - /** - * getJAXWSProviderURLs - * - * @param jaxwsBaseUrl - * @param compServices - * @param jaxws - */ - @SuppressWarnings("unchecked") - private void getJAXWSProviderURLs(String jaxwsBaseUrl, Map> compServices, - Map jaxws) { + return extSet; + } - for (String compId : jaxws.keySet()) { + /** + * getJAXWSProviderURLs + * + * @param jaxwsBaseUrl + * @param compServices + * @param jaxws + */ + @SuppressWarnings("unchecked") + private void getJAXWSProviderURLs(String jaxwsBaseUrl, Map> compServices, + Map jaxws) { - Map compInfo = (Map) jaxws.get(compId); + for (String compId : jaxws.keySet()) { - Set compServicesURLs = compServices.get(compId); + Map compInfo = (Map) jaxws.get(compId); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + Set compServicesURLs = compServices.get(compId); - /** - * NODE: provider may not support description style, so only process - * annotation - */ - if (compInfo.containsKey("anno")) { + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } - Map compDesInfo = (Map) compInfo.get("anno"); + /** + * NODE: provider may not support description style, so only process annotation + */ + if (compInfo.containsKey("anno")) { - Map annoWebService = (Map) compDesInfo - .get("javax.xml.ws.WebServiceProvider"); + Map compDesInfo = (Map) compInfo.get("anno"); - String serviceName = (String) annoWebService.get("serviceName"); + Map annoWebService = (Map) compDesInfo + .get("javax.xml.ws.WebServiceProvider"); - if (StringHelper.isEmpty(serviceName)) { + String serviceName = (String) annoWebService.get("serviceName"); - String[] serviceImplClsInfo = compId.split("\\."); + if (StringHelper.isEmpty(serviceName)) { - serviceName = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; - } + String[] serviceImplClsInfo = compId.split("\\."); - String serviceURL = jaxwsBaseUrl + serviceName; - compServicesURLs.add(serviceURL); - } - } - } + serviceName = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; + } - /** - * getSpringMVCURLs - * - * @param springMVCBaseUrl - * @param compServices - * @param spring - */ - @SuppressWarnings("unchecked") - private void getSpringMVCURLs(String springMVCBaseUrl, Map> compServices, - Map spring) { + String serviceURL = jaxwsBaseUrl + serviceName; + compServicesURLs.add(serviceURL); + } + } + } - String realSpringMVCBaseUrl = null; - String suffix = ""; - if (springMVCBaseUrl != null) { + /** + * getSpringMVCURLs + * + * @param springMVCBaseUrl + * @param compServices + * @param spring + */ + @SuppressWarnings("unchecked") + private void getSpringMVCURLs(String springMVCBaseUrl, Map> compServices, + Map spring) { - // NOTE: handle *.xxx,should remove *.xxx - realSpringMVCBaseUrl = springMVCBaseUrl; + String realSpringMVCBaseUrl = null; + String suffix = ""; + if (springMVCBaseUrl != null) { - int allIndex = realSpringMVCBaseUrl.indexOf("*"); + // NOTE: handle *.xxx,should remove *.xxx + realSpringMVCBaseUrl = springMVCBaseUrl; - if (allIndex > -1) { + int allIndex = realSpringMVCBaseUrl.indexOf("*"); - // check if there is suffix, such as *.do - if (allIndex != realSpringMVCBaseUrl.length() - 1) { - suffix = realSpringMVCBaseUrl.substring(allIndex + 1); - } + if (allIndex > -1) { - // get the real access path - realSpringMVCBaseUrl = realSpringMVCBaseUrl.substring(0, allIndex); - } - } + // check if there is suffix, such as *.do + if (allIndex != realSpringMVCBaseUrl.length() - 1) { + suffix = realSpringMVCBaseUrl.substring(allIndex + 1); + } - for (String compId : spring.keySet()) { + // get the real access path + realSpringMVCBaseUrl = realSpringMVCBaseUrl.substring(0, allIndex); + } + } - Map compInfo = (Map) spring.get(compId); + for (String compId : spring.keySet()) { - Set compServicesURLs = compServices.get(compId); + Map compInfo = (Map) spring.get(compId); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + Set compServicesURLs = compServices.get(compId); - if (!compInfo.containsKey("anno")) { - continue; - } + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } - // get resourceClass path - Map compDesInfo = (Map) compInfo.get("anno"); + if (!compInfo.containsKey("anno")) { + continue; + } - List resourceClassRelativePaths = null; + // get resourceClass path + Map compDesInfo = (Map) compInfo.get("anno"); - /** - * NOTE: RequestMapping is optional to spring mvc resource class - */ + List resourceClassRelativePaths = null; - Map annoWebService = (Map) compDesInfo - .get("org.springframework.web.bind.annotation.RequestMapping"); + /** + * NOTE: RequestMapping is optional to spring mvc resource class + */ - if (annoWebService != null) { + Map annoWebService = (Map) compDesInfo + .get("org.springframework.web.bind.annotation.RequestMapping"); - resourceClassRelativePaths = (List) annoWebService.get("value"); - } + if (annoWebService != null) { - /** - * if there is no path on resource class, we take the path as "" - */ - if (resourceClassRelativePaths == null) { - resourceClassRelativePaths = new ArrayList(); - resourceClassRelativePaths.add(""); - } + resourceClassRelativePaths = (List) annoWebService.get("value"); + } - for (String resourceClassRelativePath : resourceClassRelativePaths) { + /** + * if there is no path on resource class, we take the path as "" + */ + if (resourceClassRelativePaths == null) { + resourceClassRelativePaths = new ArrayList(); + resourceClassRelativePaths.add(""); + } - resourceClassRelativePath = formatRelativePath(resourceClassRelativePath); + for (String resourceClassRelativePath : resourceClassRelativePaths) { - // get the resource class path - String resourceClassPath = realSpringMVCBaseUrl + resourceClassRelativePath; + resourceClassRelativePath = formatRelativePath(resourceClassRelativePath); - // get methods path - Map compMethodInfo = (Map) compInfo.get("methods"); + // get the resource class path + String resourceClassPath = realSpringMVCBaseUrl + resourceClassRelativePath; - for (String method : compMethodInfo.keySet()) { + // get methods path + Map compMethodInfo = (Map) compInfo.get("methods"); - Map methodInfo = (Map) compMethodInfo.get(method); + for (String method : compMethodInfo.keySet()) { - if (!methodInfo.containsKey("anno")) { - continue; - } + Map methodInfo = (Map) compMethodInfo.get(method); - Map methodAnnoInfo = (Map) methodInfo.get("anno"); + if (!methodInfo.containsKey("anno")) { + continue; + } - String serviceURL = formatRelativePath(resourceClassPath); + Map methodAnnoInfo = (Map) methodInfo.get("anno"); - /** - * each method has Path info except only one - */ - if (methodAnnoInfo.containsKey("org.springframework.web.bind.annotation.RequestMapping")) { + String serviceURL = formatRelativePath(resourceClassPath); - Map pathAnnoInfo = (Map) methodAnnoInfo - .get("org.springframework.web.bind.annotation.RequestMapping"); + /** + * each method has Path info except only one + */ + if (methodAnnoInfo.containsKey("org.springframework.web.bind.annotation.RequestMapping")) { - List methodRelativePaths = (List) pathAnnoInfo.get("value"); + Map pathAnnoInfo = (Map) methodAnnoInfo + .get("org.springframework.web.bind.annotation.RequestMapping"); - // FIX NPE - if (methodRelativePaths == null) { - compServicesURLs.add(serviceURL); - continue; - } + List methodRelativePaths = (List) pathAnnoInfo.get("value"); - for (String methodRelativePath : methodRelativePaths) { + // FIX NPE + if (methodRelativePaths == null) { + compServicesURLs.add(serviceURL); + continue; + } - methodRelativePath = formatRelativePath(methodRelativePath); + for (String methodRelativePath : methodRelativePaths) { - String methodServiceURL; + methodRelativePath = formatRelativePath(methodRelativePath); - if (methodRelativePath.endsWith(suffix)) { + String methodServiceURL; - methodServiceURL = formatRelativePath(serviceURL + "/" + methodRelativePath); - } else { - methodServiceURL = formatRelativePath(serviceURL + "/" + methodRelativePath + suffix); - } + if (methodRelativePath.endsWith(suffix)) { - compServicesURLs.add(methodServiceURL); - } - } else { - compServicesURLs.add(serviceURL); - } - } + methodServiceURL = formatRelativePath(serviceURL + "/" + methodRelativePath); + } + else { + methodServiceURL = formatRelativePath(serviceURL + "/" + methodRelativePath + suffix); + } - } - } - } + compServicesURLs.add(methodServiceURL); + } + } + else { + compServicesURLs.add(serviceURL); + } + } - /** - * getJAXRSURLs - * - * @param jaxrsBaseUrl - * @param compServices - * @param jaxrs - */ - @SuppressWarnings("unchecked") - private void getJAXRSURLs(String jaxrsBaseUrl, Map> compServices, Map jaxrs) { + } + } + } - for (String compId : jaxrs.keySet()) { + /** + * getJAXRSURLs + * + * @param jaxrsBaseUrl + * @param compServices + * @param jaxrs + */ + @SuppressWarnings("unchecked") + private void getJAXRSURLs(String jaxrsBaseUrl, Map> compServices, Map jaxrs) { - Map compInfo = (Map) jaxrs.get(compId); + for (String compId : jaxrs.keySet()) { - Set compServicesURLs = compServices.get(compId); + Map compInfo = (Map) jaxrs.get(compId); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + Set compServicesURLs = compServices.get(compId); - if (!compInfo.containsKey("anno")) { - continue; - } + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } - // get resourceClass path - Map compDesInfo = (Map) compInfo.get("anno"); + if (!compInfo.containsKey("anno")) { + continue; + } - Map annoWebService = (Map) compDesInfo.get("javax.ws.rs.Path"); + // get resourceClass path + Map compDesInfo = (Map) compInfo.get("anno"); - String resourceClassRelativePath = (String) annoWebService.get("value"); + Map annoWebService = (Map) compDesInfo.get("javax.ws.rs.Path"); - resourceClassRelativePath = formatRelativePath(resourceClassRelativePath); + String resourceClassRelativePath = (String) annoWebService.get("value"); - // get the resource class path - String resourceClassPath = jaxrsBaseUrl + resourceClassRelativePath - + ("".equalsIgnoreCase(resourceClassRelativePath) ? "" : "/"); + resourceClassRelativePath = formatRelativePath(resourceClassRelativePath); - // get methods path - Map compMethodInfo = (Map) compInfo.get("methods"); + // get the resource class path + String resourceClassPath = jaxrsBaseUrl + resourceClassRelativePath + + ("".equalsIgnoreCase(resourceClassRelativePath) ? "" : "/"); - for (String method : compMethodInfo.keySet()) { + // get methods path + Map compMethodInfo = (Map) compInfo.get("methods"); - Map methodInfo = (Map) compMethodInfo.get(method); + for (String method : compMethodInfo.keySet()) { - if (!methodInfo.containsKey("anno")) { - continue; - } + Map methodInfo = (Map) compMethodInfo.get(method); - Map methodAnnoInfo = (Map) methodInfo.get("anno"); + if (!methodInfo.containsKey("anno")) { + continue; + } - String serviceURL = resourceClassPath; + Map methodAnnoInfo = (Map) methodInfo.get("anno"); - /** - * each method has Path info except only one - */ - if (methodAnnoInfo.containsKey("javax.ws.rs.Path")) { - Map pathAnnoInfo = (Map) methodAnnoInfo.get("javax.ws.rs.Path"); + String serviceURL = resourceClassPath; - String methodRelativePath = (String) pathAnnoInfo.get("value"); + /** + * each method has Path info except only one + */ + if (methodAnnoInfo.containsKey("javax.ws.rs.Path")) { + Map pathAnnoInfo = (Map) methodAnnoInfo.get("javax.ws.rs.Path"); - methodRelativePath = formatRelativePath(methodRelativePath); + String methodRelativePath = (String) pathAnnoInfo.get("value"); - serviceURL += methodRelativePath; - } else { - serviceURL = serviceURL.substring(0, serviceURL.length() - 1); - } + methodRelativePath = formatRelativePath(methodRelativePath); - compServicesURLs.add(serviceURL); - } - } - } + serviceURL += methodRelativePath; + } + else { + serviceURL = serviceURL.substring(0, serviceURL.length() - 1); + } - /** - * getJAXWSURLs - * - * @param jaxwsBaseUrl - * @param compServices - * @param jaxws - */ - @SuppressWarnings("unchecked") - private void getJAXWSURLs(Map> compServices, Map jaxws, - Map serviceServlets, String appurl) { + compServicesURLs.add(serviceURL); + } + } + } - String jaxwsBaseUrl = serviceServlets.get("jaxws"); + /** + * getJAXWSURLs + * + * @param jaxwsBaseUrl + * @param compServices + * @param jaxws + */ + @SuppressWarnings("unchecked") + private void getJAXWSURLs(Map> compServices, Map jaxws, + Map serviceServlets, String appurl) { - for (String compId : jaxws.keySet()) { + String jaxwsBaseUrl = serviceServlets.get("jaxws"); - Map compInfo = (Map) jaxws.get(compId); + for (String compId : jaxws.keySet()) { - Set compServicesURLs = compServices.get(compId); + Map compInfo = (Map) jaxws.get(compId); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + Set compServicesURLs = compServices.get(compId); - if (compInfo.containsKey("dyn")) { + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } - Map compDesInfo = (Map) compInfo.get("dyn"); + if (compInfo.containsKey("dyn")) { - String url = (String) compDesInfo.get("url"); + Map compDesInfo = (Map) compInfo.get("dyn"); - String serviceURL = null; + String url = (String) compDesInfo.get("url"); - if (StringHelper.isEmpty(url)) { + String serviceURL = null; - String[] serviceImplClsInfo = compId.split("\\."); + if (StringHelper.isEmpty(url)) { - url = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; + String[] serviceImplClsInfo = compId.split("\\."); - serviceURL = jaxwsBaseUrl + url; + url = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; - } else if (url.startsWith("http")) { + serviceURL = jaxwsBaseUrl + url; - serviceURL = url; + } + else if (url.startsWith("http")) { - } else { + serviceURL = url; - url = this.formatRelativePath(url); - serviceURL = jaxwsBaseUrl + url; - } + } + else { - compServicesURLs.add(serviceURL); + url = this.formatRelativePath(url); + serviceURL = jaxwsBaseUrl + url; + } - } else if (compInfo.containsKey("des")) { + compServicesURLs.add(serviceURL); - Map compDesInfo = (Map) compInfo.get("des"); + } + else if (compInfo.containsKey("des")) { - String url = (String) compDesInfo.get("address"); + Map compDesInfo = (Map) compInfo.get("des"); - if (url == null) { - url = (String) compDesInfo.get("url-pattern"); - } + String url = (String) compDesInfo.get("address"); - if ("".equals(url)) { - url = "@UNKOWN_SERVICE"; - } + if (url == null) { + url = (String) compDesInfo.get("url-pattern"); + } - url = this.formatRelativePath(url); - String serviceURL = null; - if (compDesInfo.get("address") != null) { - serviceURL = jaxwsBaseUrl + url; - } else if (compDesInfo.get("url-pattern") != null) { - serviceURL = appurl + url; - } + if ("".equals(url)) { + url = "@UNKOWN_SERVICE"; + } - compServicesURLs.add(serviceURL); - } else if (compInfo.containsKey("anno")) { + url = this.formatRelativePath(url); + String serviceURL = null; + if (compDesInfo.get("address") != null) { + serviceURL = jaxwsBaseUrl + url; + } + else if (compDesInfo.get("url-pattern") != null) { + serviceURL = appurl + url; + } - Map compDesInfo = (Map) compInfo.get("anno"); + compServicesURLs.add(serviceURL); + } + else if (compInfo.containsKey("anno")) { - Map annoWebService = (Map) compDesInfo.get("javax.jws.WebService"); + Map compDesInfo = (Map) compInfo.get("anno"); - String serviceName = (String) annoWebService.get("serviceName"); + Map annoWebService = (Map) compDesInfo.get("javax.jws.WebService"); - if (StringHelper.isEmpty(serviceName)) { + String serviceName = (String) annoWebService.get("serviceName"); - String[] serviceImplClsInfo = compId.split("\\."); + if (StringHelper.isEmpty(serviceName)) { - serviceName = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; - } + String[] serviceImplClsInfo = compId.split("\\."); - String serviceURL = jaxwsBaseUrl + serviceName; - compServicesURLs.add(serviceURL); - } - } - } + serviceName = serviceImplClsInfo[serviceImplClsInfo.length - 1] + "Service"; + } - /** - * getServletsURLs - * - * @param appURL - * @param compServices - * @param servlets - * @return - */ - @SuppressWarnings("unchecked") - private Map getServletsURLs(String appURL, Map> compServices, - Map servlets) { + String serviceURL = jaxwsBaseUrl + serviceName; + compServicesURLs.add(serviceURL); + } + } + } - // temp store the service base url - Map serviceServlets = new LinkedHashMap(); + /** + * getServletsURLs + * + * @param appURL + * @param compServices + * @param servlets + * @return + */ + @SuppressWarnings("unchecked") + private Map getServletsURLs(String appURL, Map> compServices, + Map servlets) { - for (String compId : servlets.keySet()) { + // temp store the service base url + Map serviceServlets = new LinkedHashMap(); - Map compInfo = (Map) servlets.get(compId); + for (String compId : servlets.keySet()) { - Set compServicesURLs = compServices.get(compId); + Map compInfo = (Map) servlets.get(compId); - if (compServicesURLs == null) { - compServicesURLs = new HashSet(); - compServices.put(compId, compServicesURLs); - } + Set compServicesURLs = compServices.get(compId); - if (compInfo.containsKey("des")) { + if (compServicesURLs == null) { + compServicesURLs = new HashSet(); + compServices.put(compId, compServicesURLs); + } - Map compDesInfo = (Map) compInfo.get("des"); + if (compInfo.containsKey("des")) { - List urls = (List) compDesInfo.get("urlPatterns"); + Map compDesInfo = (Map) compInfo.get("des"); - if (null == urls || urls.size() == 0) { - continue; - } + List urls = (List) compDesInfo.get("urlPatterns"); - for (String url : urls) { + if (null == urls || urls.size() == 0) { + continue; + } - // remove /* for better match, will not handle *.xxxx - if (url.lastIndexOf("*") == url.length() - 1) { - url = url.substring(0, url.length() - 1); - } + for (String url : urls) { - url = formatRelativePath(url); + // remove /* for better match, will not handle *.xxxx + if (url.lastIndexOf("*") == url.length() - 1) { + url = url.substring(0, url.length() - 1); + } - String serviceURL = appURL + url; + url = formatRelativePath(url); - if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { - serviceURL = serviceURL.substring(0, serviceURL.length() - 1); - } + String serviceURL = appURL + url; - findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); + if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { + serviceURL = serviceURL.substring(0, serviceURL.length() - 1); + } - compServicesURLs.add(serviceURL); - } - } else if (compInfo.containsKey("dyn")) { + findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); - Map compDesInfo = (Map) compInfo.get("dyn"); + compServicesURLs.add(serviceURL); + } + } + else if (compInfo.containsKey("dyn")) { - List urls = (List) compDesInfo.get("urlPatterns"); + Map compDesInfo = (Map) compInfo.get("dyn"); - if (null == urls || urls.size() == 0) { - continue; - } + List urls = (List) compDesInfo.get("urlPatterns"); - for (String url : urls) { + if (null == urls || urls.size() == 0) { + continue; + } - // remove /* for better match, will not handle *.xxxx - if (url.lastIndexOf("*") == url.length() - 1) { - url = url.substring(0, url.length() - 1); - } + for (String url : urls) { - url = formatRelativePath(url); + // remove /* for better match, will not handle *.xxxx + if (url.lastIndexOf("*") == url.length() - 1) { + url = url.substring(0, url.length() - 1); + } - String serviceURL = appURL + url; + url = formatRelativePath(url); - if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { - serviceURL = serviceURL.substring(0, serviceURL.length() - 1); - } + String serviceURL = appURL + url; - findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); + if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { + serviceURL = serviceURL.substring(0, serviceURL.length() - 1); + } - compServicesURLs.add(serviceURL); - } - } else if (compInfo.containsKey("anno")) { + findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); - Map compDesInfo = (Map) compInfo.get("anno"); + compServicesURLs.add(serviceURL); + } + } + else if (compInfo.containsKey("anno")) { - for (String compDescId : compDesInfo.keySet()) { - Map compDescInfo = (Map) compDesInfo.get(compDescId); + Map compDesInfo = (Map) compInfo.get("anno"); - List urls = (List) compDescInfo.get("urlPatterns"); + for (String compDescId : compDesInfo.keySet()) { + Map compDescInfo = (Map) compDesInfo.get(compDescId); - if (null == urls || urls.size() == 0) { - urls = (List) compDescInfo.get("value"); - } + List urls = (List) compDescInfo.get("urlPatterns"); - if (null == urls || urls.size() == 0) { - continue; - } + if (null == urls || urls.size() == 0) { + urls = (List) compDescInfo.get("value"); + } - for (String url : urls) { + if (null == urls || urls.size() == 0) { + continue; + } - // remove /* for better match, will not handle *.xxxx - if (url.lastIndexOf("*") == url.length() - 1) { - url = url.substring(0, url.length() - 1); - } + for (String url : urls) { - url = formatRelativePath(url); + // remove /* for better match, will not handle *.xxxx + if (url.lastIndexOf("*") == url.length() - 1) { + url = url.substring(0, url.length() - 1); + } - String serviceURL = appURL + url; + url = formatRelativePath(url); - if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { - serviceURL = serviceURL.substring(0, serviceURL.length() - 1); - } + String serviceURL = appURL + url; - findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); + if (serviceURL.lastIndexOf("/") == serviceURL.length() - 1) { + serviceURL = serviceURL.substring(0, serviceURL.length() - 1); + } - compServicesURLs.add(serviceURL); - } - } - - } - } - - /** - * we should figure out which JAXWS,JAXRS engine is used NOTE: this is - * barely by HUMAN, not 100% right, we need refine this part TODO: need - * refine - */ - // add axis2 - if (serviceServlets.containsKey("axis2")) { - serviceServlets.put("jaxws", serviceServlets.get("axis2") + "/"); - } else if (serviceServlets.containsKey("xfire")) { - serviceServlets.put("jaxws", serviceServlets.get("xfire") + "/"); - } else if (serviceServlets.containsKey("cxf")) { - - serviceServlets.put("jaxws", serviceServlets.get("cxf") + "/"); - } else if (serviceServlets.containsKey("jaxws-ri")) { - - serviceServlets.put("jaxws", serviceServlets.get("jaxws-ri") + "/"); - } - - // add wink - if (serviceServlets.containsKey("wink")) { - serviceServlets.put("jaxrs", serviceServlets.get("wink") + "/"); - } else if (serviceServlets.containsKey("jersey")) { - serviceServlets.put("jaxrs", serviceServlets.get("jersey") + "/"); - } else if (serviceServlets.containsKey("cxf")) { - serviceServlets.put("jaxrs", serviceServlets.get("cxf") + "/"); - } - // add hession - else if (serviceServlets.containsKey("hession")) { - serviceServlets.put("jaxrs", serviceServlets.get("hession") + "/"); - } - - if (serviceServlets.containsKey("springmvc")) { - serviceServlets.put("springmvc", serviceServlets.get("springmvc") + "/"); - } - - return serviceServlets; - } - - /** - * findoutAppFrameworkServlets - * - * @param serviceServlets - * @param compId - * @param serviceURL - */ - private void findoutAppFrameworkServlets(Map serviceServlets, Map compInfo, - String serviceURL) { - - if (!compInfo.containsKey("engine")) { - return; - } - - String engine = (String) compInfo.get("engine"); - - if (engine.indexOf("cxf") > -1) { - serviceServlets.put("cxf", serviceURL); - } else if (engine.indexOf("jersey") > -1) { - serviceServlets.put("jersey", serviceURL); - } else if (engine.indexOf("springmvc") > -1) { - serviceServlets.put("springmvc", serviceURL); - } else if (engine.indexOf("jaxws-ri") > -1) { - serviceServlets.put("jaxws-ri", serviceURL); - } - } - - /** - * formatRelativePath - * - * @param resourceClassRelativePath - * @return - */ - private String formatRelativePath(String resourceClassRelativePath) { - - // remove first / - if (resourceClassRelativePath.indexOf("/") == 0) { - - if (resourceClassRelativePath.length() == 1) { - resourceClassRelativePath = ""; - } else { - resourceClassRelativePath = resourceClassRelativePath.substring(1); - } - } - - // remove last / - if (resourceClassRelativePath.lastIndexOf("/") == resourceClassRelativePath.length() - 1) { - - if (resourceClassRelativePath.length() == 1) { - resourceClassRelativePath = ""; - } else if (resourceClassRelativePath.length() > 1) { - resourceClassRelativePath = resourceClassRelativePath.substring(0, - resourceClassRelativePath.length() - 1); - } - } - return resourceClassRelativePath; - } + findoutAppFrameworkServlets(serviceServlets, compInfo, serviceURL); + + compServicesURLs.add(serviceURL); + } + } + + } + } + + /** + * we should figure out which JAXWS,JAXRS engine is used NOTE: this is barely by HUMAN, not 100% right, we need + * refine this part TODO: need refine + */ + // add axis2 + if (serviceServlets.containsKey("axis2")) { + serviceServlets.put("jaxws", serviceServlets.get("axis2") + "/"); + } + else if (serviceServlets.containsKey("xfire")) { + serviceServlets.put("jaxws", serviceServlets.get("xfire") + "/"); + } + else if (serviceServlets.containsKey("cxf")) { + + serviceServlets.put("jaxws", serviceServlets.get("cxf") + "/"); + } + else if (serviceServlets.containsKey("jaxws-ri")) { + + serviceServlets.put("jaxws", serviceServlets.get("jaxws-ri") + "/"); + } + + // add wink + if (serviceServlets.containsKey("wink")) { + serviceServlets.put("jaxrs", serviceServlets.get("wink") + "/"); + } + else if (serviceServlets.containsKey("jersey")) { + serviceServlets.put("jaxrs", serviceServlets.get("jersey") + "/"); + } + else if (serviceServlets.containsKey("cxf")) { + serviceServlets.put("jaxrs", serviceServlets.get("cxf") + "/"); + } + // add hession + else if (serviceServlets.containsKey("hession")) { + serviceServlets.put("jaxrs", serviceServlets.get("hession") + "/"); + } + + if (serviceServlets.containsKey("springmvc")) { + serviceServlets.put("springmvc", serviceServlets.get("springmvc") + "/"); + } + + return serviceServlets; + } + + /** + * findoutAppFrameworkServlets + * + * @param serviceServlets + * @param compId + * @param serviceURL + */ + private void findoutAppFrameworkServlets(Map serviceServlets, Map compInfo, + String serviceURL) { + + if (!compInfo.containsKey("engine")) { + return; + } + + String engine = (String) compInfo.get("engine"); + + if (engine.indexOf("cxf") > -1) { + serviceServlets.put("cxf", serviceURL); + } + else if (engine.indexOf("jersey") > -1) { + serviceServlets.put("jersey", serviceURL); + } + else if (engine.indexOf("springmvc") > -1) { + serviceServlets.put("springmvc", serviceURL); + } + else if (engine.indexOf("jaxws-ri") > -1) { + serviceServlets.put("jaxws-ri", serviceURL); + } + } + + /** + * formatRelativePath + * + * @param resourceClassRelativePath + * @return + */ + private String formatRelativePath(String resourceClassRelativePath) { + + // remove first / + if (resourceClassRelativePath.indexOf("/") == 0) { + + if (resourceClassRelativePath.length() == 1) { + resourceClassRelativePath = ""; + } + else { + resourceClassRelativePath = resourceClassRelativePath.substring(1); + } + } + + // remove last / + if (resourceClassRelativePath.lastIndexOf("/") == resourceClassRelativePath.length() - 1) { + + if (resourceClassRelativePath.length() == 1) { + resourceClassRelativePath = ""; + } + else if (resourceClassRelativePath.length() > 1) { + resourceClassRelativePath = resourceClassRelativePath.substring(0, + resourceClassRelativePath.length() - 1); + } + } + return resourceClassRelativePath; + } } From 6fdd767e30eee5ea75546cd34036c6cd7a3d16cd Mon Sep 17 00:00:00 2001 From: longxiao2 Date: Wed, 11 Oct 2017 14:11:48 +0800 Subject: [PATCH 06/14] =?UTF-8?q?=E5=9C=A8buildFat=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0struts2=E6=B5=8B=E8=AF=95=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...om.creditease.uav.monitorframework-1.0.jar | Bin 0 -> 60403 bytes .../lib/fast-scan.jar | Bin 0 -> 43536 bytes .../pom.xml | 26 +++++++ .../fat/struts/TestStruts2Action.java | 65 ++++++++++++++++++ .../fat/struts/TestStruts2ActionAnno.java | 34 +++++++++ .../fat/struts/TestStruts2ActionAnno2.java | 28 ++++++++ .../fat/struts/TestStruts2ActionAnno3.java | 28 ++++++++ .../fat/struts/TestStruts2ActionAnno4.java | 33 +++++++++ 8 files changed, 214 insertions(+) create mode 100644 com.creditease.uav.monitorframework.buildFat/lib/com.creditease.uav.monitorframework-1.0.jar create mode 100644 com.creditease.uav.monitorframework.buildFat/lib/fast-scan.jar create mode 100644 com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2Action.java create mode 100644 com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno.java create mode 100644 com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno2.java create mode 100644 com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno3.java create mode 100644 com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno4.java diff --git a/com.creditease.uav.monitorframework.buildFat/lib/com.creditease.uav.monitorframework-1.0.jar b/com.creditease.uav.monitorframework.buildFat/lib/com.creditease.uav.monitorframework-1.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..9a11f0f81fc44e201baff91aa3857f1aa80b3dc4 GIT binary patch literal 60403 zcmb@u18{BIvOgT#wrx8*wr$&XcC_Oi+qP|U$F`m9*iOFOd(XqUukQKYef3{ebInyX zdvuM_-Ltz#k6$l&DPRyNfWLjv+@Qt&{^O4?$gjJMh_V2!gsdpN{2ycx0H|MNj(lsH zHeZi_d|fF2olHhRRzg%nNtsSY^j2nkOj?STZU$D0mTGc*s$P*{o_YJgkw$Xz7mXCH zAO!e+focL8bq|SqYsODSWGO`@=S-?f6dY)zcxFXZZ{#t>+pi~*%ubR$yP{yhMPR1E z!C+uXrU=(4I@Jl*F{Fo{VAo_t9oik*0RJ&P003dvKd%DhYkEd@HvhSR|49M=2ZfQN ziG{JViGh>JUl61JPhuN8TMK79$G;ea_pb*T*xQ>r8vMmr;{V^V=5}^gf5CwKf5*Vd z-r_HqQ2c8qMh5oIE{-N&tFSR~vvd5bsWAT=TpUg8?VSE5SC7A#7R|rG@UIt0_^&w` z8#o&{eNE)A%!2fPGu+a~{V&$?zhd#%iy-*dvoJTXHMTZ!boz@4Q2p!C7PihNjz%W- z&i@-N)BRg~{(42&|C*Pzo!MV32IpT7baA$@{)>@+a|i$F_G}DXO>F;ynCyQNe>oev zFIQr0@po53_jm7L@>kwL@_)_apIEyXxc-B^o#X%13&h_&p|+ir>m;V8 zg5oG;QAZ2K^N2*tM$ZPx$w-g570EGdSunDR3`reTF_D~hc`H)n#L4{)V}V*DDx6KR zUi&wDZm40k{9gGS^tVw#GZ!vybn{Q?aOF59VC?m@SRL~HmsK@Gq!JzT2S-ZzZ#>~3 zRKU!IWTVTLxnVN?vN=jv2V;;cwP_^EG|aV$JQ||OMyFDKHg|75 zxYeugApa4A{vr7}r}EC5FNyDcNuJ~1mb|lxyYoNfo+v+N+sA-_15C>E@=FdSO^TL- zEfgAQ*Kb~k=z`2eX-;1(O6h)$;|lP-q%0jrbADRrJBEj=Xgl}owFd`KO5fwOVG5b) z6f*Tfe0*Mvw_StdkYnu8lzfW(eGmZe+UvGr{6FhxYg|Bl9ED zonzZ~Vp=8zl%1Dmb{IC8ckx2amRZSFLo_}XomkP#S<;Din@Q-jN({13 zEJOsR2)Tt{8ijLweG!u!Q&o(i(iX_A%9w)>a#fyssqHWc&B5Vja=F z?D&f>r1DGEB}4W))a-hHmLpU>n$tWu0Dvjtzb!{m1Easik3Z~J?bQv%4AZCU%-F0> z`d5&YPJ@Y%|9U+JK~p;=DgGS>>$df~Q0$ zJ8BZqFkTejHs{CTHO|!a9iPSN!Lz9=dowKQ+sy>~R>$L`$JS+L_vho(C7}7R45|sx zIinR9PW^=NI%8x6W>%9TO6S_Kw6D7xrWU@(!MDTO zS>L;nlIb|&6=@};zx*W@(lhJ2m5eaxXyJSWze+VV$tg+P&YozR9u*i8GG+hBYEjSJ zShwo~oh6R_nXn~MTT+o?Q+7?|%IysB{LZCx%o)JBjX4gIJe-yTGXQ>>v$bDUo~Zs~ z-eF2&xQWf0H0MtLpiOjaYJmixa()>QP`XRWG|+OmT!}ls{t;F%?qe2k5wFoISHLn^ z4yhvMu=wDygOJdkCLQfwgrrRN>@@*i9yfB)95ryakfuCL=MY@iOFd7N2s)2#8Xn9dGUAUSMq%VaQI(P0WnbxJF-rkqx&L;_rrih|$drw-k?-#F94P$M zeN?L;cx_&X&S$;Fpll>eI*016eNwR3UYdit{@|)H;*dBowehCdI}OI!G@C}&l~JQ@{XE9hp3NWZHN3*Zoq;*RAT z)Us3@MvRI(pKt`&Hifj@Dddy}&XSVNWH-C^`A7;OJFzc`8K zYsh|6bIprRHmnfk2!$aiPt- zJqa!x-9F)YX~NQggSTxRNEd11LE(aNr{VC8CZE*4M&b%WT7(!z>9J|X#|GCi^UyxQ zpiSK0uKolHXUD%JQC_9fLEWRW(4cC1WD!d8bNzdNkb?tb^g3~M1s*|qHFHDWv98N8 zYY-bn3L$CeEncH)7s#B@pzWtXcOP@FvDqHhztS~;h%9hU4@<)k#jS0g{Fx`(GXmNkBn7L=@!vZfj0 zzT}@MyD{i9V)9$#D~fN@VCgHnps+WMuFkp={;x)_zZ0f|}r zn^Z|PJt9JJIQU{uT`zdTv18A+9!J7Mb0-VTooe5EtTB$9T%7i4ebE^hJKZ+d^9jtd z+DK`xeL1e5yxQnBU`%be5e;g|vI<)v2rH_xak&?HBi=8hHePPCWH~c=Q&#p_raj0L z%GSG`Vl4YeV}B|9O~(A;={vWDjh~oWT9ttp9Ie_6nOpPpH|_RIFfL6;_l5^Xy2>CK z`JK4_J))5Q2{-u-M{v(mTyuc~J9)IU5&OG&o>iicyn(j7fj!W$_pFGVY(X^Pfy+~Q zi3ZA&^#LW5mhj4;=C501Y^X1uSz4M!zj^(j6DO@b|`Af1Gh~k(z+ZE(1OJ z9k0Fv1+ICIvv6~fd$fi2!zCZaYP~VSdilQTRHB2kyk-I4nhwqov*r>tg*{A+yR89G zd|6Zx97@97AQ8md<<@~LDUrBp`o<7H&hR~uNt2Es-<_?L{t!cLk|*W$`L13<><$26 zb0OkB5CQB5C*IJ`;ZLJevMqN6}&)}ZVoV79vj)* z@8SOTik@0?hw>#o;(K}{2P^SKxO8fJ0T6mZAkNEBn(oIjO+!TX;_$-h2|V6OVT_`5 zNV@ICQKZ|alW-5C_V_ij(R`H`Na#jC6Tsy5hvi2tMis&=G>xEC~*Z~;nYW?VXhxDeKRQzcX`(ak# z8^7h6>*&kssjU405vk1w@bP1V>ODh&QBAGeCOjHp;)By?Mag< z0dO>9uo)a9n9jHFbR|S*oCL~1fs(wrv%LajzxxhAXZ48gO(y-E>cMk zkM$G0m%I=E=JZ3|Gl?)43})>-TX+fU03I9W#7SfvI#}}Fu5HoCKFyQBN!)Nw1dL9o zPV>~HSKdBWFfDgkwd-uW=(~ljh%Zq-zJ;8$XI}}0E*+O^fnczwmyS%s$h`b2wW560 z;>TPJR3$?}ostgt=6qM8)7q1WwX85kQzM3W{WP8?F2jDCrzy{hVr*2OrBSg$zLT(6 zYymg%%8WmK`ytZuAt5rscdWKc^yU1V9kF=@Cf`oc01o*{i6 zQyp$XvNYZ>|L-Tz=VDYkT>3V~AsrMNhC2!>kf_5>^P+X1b(bsHKkM!i<1PjT7yuv_ z3;=-Vf2TX8ug!_Efur#sdzJsnm@}2vWRV3hK7zAyC>t73a)|=?Pasw05iLYuhe`xG z%m;<5gI)cD>a^UNh3O*Ya^bgG*ZKQEljBmJNVmGwlP|!O^#1~+-4ryb$j#i z0y9K|6FM`}C`a-ZT9#=}sJ0eTc?DOk1eack8qMvGHW{2znWUex+AiYF^@r!K{np|J z;S>6V+d7h*Tl_t0WNX8>7l{x6bL$Ie!OBty8%1bZS~PTeT4rGp{INSC1on`Sn+!#h z*SzG>SqdiFoz=-b;rlX#Kw}ZuHoiS(yoC8iEh+=sAEFL|c*i8H#;T)ZbzxIt8e})G z68u!AKnf(wa(8C^a&9wWsIL9qjS)VuWghqDY^oBhaP*Q?r+Ad4V!h_xRhzGRo`
  • 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 z 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
    nwf&;W>wb4Tjcc4G*QHbdQ@v`^k#$OgPztz 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 WV8GR{uP^XIkEVcg_GhDCfBhedY=SKS literal 0 HcmV?d00001 diff --git a/com.creditease.uav.monitorframework.buildFat/lib/fast-scan.jar b/com.creditease.uav.monitorframework.buildFat/lib/fast-scan.jar new file mode 100644 index 0000000000000000000000000000000000000000..560f3da8ef20ed62ba443a290d38231bedd97cd7 GIT binary patch literal 43536 zcmcG#b!;5(vaV~!F*C*Nn33n4XfCV_;lBl4GEqot|q}WnO06KRG;s08^HOg=-3exFY!bS9pI< z<^S^n1JD2a1rmRMwQ*vyvT?WeFlDm$u(PoCa5uANvNUmXH?uc!b8|Lvw{|l#adfnB zWs>~6DE42AYX4rOU}5~%eRb+vj!VL*0$X8S3P?yu45_a0s3Z!qJI)xY9g&(0P-QKu z%EXh9o7_3xF=kSaT_HmIbl%^Xgb%5{Jc9`$uymhG6bDqM>NfHFdH$H*$iw^m^LoMc zjjzMWB=R5%kQc9Rxaj_NTz7+h;;Wc5Hu>N~_|$P{ngJUenTrLH;W;QtOs`H~ir1v) zpTj4J!aJ+$Cf6}J#0-idSM%a=cqpF7av@ZuI*-vns=F2ifF@I1OoE}-U{&=gt0Pzw zf3ko~U4-j5kbw89>*yuM+%}*gX&9Q=EnJCoQjKNgBM-dD44HPCVy&KYL|~NfnQKs} zlD9!}|-nIz^~rYl3pM?z|jkaEMn82Lo60+bos< zC5WVrc_wk|xBk}FgfR>bgTAphd!jBuhI5ulShsF{{Z&M;oa?|#qJVpDxpQ;t$Yr?QSQ9i*cq-4igjI*eAOG0=Q*rm0E=J+hoz_cy_9^SMM~WQ;ViB{y4tZz`XzhaEM6a1 zDwD#V{yE)c0k_cF=a2r98=>2;WbgKoa_@;mrVeS!oD;5@Acmtn5I-TAlF8tWy7LxA ze$nTn0BAxUO5pQf>h9=l)v<#B1Dl8bPwJNZ@2i{n-|{X~-%`X7!TkWHGcq79yP~61 zMsB8qu;-#9gN031Q^R0Nyq12YA~SZ+%+en?_=7viL!m49gAt1}`NJLwZ54~ynlA24 zUrh%+e}MeijDiARAoh{J=$)B(Q$bou{ghPq=sByi7T_NZ^Ua4E~y=SrOlFbbRH zh1XIF(_=We7o8AICheYj>O67@8uQWF!K!adG^O^6=w%dWl(~pj)(rzd(pImXh)}NY zLk%a=eMWVaiJf25vzEGxRiC4ST)h^MmNCxd-cyT`uhB2;i^Cm&$F|BCHq3wxY4Q{i zh*SG}^0CBmoHmA7=Gf0)o#-;(sfGk&SsMNTfG)ew^31V6_`+GRaUArAENCOSa)!RM zOna~jklRM+vZHF*>yK~%1&LZx0px$08Dq+GFF5J%Rdg)QV{jG>HNvnAAHp^o2Tpc5 zQOb1M!)2Py0CWaT7DeKEoa#<)ROOM%pJ$Uf083^olSfQ9Jzav|)XGK6)DO{%CJkZ- zE(}j*#=vP!)bM)dOY_XL)Ty4qQu9^+HAGAkN4On0TkI=VdJm1VxL5B1<~FNIHoRwl zrCK8E13J8Cz%{S>>t{fmN{-1sLK%eYx0@qD$Nb1hik&aCubo-L2+aba6(~GOvExc5 zI0E(3MxQUy7zs`8P}PV{ z`)yv3M_0pgpMma&e2(*z#%K_ZhnlrhCG(O-(MOQyS%*^cL`BaZT*{N&l!3!wW(*~q z-?Dg8n`nwKx0v=h-&5STc0ppUq)MaAuTV5g?n5YIO>}-0TfmyTqj$s;AS?pBV4`Pk zVRp?U5jC)-TwfzZyxd|In#MbW z^Zpqy_WJydQ`Cz?uj6jLoK>nuRD2%7Eqj{zs!F z9!Z)%t+Rh*8jg9#L<2uF9w!!mA%=%*ucN||b{T(kx)o=+?=QQ_&1~7i$b{o4x`j^u zx_S;9l>==MuLt?UxwU1e$yI-QVbCvs!UEp9zGyg|GK_5PLM6OzLk2=Wf;f*4fh*`pdS3PBj{_WUTN zkS7i~&!*VMmclSEYzb4l?UV>`PI>do!OjI)^GP#$^xy^VopTJ!eLZ5DwYNXcsO&eW z>=Jdzkf^ZBs?^P|vz0JFrcyjw?Ey&4n2e|+O%=VQakN`-aNCc+E;E5{F<#t)d`|=0 z0dE!qT4l;`%1bwAU*XEn6cLs%B+TvQ4fO}KRSoq%au^vt6|}Ge48qUwMsRhED9%aa zO78QgXD>;!@^(Ppo{lJ0m*VCq8O?Lde`>CO)4qT8H{$i7538YYNuI#?zVM>@$y*Pl zq7yqWF5R9N5Pj^XU$XWr$oiToG_VCYF>2uT`?duLIy9td(D^`H3zWKbxjSIvC)2Pc zJ~Q1Li%GsNRWPcbAMJZj(w*7uKHoD(gkUjX@xLJAB=zG zEy|l0_dH$!M_hD4reucJRiF^(x()1E+uC`9h!e>sTAU{LmxhnP%2tW|4-d74)wdth91W$OHuj_J;7EV(@>TP;CDu zRI8?g7KRjNAP|Z(42`*rdUaF11nGcM|t!YG2Yl1!I{M$&CGXcRG1G8YrcS`u!; z%<$O&x-&PSzgg0AFUu7%ZS+@#DH;0H!?^2>{af>jCs{ouG}exClYH$pfvLuC7vch2&kI7) z^7Hg;_>NzG7KxN6tI81?8UKMMW@Mv(oQ~i?YClsZGWd>U2SulDy=t?u;%&th!$)vS z-Sn*brH7DcF2h7G9UD4cW4mmWB3l7e&pO@XOVG78C+?h3bX~1mJAB((syXb1Ec^%N ziNk-&`DC4X{MXGQPsL~>6&s39Jj9b4M(J=4oM^{fx&F|mE1 zmovOUYMla#bI!Qe^8hN2)=+I*Us$uMETY&7sv$n^Jl_zuAnF3IbD?VgbCM>GT=J+C z`F!t$)r^-X7tY8@AWaVQIj33znqTzqd;Bd4SDa?Q=Sb2|KF#tc=d=Sn$76_`5hLdh zCiCktN1;I?)wpXi;@9Yp^0N(zTbjwmM9DoYX>Nh$2&sTVYVio8C*mo35bczlI@da+ z^(86rJkL0Rd1^Juig$8)fcIQpQw?jFMrpFiKm_79vxbI6wFk!Cs#D7afF0YWO`0uc zUJ&ccqP1iRd2m1%{;@PD?vZO0OqDb*t9 zYKY)pU@;>8&jO46|4FH~BvAvA37~#J43|NnFY*q`#QC_S%(rJILWN*da8iVKAq7m4 zBI=RI)l;(l5;`-o?tc^$@}lAYHRb@qJxo-!2>C z?J)v#;A#Sx;Z-=|m`xf_Z%5c%_U~fHkc1{!Q2wYiOn~Sjp-ksazx}qETB(WDJEmSUXu8cd_?Cz zGjGOIT*++KaW7Q=V$g(>&{!|ROkd#a^_O6gx5CN{lbE(HCOsr-&Y>kx=<}092C5s9 zNUm|B$*{O#%bh0)Vz7G0Pb-!={BG;dm%~48edD`!tFV;L^n6s1D9Gs)d&>#%)D$J- zWm|1*qIE}$>-6H~&Q6fNUt;pulHdTb;G|Z6&DD|Szs)Q?UPH~vlEHl|fBn=$Eg_&2 zcltU633;ar2~&Khszz>LV_S+C7dXLt_G=7Grhw|_ml-}A{+!%(5q6%=(81$nWMDG+ z0TJM9!Qth1*;D=ia@mZZ2^=@rD!JB+!&@!=$3_E{PH7KGTqcJOR0Sk202~`!dy<8L zdqzv#yM7YB&X@}TlMCJH)bwX$3{#>HX73Z`QxwOtu;5FgAjUms!yN#cM!K0PJrXy6 zbA*eCgf10D=$Al}Auuf?gT}Gp^vr^3Udk-@9cc5&cXvsNaH+&kl|S*JiZ(p1bjKP= z60egUGl0aGo?w*TS+T4 zcEiA5Ts)kDJ6Vy^@lZeB{|~;r%{Hp#|Kf}1e;8jJ|CMj~{ZkQs?kE_OZe!!4AucA1 zHjwh0>fJ6V>k2QbVpJ}|#C$hQrqt2)Ji3B;Ab7^QN96uEmoJha8tZ>oKJ4_u@hOd+ z7H4hVaGMiI*yDN1b$j~WAM_46z+itdk9(D^SZ?~V@}fIh?S#M5WmIjs8h)BVf8fJ$ zpw*k)-~gIAj^yzg&_~XkkReh5)+04Cu%nbXYrNppN<2jn>Br>tTs3Z7g z>>Vd2l~ZbXYAq$N>g4SHO|ClQ2!e4Gbufo8@60N)wA9yXw@(sE(dqhYjSQ~j%L>7Fms3ske) z@I8{&b5o9=s#GhEsG!dHVSGGIb?>M_yv=qQL`$60d&(bpOH0kM=|&ZNlC*G+v0Ks~ zC^d&LAp0ea#_A)%)>WAx6W6VVf%yWrpPoEL0IEJxqbN{RW+Z7uf;q;IDh;EwgW^=} zW9=dGY_(!dwo6vf^LfNVB-s{F3Abfya>FeCYt!_m|0xLvop<$-8ZgIdHk==mDaDJH zum;^{*i}7R==2%Fh_yv8p1Q`I1@H;GY%K4&kGJX$2mE@<`h`cfu;*4;-(eEL7K~Lj z6{}-b1swiN#N2F3H@kc<+`=f86R{XO zdL%usOOMsHT>rkWdY`J42%qS;=Y%W2ti|9>jbauE`p>l*9#2_NkYnsak7IGU5aV+Q z#gMSI&pjOseAgh^eGAFv3gvg6LOMn!o`>?k06Y&VL1B-}S9DLhr!4+5-xa}d=>5-K30oWtKkta58w~8xN9UXarR^zL)@C8&8?NL0QR1EfG1G_3V${#f56Sb5 zkvloeGLkw$J&MD-=P!MW!kU$gf!jfhDw0@}B6z)?&|RKbG7exEx)9I~a1sux%+6@}!yzs{C%)+;VV>)p2z*KWzX zOD$>uyp=SuV$b-3DlUf;Zxcp{E*Eu;|E>@#=>kNA{t`><9$ z&mwx9!Dx*E#KLegEM;}!M9oMJ5|~)Q8{_h=qV9$r2hR$)&(Y_@=BOuJBmdt*HvG-X zB;Xk6EfeN*{->8bdz}tJA0ID71KijEcIIi`z_v^2Zq4bgRt1x_QVXj!A8Lk-2$M89 zzLt*DD3Wer<38m2tB`jL7+Zliry1Kiq-xg7&QG54Qv%+I+ZbFY*OP(W-9 z7<`QRdCOw>UjSWQycP!Dd~eknOo^LV9D~96#xuR`fLTbXohM;~O~r9$FW3CB_S7cM zr*WxTJl6A(P~`8E1GkfE-EiTw-YeM@$~TkhA`1%BPI|?(M0i-x@cQBj z!B?P7NFgd;mnd|y&S6x!?1#F1)UI8uBtpN;b#? z*K_-*ietmpr${2PW;bOL;Bn)_S2`_k3!78V(n1|$XrQEB0K<(w$DlW~R&W zX|sv8v$b=$WVT2}F$ETqs|HDG@oH9*#HE$ytGH;oDwP-*Z zRWuEoDONE5!q~)9(jYD7WXH51k}T6C%ICs4l)^2AZ9sA1&PV*`Rpb`n8~@;Mm%H40 zkotj!BY1QtPLFrt6E~XrfgP2a9~&^*I`KU3mzkyhh6v=S?9jz**YcT{#njr5)s$?v zEJ?_R+=P*Aor#<(*`fB+Pi2>lkXYn)l$aiKCcrpmla%v{U|pGb#o8vP2ZFa4CpU1H zk2gUh_0KyPXD{rnu=lzO(GCGDOOC&gMEs%lzz#3mBmO5-n1JG3frbPF+lTp|Ep)j4 z?RRDBdQRy7_+44;e5=HzM30ejXUmT5ir_v6brie?Ivh#>L7STAMN^EQO|0Ov+8bnF z=DMx_4eWDCtQAZpzKtn_`9_x8pFX!fHc&#rULWN8KzTeAhGR7c?XXg zY0%9baIe))eyIf~`dS$VJc`0`>8A_fyq2xi2mST+gJAL}ax>NHsT=dj1;^yB-`ypD z99?9w!@9VuUL0sZ8jx$sg^I7V>Bykbf<}%UScY3(?0ib9dp-)dYP@Y>m9ZK4ka$r* zs9CRLhiOj0)XN$@w2{hH(Fv zpr`&evoQrQDp*_;%pe?S<{-e)D~6=)Y12ZKB`8ZVX(@k(>aWbfZ7ID_u=O;A`@z2$gjQdHtyzon&d%455?o76x<|7Evc2ravKbK)!n*J~V&%E>rd$9WQRY=TTi!Rlp3lMXu{3 zqqliXc_;cwf(U>_K*eZ%o*c(Zj|juKl{tn5Q&OiuAb=OOw&6{k3{DIbl_GrQ-#&_3 zKBduKX*Km$X@b5;^*=J+jOY;!(Z<;!bAC_qJ{y& z;a)Z~m^8e&q(6(!frBP%!H8|}5pFGxBV1(jJ;M+V129lNax;&TBj>{>jlX2!&y@rXwN3S;iK9RGHr` z%+qd_=^vs(+qm-}{}tfD-)!c8a+-qY|06(|ZFVSK>mp?mVZ-H<*2+n-%3{^hFilxZ zQcd|>najiVk%Z{}1K4$v1(HT%a70w%@Q$O>mNFfZjr3nxuiQ`DW6x{XOh(|_V`5nF zz>4%5l-dD6cNb9~nk6o7`R-|;@%r}Dleh5;j2Gd-xgNzfKW5wL&|z0Jg;-$5wcE~* zS>e5_D+F@ozf2tt-EFdO6nkyEfjnR_cNlziXrF)w7R_@KaGK&Otuq6NZWEYQ}-i^lZIa!0AiMqvShgpE*yN>UVR+cJ^(_C||N&;P%Iw zJHLzhWTDT{kKk5faJBPzCjxc>Kvp_|FEFurq=7qbr&^pUaE=J%89=sx8GQbzeg;S| zJE=Qhyh8g^G_B3*{CtDk`lNRE`6((@=$CH?x93G8I4G62!-MINYE}SW$B2_8%1Q5a z7iJm`BU@zkw?43`|K@Lq%=PYwes5lst_=_SgVK^g`7b&G8Zi0iDbe`yDS?P}<_-UqHwn?Dy)c2|f`_fc-7qHH9bo!P`h^C_5|zRYbA4G_MAaSZXc9%jCjMuyYO^3wFk z4vX-9k9EHy3ph-jX3dL`CmZ*16#aF<6S1m}>4co1@uP*Wg?+P0+D%ZK)@GNNOpg)GJ_)1vn{Omn)p{2Jd?zhQX;XOdR0-+6_^om<@wTAE3jIRX*e)0FkW~+q_Vb3BE$W>69)r;Ybjf> z1ntU}4LyxywzuJ;c(Os}t>*I@y&1%5`S5m&Se_t}V_Aj424@u~Ee=|a>M9f}>hrb) z-2C^oach~6O@f!ATq5$xmPMPFy0Wt(BrfbtIyKlmn6YZc zv%HRAPA~Z(6YldkJCaU0$p7ZAPweNX7ek{Q(9Qs?t zv&rlOm9I3=sv)wXd`eTJ=p|<|vd=$UeIC-65IPptDZTeqt#j|6_(#z+jOO;27u^4` zqEP++P4ns&Ztnkw7)srWAYs&8k4U0iFdOPKwJ;!^Dj6+>oOF~hE7s1Rmd6ckC8g-HZ>-763z!}|ef=_kU}{F`%0D9 zChJK=kmPgsA^c1bhzY~N&;ArHlXzx7IAiN31!l@^qLVP^k2N^}swAAq?h0TYXm+pbhiUG$I704GbUYbeUMpqHgQuIuOeCxh$E=SwY=C-4Dwn<9kVL3^h{+cd82 zjozlowcgF84I;;j+Mmu5Lk@yo)XOKxUck-m!2Yk=tzdK)C22FhWeBXHZ_V3wI~s!R zK^iNEX;wa)LjYh_$>}S<9sh@OWN@#_{ROgLfQDPB$P-Y~iJCt}M6=l|ZI9>**%wz{ zcFii?Fe;4k=7pc_bUzb~<|aoV($jnU24lNOv37X2tg018TExwb`|RO6y7BKd4`0w1 z;=}tECel^3mJadxi8;@Fg;&EQ`>!x31Jve+B6;Zu1Bff zA(6!lz3#|1Fke^44(7w>gH@@@O(Xe`VGp6Btf3qYoZ?Zsx_K|Udiy+;5(jT#6QtB@ zix)H=CcdF|b**CP>sb1{@7@r?kWVd6U#D6Cj$eek$6(O8IjDnO0HsYdQ|g)D z@RKC5IdM^D>2sSV@TrYeiU2+`3%mrWKYJ%R#vusOXgS71{b@C9jA0Se;+G2(jpfal zgQT_FMOx$AB_UxkRcwGTBg)1g)jAlqsD3nqE93E{9&iocI36v|Or)`D=C6a}9yB)2 zgwqmPzGA=E+{3xx!0VKY@3ZkbryCKcS$cRnnJMtS)1(5rx1EQa1OAyei(GN=23Ko(bZCZV&iZI z$-1W(U8RvihWFNzGF+F<*9XHY>nC^j3c%Z{ThmnBNo93*g@C{xCIEp#5Zx9 zeMforU*93PIf7dxD1gB~p4aY&0Y4KJgZJU`9lqpJ_D~K*Eu?EJCP(T51(VF&q;e-B zNxo0pYa?E0Xpa?=v}%MRHJ}B*3S59DhS;?WZ%=KV^XG>Yy{yqZDbbncNpM_i8=`{A zYDL4ZS-BtQb61i$JKz|p(z?P#3^s~71($`IdZySr2-^z%R}*0=yw1G7-%cA5KR%05 zyTEW&s6>R0(HD9`LptOuQ=?)ws&#BqF3_s~6f+AIF)UfT)>-bgEc?2CXm~CrKy3|Z z=?s|K7GdfoNOSF2iZMA}7aPsk3O8Bnoy4$(SEih--?|p)-fHHjbRmh_ z-2v#Iv-4^$E#d)c$#rH*wf#^atrxwJws0(j}t-TVr3> zDh5FD;do(@n-R9SaNSh}@k}N#9^y9qtf5V*fzA4Ei?H<$4SJyh$4l%^*7Z?J;l0v< zwLy?CCmN1>+xyjyvOz~wXK1nJ55WEQ!4iCa$s`$r6L^dn&GiWI!E+=Yw5FwBUZdJg zgP{2^a2n0fcrK!yN{Oft;iwF%V-+CvV)<NU|%V`TaGDNqeVC(oM_ojKuHU@R=pbK|L>QT;QsaXWkm2r%}i`8<lFnPB1}7pUicpIV_!f{c99%^u zpO{>A%z{chNlu+S<-5s6CZCgFt_Q~eRF?5ix9gUK;_ZNr>H~6^lEbVxg#6ve^iSIx z_yyCrSs|nsCSdhhx1bn#@dw=xIvIU0Kpi4mFiI!E*5~JsQPvw~_Imm74>3>UCHosJ zv$FwQtA- zj2?;&JS-*s3h6*bgx1wb&&Q82Z0tT=yM#-Q_Xrgi7n(4U{B>W{ecBIcpBZug_XRhtbwFVRz+O#f$4^k{n2o3nzd8V4WrZ_u!= zfT#iw+&oL5(%QO>xUwM`HLs@<^cP<3GZoJ*_8(MdT_D@?A8pWv{aft=7q_hhB<*8< zduMsUPWee+N%33@9<=dYmtL-%=ny$GXLvb&Sm2^GH?nN+J3ZA__=_;w6_O8cOjiWw z)D^jbfcLPuEA)kpjGmmK=zyjPs4<>kL>NIw?qkYRl44OVj-ryS(=BJ!_N}j1;pWOi zEJfg?EZir~3y~8JWZ_ggna1rQi)aqY8!*%2C@2Det1pvmbD;XE*u0uX zPnQ<N3l>%KksAD`46seq9T42y)vd`mxU%j{-0X zV!lZ77Fu8K*a;oXv>L9L*x$fTSi*ejeFDZu+Zu?`LTd1~y(8h|;aj{#O@_Eqx%id! z?Agt$tkSFkaHt%JX!3B`ktt8XWn-=+hYSLY zHR6vwu^;AZt&3TCX)1$$WPk}j)P%z2(mICw0u$4%u7k8if23g=J2S^~cNa)HVXSv_ zG~Zk)Daa@LIAuIu@w^$|FaE5lu)G$*3%&f5=jGHHz+nG_0sbT(AcIE8EUls(-MC=A#y7RYx~@;tKCAvA&o)9MZT#DsJ>} zFDvGaN5lx!zFiO2q71C5?QO9oaL2AoH0E7!+PPUlNhTu^2j$knsw)K@qt}N=&_)vd zC(f9WDti0+51&wXF4m+CAXe#AN31U~2UJ(>r5H?NxY}*w=*P?lh~(?>xoeDE`a_;0 z)WFZWOEt`Lk~FG>vw9Eo$WNO~wk|2#+uS%FyYb1sfn&43o2&FKd`I=ecw)7eQyq^T z-S;Yq(h~in!E9Y{5e(uDSKx{Y<`90aGDl4=KCpNXEu@14^Exguqq`>8swg$1&6N=& z1jTV7m~DgMjrrCC;|O(UUsc(^+M$x+Bl@b8iG?seZCr-ZmF{uL9cI$z|b;}NBQ?4(plbSY8QZ6hI)=tv^oJ$iUNR0i+fUN6vbGnv!k_pN{N(ht_je*TbCB0i0C_HPCOthO&q_Yh+C5m3KKV)Z}E5>ZTp~mS%HtHTN zJ-g=yC^6$Y3Co=|EHcv*d_Q1Q4|LBhh_PFJW;wQ6W~{#ZBeTrLAs90!ITsRGOSITnjzW_l{NJ3&ok%uN*ny=!Izp@^X;7(g~%=UX1^?h*FOfE}Z@wsHo6@Hxotd zNhKn7KT+dHo4?EmiEHHHKcS=j;f{E43>rw_{aHfObhlz{?`zI#7P?d-M$taWO{v#fA5nQVS#Y`tepkS-7vGkVSnT8aDtjb@5svG2o)KlZ{}~@kS+(4Ez$+yxRMphIu&czEw1{Ot^gfEHx0?b_)p~{p~H@R zHBkdWr_B16^1;-rbXr?b0!JW&jaa(0TS(W{O+g~J-=dgoceVIVhv5;ONmAP0xUqjg z(+l?&EJB=!Y~z?Co=Isj}rPC_Xlh84gz7G^d0)O|zf2Cr|iK zI~53gxwPAeFp;kueW5M1IaG9!o)`e9hC5gll=4Nu<+69!5v{SdF@q$kQ}osadkw3~_&0R#v0hed-Dz0<8UkLsuPms8gz(_z|S^G%%!?B6=Wr8F$`R24t%dOzR zTT#OG(lf@Jj5;`kLIG_H)JOoVl}>WLR1RR_Xh`nxmE!|5NVi=f7(1zKQIu=*Pcwc{ zy!LpU=L${B?dcyx+D{Ep-}%KTx3&6Pqu)3(Tygip>Qq6nrE9Yk%>4_`Q(=ROxYi}c z0sLfX{rCp9cvoz}(OS=T_@6|dy z71ysw`qfA&jX-=>CMjz4-QdVcTuY>D#ij_Uh#PW#(-caD6YrCjGwfHK4V7#8#~>4eu#5OZ$BD{B;M%gH&fRQ2RJ)--pn%c^5%2-{1EaPZ`Q?O*AV+C+& z8{v_GQ{AW?jSm_66V9)24p05~Mt~#dR*=xr^QrUS4>VvE7`hIl0vU_-+|U%-pXI4} z?jjCNttVlp%Fgu`{mbbih9e|AEa;F|WV9*cWzStZb7$^*N$Mag`!$l!n?stE-Ca

    gY$dFQiHL4=ZyJm-oHVyjtNpDy(Kd$-e7Nv((GFrf}xC?dh%Vdy~1Yrb7 zmDXvo*l_v$;+uIiBpYjEGa4#t7cCT*t#k32j!SA6y``!&=Y{0B^3NkmEmGfx1Me6I@!fCj6wLwyKQU`FX}qn<+|i%C)lh~Ki1;gkugT< zfb}H{jBpot)i{hX=^7*M#U|pBp4Z@T9y5GQnRadyhJJl*o-&$UHa^{#;1OGT#XWeb z&eA+*b_kwP+;ww)92pK*pFPd-WV>TSxb*f_-B(-ns?kNn3cgxTIgh$SWisZPv9m^V zrsY=N)VHcX8fcmA1d8j>anLd3&Z4pUrunLDOh?GH{hm9YcWC!U?KJ1K8)(~fBf*j(3PE4|E98fd{B+Tl*BaUo1r zYt_BVm&#AVT%lveo^>M+sI_f$Iaog$*wx;70Bw)`SJkn|{KT-Dmbl)5*}>2_SK%?b zD$+UR&gXYT+<2`1C_&fXXr8-~_kOx096mhd90oCy#bRmE22 z!ml6EBsgS>xY++%NP>lbZ(IX?JIDSryV#=v3oTw8z*}#Rp~ZRF^<~TO+jbx(uoyz^ z00v9;)(8g9Ftm16^`g8c`?(r_!ZwJz6=pf0 z99};_AoAtkte@HGrtC+Octbu?%F^nit+!%PU4}<^_y)z_n;H-&>)&)JJ~4V9s#JIF zwZ!QUUXsH#qR1|E)id9a^LwLL?yZJp8^NI!SwU(>A74gP$h+oaALmAVgFn{RBF1+q zVeiJdo0QY1TNr<)+pzF%>E<+v_qm#+t zvK+QT{duDesMxbYFPHpoG0A1dK~#&xp;{3Sr-3YBN3;8c3u2Y| zY$ka}_b2~NE9&e@kgQ3epR=s|R-?%WSH5*@frE(yK+r&1D^0n%W?11yfB@b7HGcJLK z=N+d{38N1U%cQRSful`EL7XG~!H_u3nZyqzRTT6x_g>5b98LqD*cyUoc{W$>5>hCC z%>#ljo4S`Um#$q5oJ!GxnIC4QX{TGE3JW)>R_XDdY5< zdj!j<7#Opvxf>X#n;Q%mUT5~IFG5=qX_tQ&*Vb&3Un{f1Vc?W0*CscYHTp!NS1YHS zx=#j3ySisJZHt`G%9X!n14tsu<^`q;`Mi|75R=dQI3SY`V0Oqe1rU%WaSNTXGU?mm^mf>eVr?cGm1pJbUVQszysM$NyEy(V$SQRoTVtA ze!j;_f=6fG6{TRBqL7tN6->W3Gf6g`2Dk$ONa$F2&q?Uy6V;%{=MtR|1y3c{I2Lma zsp*If4CuNES)a1Kvt3M|7Hh9T%Dq!JKM$IlkDxq4cIYPc}B^LLwv`7*O^5Q2OS{t*B zmX87q*SonaeIzNKycR(UX3UzE@Lgh2jl$nMisAH<0e7VUk^(mO)^odypF>WSHE)21 zJ2n-qoyrpx+y@@v?v9&0%S4qOgn5VtM2#7drQ4OhZ?h*a@C3V-;!~ZmuyF6y z{T6N!x;cMmPOzCh=+svJ{Hh58rX$&k(IrYw-+OE&rgwEc0C5v3mg53ekfJ(2M zoGouToAYYiD@r9u0->Du^qcc;)?)p`HbGw;&a}86{x0`s4(=836!r^wjN6Y3REB9$ z$vr=aP+Wfe`1|m_{TVst<(ReDr=&?>Y{(l$FH)9hY%?iomy@~JuW7TU6%qS`Y6VF! zk~ZVndI?QiB3E}QXBCT&|3%t4$9UF!VZNs^ZQHi(?rG!Owx?~|w%t8#+qP}nw#}XQ z-E4NV+5KgaR4O+&_rE$hbx)no^V9-_rgHvDQo62Zp`loky0%4W1NGgXhJey|2@V># zMxwqC7AZ@ND~Ca~%*Z}4Gmgku(O+SPA$D`(wh}=M+E`%BB;Yt9R?vk=y>F2IRiX)x zqG%}G<4RDq3^P@BVCQHRDLukX$xW+ry2OJ`Fx-lf zf>u%6jWoZx8L{>kq|8OJH07Si`$0WbB*(!j=Lfrb9TS#LDT;9f&i_6@1uP-S1uYzM zlu^T!NmP-x^@%(KufB0)j*A&}##%AGq=|aQ|G6}3$ev&$S1)uF-53%W9fbBI#2m9UoH=(5lo<3e*bk#s zp26NhRMh(K5c+qX?irC)#AqdCCSH%nbfW+v=9ktxSo-^+G=sgEsOS?R@iY z6T@73-$>;j%vR<b#B5F3G~s%B2YWED{R5&)N{*|?9j`l{uxB}G-gD$Aq*WZ<8Au15$-Z$Z2!#5# z4ZAUkw*`sn>_+{NLr%mgvSQ#E>S+9c5N1`{$U%bvf`9FY{9H$_DewJmQK@!VLlkI2 z7g6*3sc%6e@AL#Ol>~0G0`bYhE8Bs?gA|xtZ+QFcJ+poF`Vec7C#+2XUs+$(JtsC8 z&cvrzKFRnPSNsiT0xG2r9hRRL{4REpY9t}X7tx*-Wo$l2G7FCRAU{`TsOye#hG@C3 z^iGOHHVXt@{~gVZPK$cESNqPBFmK+GF?Fvyy))XvlT6ZQIBX~HAvhGE^cEr)BiNG0 zODF><-ywM-dnXU?gzNn5UeTnuLQ4haURhTof^UOL^iIw3kVDH|2#$7mxLJtdR8$BU zYm!6e`|bFcP%gu79gcT4@sqLpy2j=4HOV8EfD3tDES?5Y(Byjar+WV?cxSBiH7Uk^ zf(%m<_=?!8GP_Wg5WR@5PGz3#IE9xeU+Uzyf_4T*wX3Zvlt~T%{@>AaAE&U2^-kL?;`J=$C`s!m+bxh+x{yZ02JNjuMwRSnTNSy0H4s3p-w4s@ zkVKM(6;~LUz-nF{diaBoQKyTRn15C$XT)m#MU&Mh`X$4Bd}XSw-v$I+E9BUXIwie- z{sAe2sty$S$m9*~t0Bbr_>QL=rxr~%u;!uSu6sqhHXrU);jG z_!L7`+7j4;zv#CH5er{@@D6<*m5db%z36?$k2KQx?3rDgBX9eT?bBh*32_+>IN$jo zrhaMKA+zaXE6>e3r|xOoT4n zA5m2<7nm-NO*h2E^-lEuvR7?KWT}GI#(6j3q8Izh!7-C=zWApjVK@0Rw5v&#Gq_O= zt(~^P#LJNloY6R9$qCc;@Bi_l~X7XjLTilnYS3srn=h2~PWZx^oWh;~ zW4gA1jB88}KkS18fG{{20zu^HpY#8!4_spN!vM-dcy@o_wYxB3f4ny5j8qR^0+OIIK{8ryH)tJS+~dmY zK^Ve-p^I(w9TybfG)&;kr=%Xj>znG*I%)hz*=;NYhgY`x>uzh!<>?QW#tvWPP6a0P zuQrzYD(;m z2Kg*-9^JKJ*3-(ioZYyaN&e=peBA-hc~;v$Ozyb{@z%*1!oOhv zDh>3|-OzwEx#>yW^N?EivR@tzhXoMvmAsqB*kfh#7vYxY zgBm7-^D)uaM*navMA%*L`~>tsXjJ)G~~vBsYRDz&sWg@fF4W|i@F z;c40FLeiG`sa@_j8#+}8vux;duM&CyH9KlD57W_zeIjViyK zO!z)TBfY-~-yXMV_hTCID+TYD_V8PGT$@-5fF4l^am=QW^_C_T{N6PivF9@t*k2!9 z850t0i~^$+MIemnCmEGNuAp6?qY=)80$DGQ5fhD^WUd5d0NNlJb)vngDwS@O0;FCc z92@1MZIC^WrJ{^4cj8Z1Ep-T4YVtk{N#u^`>ucS0^07I!J@{;_w6Z?%4}3vI@;<=1u)awtlzWk1AJ}8y~_(>C~(4!EI4kEx+C;+%LK(%VFJjJRf{L%YdLflK%aj z1NA#-WF>T%Y`Rt}*ertfh*ZoFjwd1{VSZqR71NPtoih%-W;j5yZ^q#CGRf z*>U`xZ{#fb)AG2}1M=Q#td6j`n zwxslR+`|uOM&-dAi08hjehe84pn$OwZGF>%X~R5j`44IV^CUzgvwU5JIkv<)Cb}Z3 zSu2V+&|U~j+!cE0-#QDtE^4mUVY$b2Lm3_|B)OVcQ+zqTgoDX%?)1tVLWy-m3eKKR zbjtgJy3L8%EIn1t8Ti}&uWuWBmAc65rV6>f#p_r2`Ay?QeYCn8wFB4u;vy*HG_^ov z5xBtZ>4+6>qT-G-&Gqy-e% zI175XrbSGcglDGqwC7fIQpp&Qkg$m+u7Ym48uT+K?A%A9)}5F)Ly$SMiyZj;tfetB zVj}J7q{*h9#f@Ml7;VmahEIFO5jnzVPQ%2L`U{Em-M}(?yn(X&Q;c0vsi8@Iqf4QO zC{2VY`KXf!xbhG(ssi;o>)@u8*?NM;L|c?N@vT+pehoViZsc3~dyTp5svqjVWZFY^ zFBSk3H`=974eqt1?B{qXtjm*V!M6U0@tyu>o3>X_dVDG!pTS6sJrqlCW1r z4~?57R)^dZHCJSB-BRqi*K;>|b>yy4B-;|5!DH7A4BW+^PhtNQqn^=c7>Fl3A2hVGFgK!$d0!jdX>8!HtS4C_hF?Q$t5 zG{t3Yb_RAoB9#?re$Wy9F5&?Wp95bV%a6_Hf$LB5Vvuwrnxc$iuc2hnNDBitVSuun zqp3|~uG+`*#gQt4GAuA%r%2(iW)Um3lSMF^EbJpyaD#kQ+)Unl@Vp?Q;hD~iP?TgmmKS;c6ShV%; zAO8@!qkV>Lgw#Ml3@-nP>i@@`_5au}^dQ+f&Ozc{n8o`I2!jiJ$hrE)9d zdS&{4Aq1NsYE}}2`m54m{U`*F!9en#jb*_ZV9{xIGE*H-ZqVEwM-BtW?+Ia=qJs@P zkvP@kzQ4X;|Gx0{?CJ#RA;n3TBVgF6#kIvW&cZdCrkN;B&GuPAVQ||*BK|3 z!_m(K)2z|-w_<=$!l7H?NOz-YE!GK)OhbNWu{Y~e&WaGhyi4qvd3{dg1vctJI+1eu z*iGu`r$@HT@fcU0UtV|!0li{dB=Py-HN41jzeLtR_E!~l5qu8)byQLg^9vbbP2u+s zVoyvh>4~>g^c$N7Zs--a#dox-WEI((JCr8|bDHuTP$OwZU3{t$xeD_sEIshWeoL1r zblV!Z_8uW^SPQyw6$a*z(h~?)quMH2_O5@WEtU?|7fOGz>VE{V|9hzx;Qw(U{}r@| z{j;WmPG**d|BX=})clKBE6-KCZ!+^Tp9Yd7K%UwL0g%N*bA+X1sS%_DeS`af%4Omq zBMcgmetr>7ER;Vti8 z{1>M#3+1ZUzaPuaI-_MT+rRaIIFuq6e-TW;HKWnPH&>sOP+Om=VQS3I>U8I|Fk)C$ z+dzrtTlGGn&c5ja02B%|*vVr4R@C9+t*$KSCeDHBSb~VKN`ViG{>5Ms>Hf6i5yy*} zNM$x+Bk=)c0h764mG*K@7D5oc{9^IW4I$~_F_5CF6R=H5gsv8Sm@VDV8Z-{&`XfOJ!yF%c z3uJKS!ajm z9H7$(%8ifec;@)#3IWxzV))0-%1YuN`0s)R?sB#COcwIsb{Lx_!ciKVMZ%RDpA!6a z&r|4v3+SorZSnSmbi+qU^^9;74}qaWJ>LOm@5|xbO_p;KbI_)!BT!owZYOt;vGA%f zlV?CWYFjL6s)k75#qrunUp{qng$BpQdILV4x#xTZF?;+L3<8T#Lk>B&1;vrT(!wLE zc8ygenpaLneX!Z{Gvbo+%Qw~41c&7z8twVi7nxez!m3F29w+w~P2M8G!26sMA#2ov-Zb)ZG(02HopCtdy2Eq$E*S3VF4~!4xiOt<;7i zh!~Y6QrFOL5uBkxmyJvqB*apv*}e_ylT-jbCL6#)%4?PFukr4uN?%VCoXkyj-jfQK zgm5=hw0ld7=CT00$MTW`3;xM3z;PxtBj+W=giDY>v4H%YQ&`%O?<8K|@K3k~Q#pD@tnby063m@1tgfTcn!g^yID>?(x zhLahnc~>I;h+9tO5Qx|&RQsNSdqW*7NWfNZzgbQAg@Fiz25nG*coS$ZdgG5~+{B5t zqR)|m=%Vm6j)XV3(3D0?;H!(kfu#o7K%C;mh9IJ*&6=*|Q(L-oZsoId_rf8>hmwFq z9&P`_RbvTdST=%*msyEI^r?^p@yL<{k3P6qh@@}uIn_WyF9f@)5HNKyNI{m`fJD5g zUZG%Y6NdcKQl4N1(Y|N~=Du35_4qb~=w5|dxT@`Lzu*r8zbP}x+|eAS-qow&38eTLl!rDr4Gi50kF%zAH&pAhUD2HPLUQ{1}Y7#le*{P(QMqZor`?Uz6;^CcT12p`Q4=94Jf= zGT1!b#qmm4^!N(<=b2PO^6NRj_nY|7ZfJPKWF8uH6~RH06Lx&|ONm=Il5YIr==%VP ziw(_9jY|!pBd2JGTu+g=Nz@} z5xXz=;WZ$W?V+VxOS`zPDaj&T{zOwQvGjUV`Ctr`0USj8w>3?xy0*jd%MtR zA;NTxvvk2;h*mrtK{#?GC^nAz=+k8O{KE;TCU9!aHLkTVJ&F~rriXU=s0(hw?Tf|7 zTsBN<797-jiGdpXtj&Fp0YYeCQGF#cBvqH5k1QlIQ@zmHgr4 zVuf4-ACh%~3+$KcZ#SOGN%K=vXDEJtjA&uZAS&D#qsX~T3`VTTJ}umkdN7L1-b2e& z&tEwhLiUG@tq0R#$|41g>MB_M(zymDA^j1EV#BS%T)n2^xsKu$4#r{z#6Ik{2(L9i z(d8S42SMs`BSQzPjmk(f+DQtT!jey4kahBh1QoN2c^a?3LcCm=mdr3BwLu4-EtH1c zEeQ;A7H1STUjfvWt5{B2(bP1e(CA7Johh}j_b8Tgwni64+D~@gtvo2RwSNp6$P%jD zqU^~z)YS~wiqcI*N?G8>n@XHBedd~G4+y}Un zj2VahurJK8K54e&`bZ4p&>YL@hlXZPNp3ep79*h6S-KiL9zg)d56*4LR-s~N(DV^I z`LV{6ZioBxLFyYxSf4mokp{9gJfe_0zz6CvdR%Dc?^uL;PMcaOnf`KpxKTaiB^OwH zoq%OCS1bRcgQ?kD_ofOZ$tQC|QAOJ7{i!}|%$oGB?|XkM4{W`3aCYKIiplbnE&|!A zEa!{T#3RL{IP&Yg`%omG%6;0E(NTL%&5}aGtaKo%~i5Uc!Bsbl1_}|0qte(WZ z(31rvNKj2TGyJvJ>hU!i^$9<(ZwYW4YQ_R==F9s69CP~A@jU6D{)}#9CHuMFc-_sT zqTpibw`lG0w`TiShJ7?^^jIZVuWz94$%?G8gEJb6sl3&q4&6OljB zv*8q$I=MmVglC_=aC!^GE!~0J-xK4!f?VAr^|yh4)4HtRKK%qh^(}k8Vkc?(c7FsP zLUt0`pwg1jr=ml@yGh^G3n*s6AOyM1F7a%MB-bW;`%@uIWG*{k6S$b zL_)^6Y>+FcVx{88X-rDT6cTMIB*Y%S4aiaqg&o zy>M=%^^(gsQBn4~lT|Rd6$j_T`N$T)Mq8T6)np2no#$LkV@Y|;&T@$v*BU-XS#CmZ z1;^wuGM!(^_1QQXlL0mqP9R$HSjmd_+X&g*>dAt+nD00mu%?y*L&!?aE<+bWsQPd$ z>fgOMvwMU_Td3XO)j|xVBV}45bNZnL=ws*^kW5X0e8HJs>7h!BPvz@Qs5uBQ#GuKOJleAF_&RE|JLstYt|U<^e_?V zVgnJx`-8K$dn>NDx>RU#b|0N`7&e(T(lTBUpV9eXz)4CRi34X&~|O6wIl2Np@Q^HreMchTBj_TW)j^*IvKoQSiq&H4FVnNAw^YhMA*2ZU}PpI z!W+@0SQgN&TBbbU!79-hT)<@jREqYkTPpJ+Q!46Htz;4Q%oTs86>t6tq_Fs&PUXjv96XEwmB zB3hGh=2<)2amq31Oj>=7yJJ;s5f6F>7rY@8=RDA~j%wziJVa2FGu=-*HL55g-j;e! z8}5WmrA>PNz;Uyd>X*|17orc{{HD+SX)A(o<;iV?V-2MN|khV*2nHDwm4 z4O;V&mb1(q+~5L2X=Fp;ug`7qy)Y-B@P5*k%isq>IR;SBaS>3^@##`r5%^sffNhG% zZAf3PLxi`RF|K!`hXdk&-QIi4Y1!|{X-T%T{2V+)3YS%(REQwmjSmzH}Om|GV#jEZ$--BR16#2oSpGf4o)J{({|c}M^hBcJM#p>>I$1LXXR zkVis|A4IID9_1yASoIY+_npWp2AyJ}3-s}ZDFe8A^bpr3-1^+G5LZjJk5Z80f4AiB=7)Qh3fBYjAuD%{ko57Jy?s64RGG;I!Hd_- z%`n9)(n;co3EGxVU*AF@^RiTA@%Mno5k`~s5Rz?TcONBVF{!6v8RMNBU$w0x{B%j! zAx@~Q7_QLXiML3Tr7EE_gwJyp{F6JRBqwbfL(6m@sF1R|1{q)k{Z3ekjaNn zRp$+3vF~e^<0-*Z8tAwDrG-8Hc8}bO^ox&Bswd#(+E0H4u&xKMw+7Ve#vd^xS1IhcdL+NgQX; zAEQHgV^>D-0*rKP$oed7#f{+6D=qY?>D+dnm)DK8pmuO9zHQRdvj{vZJ0C|Rwv(q3 z*?b88(to+I`RE`U_bIz=cRG+QMU7O0`~WNMa$z%g+;+UGo94(k?4>=}yyYs0zY?9p zaiwUB`%mkdtrGb}L~XV46$-gCqeBw(#QJ2%CYudzESLpA^7|p*d8DdW7w$NK1uCi%}T)-HkAw2hm+njc;4& zbF^S-lY{aHV#?uebH4|- zZkFeL;Fb(W-_2Urn4+QU0UssBBW71-tccS&gR16PLi&KojPa{3BYgbcN0!^C6*!Oe zY?8Yn2=wlGATmt$Ig4mYZ+4MXBjSyE zAuWw{EIE~Qs(9lHI>UP=!p=_*TuOUf$|WxS3cLvQv94k$Y0%xiFSbR?T2d019!iA> ztnyeiE68{Y=(;&AJ1HN&;;+4oj$jw^12wCrNFB=jl$7I|T?o!vpDl2F;u=?K%UeF9 zfFw@k(xGE9IQ(n?4b0?&<#TU$tIjWfcjq2Z>?UC|*5oCrhP}BVvhH|;74HeYw{B+c z>T%9*`i%SGVv@;$qH?OFCJR?J0iCB8niv>h!wqiTvRwm_^Gt@R8LNGXIG`f6z*5mO zxUtj@(K4k#Yl(ZJ>=4+f6f4*EUF_D0)Dk^z>m36WuOEs8(29hil zI4}T4aIDkK;MSV(x2fJ;+aJ-s)C};}193A^`8$m6`~e0#B4-{T_q)6}@Y%YAo&h2y zyPy;O`Z%)Jqa29Ea%OBvN4LvdJUA))h%IO_0}&^m0Gj^u5*ucj{&ib2>tQHQq?n=O zTMSR!@*71SwC5chKMqyHJ)XD-Wqp{XP(dvUvV9`?DDqGdHEJx|Fo=BxJ32b#lo=1= zN2|UB5%#69;aVLYKiEBKOO$Jc^$<0}uc%2$s3xk`m7>U=P$sziF-J?)=)z|~twNR^ zbJ9qQ#QIwpBam60V2h;67MWJ?X=UdVp-T-4!vtpLg|`kilR z2ya2m9=z}w@P5cdkc(UnZww=8i-TJ|vM8>UybkDOK`7D^69t^DU$g5tc3@H|j!+xo zTC&NbR_wEv`E2MN#Y=LLN0t{}91_uT6xroT4kd|hiSv3vCluc44lSel3KX>*$SfH` zm_ayxjcA$S<6+Uqw!0d6Ldjq@igcoU@susvobae!?L-k6QDp}oJa9?FhOqoWz>f0K zd%e62IGY259V}po?7^#8{9z)n`%@HQk57SGO!o8saWZgSMt- zxTZz}njO?5DCk=!f5^u{QX{JqL3r1?LR>FdW?C~R!(Q*vYjb$F0Mg(!=dM@aL{M@D zNHZ%eQXUB_(<7}`UQ){%I5$0ImnC|&#yCKr9<^-Jt%VF3Jc$23yi2M~V#bH*;^U21 z&G({T0Fdt_`ibjPy8W0p+nydfM`)uDL%HWRuABc5BD~}-*$b(`z}ouUIlC@IF7Cp& ztW3I!$=LewYx;sTh6^D8xEPNdHq_Klgfd8iZ*oV+KIyagb%95Svlvr+CIf$xuo*o% zXyFG(s@M)N-;BgwKzw-_KI4tEBp*Hj))RXU*SVy5B+r&!6%XO)viLpgnkTCBZp}+E z&g&1bX8FH#K*26=;(=vIt}A`y5Zy59QtApS+IJB0=g}xABxUXH{<|F2z1`QqZ4fU< zTbuZ4U%=e)1}K<_h&G3e)sFe9bgX8<(3!~T;3;yOEm8LUrikZ3?r@uGx@yErN+P6+2+o4S*H)oLR2JtN5OGba1y7}3Y zL^ev!n+_RJ*tSq;VKB+HAJ+0kTo*}-yCvezT+yZ8kY-iS?!ji!2b?de4)#T zYS+c>g6AKE-x2%(*9!g){Jk@53+oNMyl+y2$se-4lVXeBdEH;VBM|=Qw!JdMa*@Zd z{D=_1N_Wz0{zuyCC&=-ry@DO|!FG=9={;edcYgca6(SG;TMLAfS%!mcn z_KRJ^oP?w2i9;OqgayGp(=d6^4|RP#)9zh6SI^&7T_L6ya+2)eyuPH3@Ve5MFEC>; zc6#hta?;$orTDTPhznLq867KMl=2{FLOF?lwJ2{d$?^|766Rq`kk@i9e>eY~Rmu7e z5*zmyJQNDw^hW|-M=3vtlh%x^$t4HX>|@gN)7)eE@{hz_C{q@Jk|JcTin}>H7{$if zvZg29#IlIWvok!NdgIREOonxH_2q!$blMOs>s2N<9daBkL(HWcqGojn6m_(s;WiX3 z)R~ox;PFDZ-CN|UAjhK#7jmU^B?IJ6a=$rXjbPvU>Y{~WDrD=zSPLbe<54nlK z8Tr{5bm!f{rA1Z3Y%KnkVAR-O!^cCA8|2*r=k{d_zs_J|&2gi{IFpMgNdsQaMK$_# z`R=Rm1N{X27Nk3`$8!S`;~!)gC6k$fF;6*7ijOx?kQwK3w9nWda2wP%Z|)mhOEZYZ z&tOJsSN$d|blc(@LB_lzQuuwbEk0e%&~-Kg*d6!D__sEKG{wy~_J%cEPf`XeAJ&7K zU3RrIU9AZ2&2KQ&xpRL}VoLR;o9l|C9H4;Nx72wv{QL=CC-EYqC7~oKAwy2r2+Bxe zR;Bl1*FJD-(LY!xO@+HROh-(x{xK9Qc9TeVaoP(G2yyH~_4Zsi8>?%>>&^prvE4TF z_H3K3;eXnJ-VjOOS1z{@w^Wm==Y7FSz}X$<2gFH1kjraYJ; zp?sV4@j0Y2@`eL*fUxl1R3SV3%UyS-sMAJ5x|o_2GgD3>@v3Qoxs^nb@|K*6rko;{ z6!mD>mp@hlN;BKfFY?!0(H40vOF!e8Fu+6IUaKc&8%rH&nQ6YNfHo3WOzGeP;1C&^ znKN7k#2g7j9AdL<+3uY@JhJcKPIk((xpVE948zo%6Y*|V$Xn)1N!!kA_HQ0Dqn zMd4RZmujzG04!iwQ8Z`gG5@S=5_&U{wWbg zu0b4_HVBWd`D)QF;YqID9ANk;v@fZqgDE1|U6e9|F(;o%Cq12eEV-e|ebh^#T6S$1 zq*EvfgP41^cFCz^Q)u;rocdX6bRL(vn92P4Mn_ec*>Z^Q43 zT$NwNJBq0GoEE9KU6(@- zfS)Oph5S{BdX|U|h@F|=*19*n2yYU673$FNDYJ)9FPsk^pBdiy#`KKSVkt0IQ?TtRPK)8o(PNNVf|UU=b_A2=X}Grg|ORePMrX zmQ*(!wwdqx^YcgD4!g+Ds1Y<(!K{&jIo(=Jmfd27=oWmTzs(_qbs;r!4~GF{4pmUo z3c@T>3zIgjTe^=-V>}q41^qPdEr7{|0fOD5k6CS2McLb1W~ zm=>P8*^SFO7Czf;7lRSqKHnfcPB#ReFwmmJimVxFno|p#VtGeg?zHv8R$|o->(=(g z#^)O>K}quAWrOLBQZnH|q9UM(x+7gvsO94>hhTrjMyC)KG3R+b&q0&6Y~Qi`N0`fu zXMc>w_hj#aFAXt8!$lVlqAlVS`^JsC@+%zb(%o2CL+r;55HcrCf47gI+(lKWpi9=bp_pm|16JEOdg>e<~aJ;Xpr>`RWGO} zI*Q;5X~Pa0HvJ`#@FjIwyS8zdVgC1P<(&{winJ?l6%J8&4Cw(p)MWPE$7IfDh3Uu3A0M-W>q- z20g21P<82khUl?qFtgn>MKYouhqhzO*9o4DbGB;9iY={n1-3o&(s=;&96n=NR`%De z=Rm34eyHy5nj~i04c!#U+ zso@z=O8jXn+Lo7Ok@v(LmxykUGH{du4y9HPxbP8{@yRs14Eg9(qj)SRX`$^O3ULXf zM@k8W2V&_vLsf_H68y}lxj!VlV&x>7g`F_T7=`OCdy`M4;W7%5R8Z`YG|>>fzXxbV zXqQ?G#H`xHtkV3&(&@U>dN z(XY@XC7HZ`|NhWJ{hnPd$+HK+ciR6>k||V{Ksz@+!?bR$L3jbf4pH0U6}C=MO7ZU3 zz|I!Er$s3U>JGX*zTp=NLz$g!U;EYF1SYx3?t@ot6+NR;+GJ6nIqdbu*ApCG(%-lc zQBp8BbW>?A_=Nsf3tnvh{K@|hz*ol03ikb%`HF}9Px(gR|B?F=77+XI*``r>(gE2B z$Ghp(e7+FHG#>>7tdwL`&^!r3x->CHumOKAQAI9Rx{d@eFTJtJuqPlkjNHEnvc^5QXIHw&1BcOxoKoH9dOV z7wt1O&|9F0Q`SA!msOtYt`h5lPb}Svo8NWb zj7~*~d(GyVHZk*%*C7o&lL)d+bTRl~N-+j%fPd3;Vf9g8w1Oz<2{SB!gAr2+o}eyS zP`%A!_X&V`I7cFjHsJZF1%+$(xoZzzwXqfv`R4d<-WM6sEV0=Kcjg_B#otNl&{v-| zQ7&c8Unfh+I2KU{Qh@i5shTHStdQh@P-qv%R0nge*rAfgDj_UEgT+9BnHXprt035) zjeG7euf&)oSwdpT0QxeUYHY2}Iz=L{q#9g`8NkzA;VZ z0P*=#qMAujpRh_)U#W=Ok)YX>r`&#=dQa?FLR>3YaCeub4szOkV`SfAVVN76f~(GW z3Wz{mhe|n6(d{xpQk_oaZ44+nW}def^{a@>W$);Y(m^bW=qNpRnhWi=*HvZx{ykH^ z)z&P4L%KNC|0>x!K{gSd6#YG1_-t_eVpge{@%yLSXN$ij#P~p);yjg#ZIUC$(Q&Xa z8*z&c^7CSd<1o{$a-5!|E5E{Rtzn-dowd@YM_&qRwXD*H|J0>OKk6~*eB1)W9TgOU z5e}jYP4cO2jdL3cXvJF)_US}|TtdfBlmyw}n8KXlz0-$QY-O-=`VhL(+_%9d?UBjs zIol?M`um{_N|IuC582RPkqU==Ut{10$bm2Wjj}fQm3V=#SKCcTtlL`fH=XZ6PN7c( zPdA+@S=E0!L%tQmOjc4}z~U^XZ_X4iZ2o|oikjiMhtDRvk>v6Y&So1uYL=k|;OYG#?P`iM8(6$3B^>|F2bp1#28Po^6s=zhJ6CHAVo*m@ zNOvXTU7p}Anf#qF87@UBo#+_~Des6}T>KHk(6IfDV}kPW)9AKElwk^bSOjd_>XVmF z6ZP}Oh@V&?SY5EeU#Mj)jT*-;sz)n`Y^vFdd@1jLl8p00SC{V9n6?k zu}@&$Wt7lU_$FCdYc{)2!nf!ci%X7=!}Q%Z(J}rD_(VlNvDBHo^p;UxMFH9}*!RyM z)7+~SVe3hU3;6Isc0N)roEPtN_)9zFA&GFzmfl>O@bNgw_Q6?))FR%Hb zNmZ@w;kG~*b@Tflydq!tJ?KbEIvy?5eph-$0$0d4IzyaST|yRdZp&t`5-Lze8b3nU zjRNchB!slbiK-VTu&s}9Zy;uOw)^x1Mo@ueU(N#~Eg{ueGQ$OlhFe?x%gDb9cuqP7 zO4{;cnsKkp*LUGq;Gc_`#=ic&ty6&*SVZryJ^cyHf6C{||2O&E>K`L|TYDP=BL@c? z`~MDQ|Ld?W_utXs9$LdNVIq%prS9}>FVahXA(*&PLuB^DVt zr>r>~K%@8)1RTnK3~HGN!2S zKz|NiWpG&Gp$7d$4*|&>hKqDlt{-!kj#36L+(+_(KaVt0#nN+@s^@52=9llmryy7_ zf;=ykD7=*pFxgEO@Fiv>So81vu@KKBEtQ2Op+EuOS54>$$>|~>+89Id!ltV)K$|Kj zB&Ki!a`LJeHkVJ+&U4KS9_`np{*Uv5oN@O;tcWTvmi)kBNNJDFQr|-5s>C9QrSZCB-!l2LdwEf>Nrro72nVBfHKJJ@IdQXUuZ?9XqOWJx2;-(zlIZngi9i1^2H|KDH`viS?_TRS@Z&p{zCAdA9?@)dqQ#Z*N{ z2TTM`ehZA33c^lECQh(wh}uULcDq0sv#DR4*^n9a#e^)ea}~qXlz>P#Bb5H!dENQ^ z=<)Yrv96yr0a2jPFvW8Ril-({apiB^ljiisuV5}Z6jxe;1^Vqv%$nn5@P3QmJ+E;T~p=Xe=n3rK6{l5^P43$49RJHi$(%Z%<#mR!3M-FT>C0R zEnx4Jlu_6)7SE3FPlQhZcpr$eJe?HXB)!(%Ah5`28)iRN#zs_>Pb1gQn#uLrG`;uA!|Gw)ndKDj>gw#j|C zoITh)HnA=HgvlUJL<5;ORiKWQqn!ip<33;?ApZo%8XC`O%HQCy{g1(+_5TqZijI1Y zW(J~W)_RtrW=58V|EsLwB`+WE(;d(jpBzi_)z94xx6;ozT4`?Ou#Bke+JnnSsdVfEM_l;Sx(2vq1l4eWr);an^ zWn-%2&NyAwdM{{qoV+oexucOV356#KumI&Wv1EJN05Ha;mHUyfexi*Z!yl3@VX~on z4l)lu(r}NXlkf`53#}-FWxad@V|qhOr4f*S-&E7-+8OV*EA-OqHNYE9!+8 zD)}v*u$+vbqKcW#;U#JaN0#S48CJLEut>7;O;Ub-ucapze+|dSgVJ`K?Xb4NM0r;l zAL~Ah@IR@Xt=cUtS{;-0_RgWoPm)hiqm#VqGbXD%H|`c^GIgiSzKG8Zxw$ zq&6kk-*EXat(|u~T-)}*C0ry3qDPA;F-G(*B6@Gpi84y`7F~#F6TKTPT69A6E~1C1 zL5LQk6TJix{EobLuX6LtdpF+p@%fzjXTIyqUT5vK*V<>T?h#kQ+e}ODjHS_kU~EhB z5FxqweNmOIEEt}@5)e#`4#&jm)?k{ZzCmFHT@nhSsq3v;q~`Cf%yZ!o3gml>rHOa_ zsNy;2fLpac?@(U#_~oM?uYg$B1>1Q7x?uWCUC_LMF8l~T2v}NL9qWXZ<^Q7!Qiy;m ztf%Igm1^+Uzh9K#t3a_TL%nrX@ZfFE1T(QdaVHIR8~%4gPtWlK1-+tIAH8B4L!CDt z&CbkBZO&l4Wl+f_q^!W_S-3LT-6uR7Qj^5{QEnyMUiyIcHeoF13n*=6iLNR;A|m;AaH+dpYWy}c7}8+;{>v@@$F zMbx_n=}S7J4;oTHT_&C=UgOLBE{v(xTP5b-%_d~$Z>v>zMBxzeD+ob+bl4{~8LKv1 zr!?^{uQD_cZOSDGH_s_2SwtIe`43yLx`-asPIT-Ma=qo5MWgzzjf2+gR_H6G#-I*< z`@?H!CJ>N%3{1VyFQ@(@YlNb`p2?qYbNy`I?ZY~OHG;4uX`_&QYH{-FODEl$J7h1s zI30xaP^qXWv5+P1I!Jz6{$Rp+Fw|7nA&gVGDMmEhb`#nD8mn8W{sK zmb%HR;=tU1fM@N7*T@iX<|aC+XQelg?V|%;eqrqnQ zb0x!|n{$DknCUO4eD58KUEx7DBXF&^1=a$75QDfAbo`C{1F0hze7tJ~Bs5pcor;u; z?nS)qQQGo#?HS~oh~{I_JM;878L!eNwQnT&jQhOYkb&isebf+c8BlvtH1|**zm@GC zm{wEeNyK`G`)gX6-p0mzWRSN#V^*1;hGIvzl3c*s=D2gj(rFo(_UfSr9YRu2coS;A zY-JR)C8Ul$)y4xpLt1`7SwC5rZ%Tf1{V`iG-v=)%&zxQ4Xx#{iTlQV`N1mppreIo^ z&I0?94b?(_$i8A;ExpMrf)8y>qt(VDQ*mhBFGeAQS?{q95pD92Y*$i=C#i&=+>vol z-m#C-PC3f$edWVv`i#J7G<5f~&?}U$R80ximPl0t(}|Pnx$f7#|8cAq&%4`EVga?V z`=weaU0|&M491VZ_0NojMVOQo4l}M#$Vg}_mN@F2$RZ*K5Za@920ywKf5|AQCyxa+ zjBHTmh0D^r5b^IURH3?`$(11?$ezjCfpcU@`)hL})mHonHO)^^G?6j|jcnogZ#vTI z;ApEux2iKfGE3xXDU=rk(lyJd^jep&#MzjYwq4cv2*Xr3+|pc07GZk$fxVMTd2>m> zavCrbM#pA?qWD z)+P;CYw@PUA>;c6_|XGem)R&BJbnc;hzQ}b7Lo#MF+6;auOP$1bM1z&893SbnS(Dc zh09o0o1+~+aIAd(=oMe%S`gU;UShwb>oRsC^vGhVznvj*VBdC$eTCrdkN#eDffCn3 z|D#55{S%F_w=*%fWt6ru`q$nv>cPJn6=y_RRx{wE{jn;jV4hoW)hTrmk?Jn{{Re&C ztqTrA*Sc0Xs*9-(>D_2WaonHrw>vp#Di*l)$T)O$ICeR%@VmS1U(zM6MrJ|RWGT?f zeqz(AvM$yeP})~4=bT2`oSM~b&-l1vHJ~TBR4EMTqJgLm-D7>)Wzp<5cyIB=6*1Q7 zaY>!U9dyK2=I0DO$!$o2ljA$b8ilFVp5AEINn!qm;|FrR&=w@h2=h)Q8;Cy$2~<-aKwxmgafKya7!D_f&eh z(H^$j*H5Lx6Leb3PmZLH?yFkuqvIB&F_6F0h*M>Ry% z_hdo2guY#?Yu&u&NW2$c%G(fmBOD!#ktC%}Vqk+$5y@k2ZjM$^-4Aw%$4r%Oh$0k? z>bP+8nOu0QS(({;5HjTxCI;JF^!1mj1Y^4My(uYRAHv}IdC@oum@=}MWEmL0@sZ3f zxMmg=`X=1yu~F21nagMV7Ue4RO%zXaX@p5;u!Aat6&o7f|_?8PqeqldlfWjO5~i4LZeTu`szk1B_>aljm99+^^)60 z#!eCNCU+c=cbOu=Q-X0lF588@BwSJE40#W$0fA-J^t6W)I5; z6)g&2B;HwSrz)b|REY$sHg%-w3K}Or*j{1nD@4`T&<|fXLqNcN?6v3dv#i` zd}7erf(iA-Iou$t)#yxknkF!f_FQT|QEf8E-)-M7Gh27nfiR&Z*vrp@2pzFI;hKTa zb|*|5J-!Op6h0i6ygw^ndS6Q)TgI;7r78Ue&EBFqY_vwIU&KoT5o4jhh~Qg>d^vv5 z%V6rNEQFr5Bzu`wG}_jpP?)M}?QSWL`+)2nStX*JuVI|nJvC{Py%7jfnFGs$<$Dw^ zRbjUlAR0k^)!}JSv8T`O)p$fF3Uky-;+yoZ!X)-E6a4>x6uWJG{Qs^PFWbnA-P~s8>G45`c02G7iV~F zrzdGLH4rB8C|r_He6f2ZYwYQDkB_KjB1%~$Ej>b?2PHT}Kx4^N877B#zOQaU7aY-x zsS;8}V?=yJqXV4pdSWZAQ7ci-pcByDbA~CrFRE7PJY9U0${E2cswfM%1wDLYwlXN)Q-iny3fY&z4H8a9poUt1# z#h4xg`*&7qITaIBi>LfL(_6Xk$YeHE| z33SZ(Ls~=Pia{}Nwb2UST-PY;{(g724gw7`f#@@My2%&nKJdOs?c}O&(JGOlTR?T9 z0z6-HM*9 zmFV4@cfQbL#qc7du`|8zd3{-RH(#w-?rP`&ligfY3BCM4c}H$!j{=hv{*J2{QwN)9 z$E@6!J5IqSQAI)T?yi?~$H5jlS+~+Th$%mOL9c&tpdj1}je&ya^^B#`2OGtinurZj zeJMX)f@)(xgc~Yam>hwM+D-d-n0yFju9SmTQcD z%3|iRPa3p}4Q=db<6@%vwb(0Tcv{=LKSVo_4Kh(^$#vm8{ABZ>QAnD(hAX7Qz3V_% zqJJVotS%Zij`Yx+wPuEr91dlB_l~P^){y9pNo=p@GA}f=%Ye{0j+5e_GRibo+F7u%=?3L$h~65*HdR`i84e`5}!3If$+5cgY%NUI{tTctYPFAAh* zQi<-)wz`?P=aGmw&qjs0Ht#k&;wPP{(XFY`%o`4(HO+%5Wj><%=KazP{6eM4C4q~| zPp)kkZx>D;E+3Qz_RNgQR*kv~b{3>Y=|7O>D~?HLmMj)BP1!{|eukQtCt^DQ&qEUB zIFNqnGA;rx0xBvh!iY14SdshX6=LA&Ap-t!5r7Bn%#aaL61XEFE6OM%AS)p%qNv0m zBYN0=_FJ?ZD8wo%OV!N)LJyF@5jpb>5a82)T|q|_Vr%!qld%T+;411vEG-Qm|LMq_ z7W^2=tJ#@m2_QoOr05wWKj2_p5Xtl}LvWrcH!w}Y2>eFhub#h63ZPNy#h5HVM}FY= z=y?x7GN7GDHUdIi49WU)q?7)q9BBZ_{Wqi?=0%ZgKSySP-30gnq|o1xthg6Nvi}^} zhQu*&Tr+3_n7OkmJ41L;B*)K@qa{es-blxhQZkBx92K;1HQ(u&R9Ao@j zQ}FWwobE1s+>`layr%tM32?eY^LhU1T53WkaNz0)bV2^l=lgWcuj3MJCnF3vAn;!s zMg8MV^Z#40?fhMyKHw^KLIkcfRDTcpL$&^1TN={*1O`Hquu%j+ND&PC_{D#7=&IP7^5PG^&klSL5It-;n=Y$Nm7kO#}o| P;Li;M0m1FX@u&X-com.creditease.uav.monitorframework.buildFat 4.0.0 war + + + 2.3.15.1 + + org.apache.cxf @@ -259,6 +264,27 @@ commons-httpclient 3.0.1 + + + org.apache.struts + struts2-core + ${struts2.version} + + + org.apache.struts + struts2-convention-plugin + ${struts2.version} + + + org.apache.struts + struts2-json-plugin + ${struts2.version} + + + org.apache.struts + struts2-config-browser-plugin + ${struts2.version} + diff --git a/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2Action.java b/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2Action.java new file mode 100644 index 00000000..ee7bfb93 --- /dev/null +++ b/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2Action.java @@ -0,0 +1,65 @@ +package com.creditease.monitorframework.fat.struts; + +import java.io.IOException; +import java.io.PrintWriter; + +import org.apache.struts2.ServletActionContext; + +public class TestStruts2Action { + + public void hello() throws IOException { + + ServletActionContext.getResponse().setContentType("text/html;charset=utf-8"); + PrintWriter out = ServletActionContext.getResponse().getWriter(); + try { + out.print("TestStruts2Action hello()"); + out.flush(); + out.close(); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + + public void hello2() throws IOException { + + ServletActionContext.getResponse().setContentType("text/html;charset=utf-8"); + PrintWriter out = ServletActionContext.getResponse().getWriter(); + try { + out.print("TestStruts2Action hello2()"); + out.flush(); + out.close(); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + + public void hello3() throws IOException { + + ServletActionContext.getResponse().setContentType("text/html;charset=utf-8"); + PrintWriter out = ServletActionContext.getResponse().getWriter(); + try { + out.print("TestStruts2Action hello3()"); + out.flush(); + out.close(); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + + public void hello4() throws IOException { + + ServletActionContext.getResponse().setContentType("text/html;charset=utf-8"); + PrintWriter out = ServletActionContext.getResponse().getWriter(); + try { + out.print("TestStruts2Action hello4()"); + out.flush(); + out.close(); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } +} diff --git a/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno.java b/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno.java new file mode 100644 index 00000000..4d12d6e7 --- /dev/null +++ b/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno.java @@ -0,0 +1,34 @@ +package com.creditease.monitorframework.fat.struts; + +import java.io.IOException; +import java.io.PrintWriter; + +import org.apache.struts2.ServletActionContext; +import org.apache.struts2.convention.annotation.Action; +import org.apache.struts2.convention.annotation.Actions; +import org.apache.struts2.convention.annotation.Namespace; +import org.apache.struts2.convention.annotation.Namespaces; + +import com.opensymphony.xwork2.ActionSupport; + +@Namespaces({ @Namespace("/a"), @Namespace("/b") }) +@Namespace("/anno") +public class TestStruts2ActionAnno extends ActionSupport { + + @Actions({ @Action("aa"), @Action("bb") }) + @Action("anno1") + public void anno1() throws IOException { + + ServletActionContext.getResponse().setContentType("text/html;charset=utf-8"); + PrintWriter out = ServletActionContext.getResponse().getWriter(); + try { + out.print("TestStruts2ActionAnno anno1()"); + out.flush(); + out.close(); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + +} diff --git a/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno2.java b/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno2.java new file mode 100644 index 00000000..a4e11036 --- /dev/null +++ b/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno2.java @@ -0,0 +1,28 @@ +package com.creditease.monitorframework.fat.struts; + +import java.io.IOException; +import java.io.PrintWriter; + +import org.apache.struts2.ServletActionContext; +import org.apache.struts2.convention.annotation.Action; + +import com.opensymphony.xwork2.ActionSupport; + +public class TestStruts2ActionAnno2 extends ActionSupport { + + @Action("anno2") + public void anno2() throws IOException { + + ServletActionContext.getResponse().setContentType("text/html;charset=utf-8"); + PrintWriter out = ServletActionContext.getResponse().getWriter(); + try { + out.print("TestStruts2ActionAnno2 anno2()"); + out.flush(); + out.close(); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + +} diff --git a/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno3.java b/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno3.java new file mode 100644 index 00000000..d99ad0fa --- /dev/null +++ b/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno3.java @@ -0,0 +1,28 @@ +package com.creditease.monitorframework.fat.struts; + +import java.io.IOException; +import java.io.PrintWriter; + +import org.apache.struts2.ServletActionContext; +import org.apache.struts2.convention.annotation.Action; + +import com.opensymphony.xwork2.ActionSupport; + +public class TestStruts2ActionAnno3 extends ActionSupport { + + @Action("anno3") + public void anno3() throws IOException { + + ServletActionContext.getResponse().setContentType("text/html;charset=utf-8"); + PrintWriter out = ServletActionContext.getResponse().getWriter(); + try { + out.print("TestStruts2ActionAnno3 anno3()"); + out.flush(); + out.close(); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + +} diff --git a/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno4.java b/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno4.java new file mode 100644 index 00000000..3aecf087 --- /dev/null +++ b/com.creditease.uav.monitorframework.buildFat/src/main/java/com/creditease/monitorframework/fat/struts/TestStruts2ActionAnno4.java @@ -0,0 +1,33 @@ +package com.creditease.monitorframework.fat.struts; + +import java.io.IOException; +import java.io.PrintWriter; + +import org.apache.struts2.ServletActionContext; +import org.apache.struts2.convention.annotation.Action; +import org.apache.struts2.convention.annotation.InterceptorRef; +import org.apache.struts2.convention.annotation.Result; + +import com.opensymphony.xwork2.ActionSupport; + +public class TestStruts2ActionAnno4 extends ActionSupport { + + @Action(value = "anno4", interceptorRefs = @InterceptorRef("auth"), results = { + @Result(type = "stream", params = { "inputName", "inputStream", "contentDisposition", + "attachment;filename=\"${downloadFileName}\"", "bufferSize", "512" }) }, params = {}) + // @Action(value = "anno4") + public void anno4() throws IOException { + + ServletActionContext.getResponse().setContentType("text/html;charset=utf-8"); + PrintWriter out = ServletActionContext.getResponse().getWriter(); + try { + out.print("TestStruts2ActionAnno4 anno4()"); + out.flush(); + out.close(); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + +} From f81c91a29a2566bf1368c4596509a4ae3ae5689e Mon Sep 17 00:00:00 2001 From: "yangminglang816@163.com" Date: Thu, 12 Oct 2017 11:35:50 +0800 Subject: [PATCH 07/14] =?UTF-8?q?=E4=BF=AE=E6=94=B9healthmanager=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=96=87=E4=BB=B6=EF=BC=8C=E9=9D=9E=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E5=AE=B9=E5=99=A8=E8=8A=82=E7=82=B9=E4=B8=AD=E5=B0=86Node?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=98=AF=E5=90=A6=E6=B6=88=E8=B4=B9=E7=BD=AE?= =?UTF-8?q?=E4=B8=BAfalse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/hm_pro_apphubmgr.properties | 7 +++++-- .../config/hm_pro_logserver.properties | 3 +++ .../config/hm_pro_moserver.properties | 9 ++++++--- .../config/hm_pro_nodeserver.properties | 2 +- .../config/hm_pro_pfntfyserver.properties | 7 +++++-- .../config/hm_test_logserver.properties | 7 +++++-- .../config/hm_test_moserver.properties | 3 +++ .../config/hm_test_nodeserver.properties | 2 +- .../config/hm_test_pnhbserver.properties | 7 +++++-- 9 files changed, 34 insertions(+), 13 deletions(-) diff --git a/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_apphubmgr.properties b/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_apphubmgr.properties index 114787ef..87d8f50b 100644 --- a/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_apphubmgr.properties +++ b/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_apphubmgr.properties @@ -98,18 +98,21 @@ feature.healthmanager.components=com.creditease.uav.feature.HealthManager feature.healthmanager.properties= #feature.xxx. feature.healthmanager.messagingnameserver=127.0.0.1:9876;127.0.0.1:9876;127.0.0.1:9876 -feature.healthmanager.MT_Monitor.consumethreadmax=5 +feature.healthmanager.MT_Monitor.consumethreadmax=10 feature.healthmanager.MT_Notify.consumethreadmax=10 feature.healthmanager.MT_Profile.consumethreadmax=10 -feature.healthmanager.MT_Log.consumethreadmax=5 +feature.healthmanager.MT_Log.consumethreadmax=10 +feature.healthmanager.MT_Node.consumethreadmax=10 feature.healthmanager.MT_Monitorconsumestopinterval=0 feature.healthmanager.MT_Notify.consumestopinterval=0 feature.healthmanager.MT_Profile.consumestopinterval=0 feature.healthmanager.MT_Log.consumestopinterval=0 +feature.healthmanager.MT_Node.consumestopinterval=0 feature.healthmanager.MT_Monitor.enable=false feature.healthmanager.MT_Notify.enable=false feature.healthmanager.MT_Profile.enable=false feature.healthmanager.MT_Log.enable=false +feature.healthmanager.MT_Node.enable=false #feature.healthmanager.healthmanger handlers feature.healthmanager.healthMangerHandlers=com.creditease.uav.feature.healthmanager.http.handlers.HMDataStoreQueryHandler,com.creditease.uav.feature.healthmanager.http.handlers.HMCacheQueryHandler feature.healthmanager.http.port=8044 diff --git a/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_logserver.properties b/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_logserver.properties index 5d25f424..ad29351d 100644 --- a/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_logserver.properties +++ b/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_logserver.properties @@ -83,14 +83,17 @@ feature.healthmanager.MT_Monitor.consumethreadmax=5 feature.healthmanager.MT_Notify.consumethreadmax=5 feature.healthmanager.MT_Profile.consumethreadmax=5 feature.healthmanager.MT_Log.consumethreadmax=20 +feature.healthmanager.MT_Node.consumethreadmax=10 feature.healthmanager.MT_Monitorconsumestopinterval=0 feature.healthmanager.MT_Notify.consumestopinterval=0 feature.healthmanager.MT_Profile.consumestopinterval=0 feature.healthmanager.MT_Log.consumestopinterval=0 +feature.healthmanager.MT_Node.consumestopinterval=0 feature.healthmanager.MT_Monitor.enable=false feature.healthmanager.MT_Notify.enable=false feature.healthmanager.MT_Profile.enable=false feature.healthmanager.MT_Log.enable=true +feature.healthmanager.MT_Node.enable=false #feature.healthmanager.healthmanger handlers feature.healthmanager.healthMangerHandlers=com.creditease.uav.feature.healthmanager.http.handlers.HMDataStoreQueryHandler,com.creditease.uav.feature.healthmanager.http.handlers.HMCacheQueryHandler feature.healthmanager.http.port=8041 diff --git a/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_moserver.properties b/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_moserver.properties index 64c331ca..7bed4cb7 100644 --- a/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_moserver.properties +++ b/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_moserver.properties @@ -81,17 +81,20 @@ feature.healthmanager.properties= #feature.xxx. feature.healthmanager.messagingnameserver=127.0.0.1:9876;127.0.0.1:9876;127.0.0.1:9876 feature.healthmanager.MT_Monitor.consumethreadmax=50 -feature.healthmanager.MT_Notify.consumethreadmax=5 -feature.healthmanager.MT_Profile.consumethreadmax=5 -feature.healthmanager.MT_Log.consumethreadmax=5 +feature.healthmanager.MT_Notify.consumethreadmax=10 +feature.healthmanager.MT_Profile.consumethreadmax=10 +feature.healthmanager.MT_Log.consumethreadmax=10 +feature.healthmanager.MT_Node.consumethreadmax=10 feature.healthmanager.MT_Monitorconsumestopinterval=0 feature.healthmanager.MT_Notify.consumestopinterval=0 feature.healthmanager.MT_Profile.consumestopinterval=0 feature.healthmanager.MT_Log.consumestopinterval=0 +feature.healthmanager.MT_Node.consumestopinterval=0 feature.healthmanager.MT_Monitor.enable=true feature.healthmanager.MT_Notify.enable=false feature.healthmanager.MT_Profile.enable=false feature.healthmanager.MT_Log.enable=false +feature.healthmanager.MT_Node.enable=false #feature.healthmanager.healthmanger handlers feature.healthmanager.healthMangerHandlers=com.creditease.uav.feature.healthmanager.http.handlers.HMDataStoreQueryHandler,com.creditease.uav.feature.healthmanager.http.handlers.HMCacheQueryHandler feature.healthmanager.http.port=8042 diff --git a/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_nodeserver.properties b/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_nodeserver.properties index b5770671..bf812b15 100644 --- a/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_nodeserver.properties +++ b/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_nodeserver.properties @@ -84,7 +84,7 @@ feature.healthmanager.MT_Monitor.consumethreadmax=10 feature.healthmanager.MT_Notify.consumethreadmax=10 feature.healthmanager.MT_Profile.consumethreadmax=10 feature.healthmanager.MT_Log.consumethreadmax=10 -feature.healthmanager.MT_Node.consumethreadmax=50 +feature.healthmanager.MT_Node.consumethreadmax=10 feature.healthmanager.MT_Monitorconsumestopinterval=0 feature.healthmanager.MT_Notify.consumestopinterval=0 feature.healthmanager.MT_Profile.consumestopinterval=0 diff --git a/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_pfntfyserver.properties b/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_pfntfyserver.properties index 3f0907a3..ab40d611 100644 --- a/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_pfntfyserver.properties +++ b/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_pfntfyserver.properties @@ -80,18 +80,21 @@ feature.healthmanager.components=com.creditease.uav.feature.HealthManager feature.healthmanager.properties= #feature.xxx. feature.healthmanager.messagingnameserver=127.0.0.1:9876;127.0.0.1:9876;127.0.0.1:9876 -feature.healthmanager.MT_Monitor.consumethreadmax=5 +feature.healthmanager.MT_Monitor.consumethreadmax=10 feature.healthmanager.MT_Notify.consumethreadmax=15 feature.healthmanager.MT_Profile.consumethreadmax=25 -feature.healthmanager.MT_Log.consumethreadmax=5 +feature.healthmanager.MT_Log.consumethreadmax=10 +feature.healthmanager.MT_Node.consumethreadmax=10 feature.healthmanager.MT_Monitorconsumestopinterval=0 feature.healthmanager.MT_Notify.consumestopinterval=0 feature.healthmanager.MT_Profile.consumestopinterval=0 feature.healthmanager.MT_Log.consumestopinterval=0 +feature.healthmanager.MT_Node.consumestopinterval=0 feature.healthmanager.MT_Monitor.enable=false feature.healthmanager.MT_Notify.enable=true feature.healthmanager.MT_Profile.enable=true feature.healthmanager.MT_Log.enable=false +feature.healthmanager.MT_Node.enable=false #feature.healthmanager.healthmanger handlers feature.healthmanager.healthMangerHandlers=com.creditease.uav.feature.healthmanager.http.handlers.HMDataStoreQueryHandler,com.creditease.uav.feature.healthmanager.http.handlers.HMCacheQueryHandler feature.healthmanager.http.port=8043 diff --git a/com.creditease.uav.healthmanager.buildComponent/config/hm_test_logserver.properties b/com.creditease.uav.healthmanager.buildComponent/config/hm_test_logserver.properties index f54a0bb2..16aeb53e 100644 --- a/com.creditease.uav.healthmanager.buildComponent/config/hm_test_logserver.properties +++ b/com.creditease.uav.healthmanager.buildComponent/config/hm_test_logserver.properties @@ -81,17 +81,20 @@ feature.healthmanager.properties= #feature.xxx. feature.healthmanager.messagingnameserver=127.0.0.1:9876 feature.healthmanager.MT_Monitor.consumethreadmax=5 -feature.healthmanager.MT_Notify.consumethreadmax=10 -feature.healthmanager.MT_Profile.consumethreadmax=10 +feature.healthmanager.MT_Notify.consumethreadmax=5 +feature.healthmanager.MT_Profile.consumethreadmax=5 feature.healthmanager.MT_Log.consumethreadmax=20 +feature.healthmanager.MT_Node.consumethreadmax=10 feature.healthmanager.MT_Monitorconsumestopinterval=0 feature.healthmanager.MT_Notify.consumestopinterval=0 feature.healthmanager.MT_Profile.consumestopinterval=0 feature.healthmanager.MT_Log.consumestopinterval=0 +feature.healthmanager.MT_Node.consumestopinterval=0 feature.healthmanager.MT_Monitor.enable=false feature.healthmanager.MT_Notify.enable=false feature.healthmanager.MT_Profile.enable=false feature.healthmanager.MT_Log.enable=true +feature.healthmanager.MT_Node.enable=false #feature.healthmanager.healthmanger handlers feature.healthmanager.healthMangerHandlers=com.creditease.uav.feature.healthmanager.http.handlers.HMDataStoreQueryHandler,com.creditease.uav.feature.healthmanager.http.handlers.HMCacheQueryHandler feature.healthmanager.http.port=8042 diff --git a/com.creditease.uav.healthmanager.buildComponent/config/hm_test_moserver.properties b/com.creditease.uav.healthmanager.buildComponent/config/hm_test_moserver.properties index 31c706b1..fd792739 100644 --- a/com.creditease.uav.healthmanager.buildComponent/config/hm_test_moserver.properties +++ b/com.creditease.uav.healthmanager.buildComponent/config/hm_test_moserver.properties @@ -84,14 +84,17 @@ feature.healthmanager.MT_Monitor.consumethreadmax=35 feature.healthmanager.MT_Notify.consumethreadmax=10 feature.healthmanager.MT_Profile.consumethreadmax=10 feature.healthmanager.MT_Log.consumethreadmax=10 +feature.healthmanager.MT_Node.consumethreadmax=10 feature.healthmanager.MT_Monitorconsumestopinterval=0 feature.healthmanager.MT_Notify.consumestopinterval=0 feature.healthmanager.MT_Profile.consumestopinterval=0 feature.healthmanager.MT_Log.consumestopinterval=0 +feature.healthmanager.MT_Node.consumestopinterval=0 feature.healthmanager.MT_Monitor.enable=true feature.healthmanager.MT_Notify.enable=false feature.healthmanager.MT_Profile.enable=false feature.healthmanager.MT_Log.enable=false +feature.healthmanager.MT_Node.enable=false #feature.healthmanager.healthmanger handlers feature.healthmanager.healthMangerHandlers=com.creditease.uav.feature.healthmanager.http.handlers.HMDataStoreQueryHandler,com.creditease.uav.feature.healthmanager.http.handlers.HMCacheQueryHandler feature.healthmanager.http.port=8043 diff --git a/com.creditease.uav.healthmanager.buildComponent/config/hm_test_nodeserver.properties b/com.creditease.uav.healthmanager.buildComponent/config/hm_test_nodeserver.properties index be80319c..d0fc078c 100644 --- a/com.creditease.uav.healthmanager.buildComponent/config/hm_test_nodeserver.properties +++ b/com.creditease.uav.healthmanager.buildComponent/config/hm_test_nodeserver.properties @@ -84,7 +84,7 @@ feature.healthmanager.MT_Monitor.consumethreadmax=10 feature.healthmanager.MT_Notify.consumethreadmax=10 feature.healthmanager.MT_Profile.consumethreadmax=10 feature.healthmanager.MT_Log.consumethreadmax=10 -feature.healthmanager.MT_Node.consumethreadmax=35 +feature.healthmanager.MT_Node.consumethreadmax=10 feature.healthmanager.MT_Monitorconsumestopinterval=0 feature.healthmanager.MT_Notify.consumestopinterval=0 feature.healthmanager.MT_Profile.consumestopinterval=0 diff --git a/com.creditease.uav.healthmanager.buildComponent/config/hm_test_pnhbserver.properties b/com.creditease.uav.healthmanager.buildComponent/config/hm_test_pnhbserver.properties index c7bf0568..54d67f84 100644 --- a/com.creditease.uav.healthmanager.buildComponent/config/hm_test_pnhbserver.properties +++ b/com.creditease.uav.healthmanager.buildComponent/config/hm_test_pnhbserver.properties @@ -151,18 +151,21 @@ feature.healthmanager.components=com.creditease.uav.feature.HealthManager feature.healthmanager.properties= #feature.xxx. feature.healthmanager.messagingnameserver=127.0.0.1:9876 -feature.healthmanager.MT_Monitor.consumethreadmax=5 +feature.healthmanager.MT_Monitor.consumethreadmax=10 feature.healthmanager.MT_Notify.consumethreadmax=10 feature.healthmanager.MT_Profile.consumethreadmax=10 -feature.healthmanager.MT_Log.consumethreadmax=5 +feature.healthmanager.MT_Log.consumethreadmax=10 +feature.healthmanager.MT_Node.consumethreadmax=10 feature.healthmanager.MT_Monitorconsumestopinterval=0 feature.healthmanager.MT_Notify.consumestopinterval=0 feature.healthmanager.MT_Profile.consumestopinterval=0 feature.healthmanager.MT_Log.consumestopinterval=0 +feature.healthmanager.MT_Node.consumestopinterval=0 feature.healthmanager.MT_Monitor.enable=false feature.healthmanager.MT_Notify.enable=true feature.healthmanager.MT_Profile.enable=true feature.healthmanager.MT_Log.enable=false +feature.healthmanager.MT_Node.enable=false #feature.healthmanager.healthmanger handlers feature.healthmanager.healthMangerHandlers=com.creditease.uav.feature.healthmanager.http.handlers.HMDataStoreQueryHandler,com.creditease.uav.feature.healthmanager.http.handlers.HMCacheQueryHandler feature.healthmanager.http.port=8041 From a95d920ddd02cf73bb638ef2ce511289741162fd Mon Sep 17 00:00:00 2001 From: "zhenzhang18@creditease.cn" Date: Fri, 13 Oct 2017 13:41:04 +0800 Subject: [PATCH 08/14] SpringBootTomcatPlusIT onAppStop NPE when springboot stops, sometimes there is an NPE. however, it doesn't matter. we fix this for better stopping. --- .gitignore | 5 +++++ .../tomcat/plus/interceptor/SpringBootTomcatPlusIT.java | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d51ef345..2bed942a 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,8 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* + +.classpath +.project +.settings +.settings/* diff --git a/com.creditease.uav.tomcat.plus.core/src/main/java/com/creditease/tomcat/plus/interceptor/SpringBootTomcatPlusIT.java b/com.creditease.uav.tomcat.plus.core/src/main/java/com/creditease/tomcat/plus/interceptor/SpringBootTomcatPlusIT.java index a550f4a4..7a3bb44a 100644 --- a/com.creditease.uav.tomcat.plus.core/src/main/java/com/creditease/tomcat/plus/interceptor/SpringBootTomcatPlusIT.java +++ b/com.creditease.uav.tomcat.plus.core/src/main/java/com/creditease/tomcat/plus/interceptor/SpringBootTomcatPlusIT.java @@ -301,10 +301,15 @@ public void onAppStop(Object... args) { InterceptSupport iSupport = InterceptSupport.instance(); InterceptContext context = iSupport.createInterceptContext(Event.WEBCONTAINER_STOPPED); - /** + /** * NOTE: spring boot rewrite the tomcat webappclassloader, makes the addURL for nothing, then we can't do * anything on this we may use its webappclassloader's parent as the classloader */ + + if (null == context || null == sc) { + return; + } + context.put(InterceptConstants.WEBAPPLOADER, sc.getLoader().getClassLoader().getParent()); context.put(InterceptConstants.WEBWORKDIR, sc.getWorkPath()); From 9e102cd0a0e6bbdc60b8d9f87b7ea5ae978d0bcb Mon Sep 17 00:00:00 2001 From: "zxzxzczz@163.com" Date: Tue, 17 Oct 2017 14:09:57 +0800 Subject: [PATCH 09/14] InvokeChain query can't reach over 7 days + UE FIX: Display HostName when there is only MonitorAgent Tag --- com.creditease.uav.console/pom.xml | 6 ++++++ .../com/creditease/uav/xrobot/rest/XRobotRestService.java | 2 +- .../src/main/webapp/uavapp_godeye/appmonitor/js/uav.apm.js | 1 + .../main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js | 5 +++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/com.creditease.uav.console/pom.xml b/com.creditease.uav.console/pom.xml index 3255e3dd..49d9162c 100644 --- a/com.creditease.uav.console/pom.xml +++ b/com.creditease.uav.console/pom.xml @@ -62,6 +62,12 @@ commons-logging 1.2 + + + aredis.sourceforge.net + aredis-api + 1.4 + diff --git a/com.creditease.uav.console/src/main/java/com/creditease/uav/xrobot/rest/XRobotRestService.java b/com.creditease.uav.console/src/main/java/com/creditease/uav/xrobot/rest/XRobotRestService.java index e88c46d7..37dda0bf 100644 --- a/com.creditease.uav.console/src/main/java/com/creditease/uav/xrobot/rest/XRobotRestService.java +++ b/com.creditease.uav.console/src/main/java/com/creditease/uav/xrobot/rest/XRobotRestService.java @@ -86,7 +86,7 @@ public void doCommand(String data, @Suspended AsyncResponse response) { UAVHttpMessage msg = new UAVHttpMessage(data); - this.doHttpPost("uav.app.xrobot.http.addr", "/xrobot", JSONHelper.toString(msg).getBytes(), "application/json", + this.doHttpPost("uav.app.xrobot.http.addr", "/hit/xrobot", JSONHelper.toString(msg).getBytes(), "application/json", "utf-8", new CmdCallback(response)); } diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.apm.js b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.apm.js index c84733be..1f65df7f 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.apm.js +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/appmonitor/js/uav.apm.js @@ -1017,6 +1017,7 @@ function APMTool(app) { data["request"]["eptype"]="E,S"; data["request"]["from"]=0+""; data["request"]["size"]=500+""; + data["request"]["indexdate"]=timeRange["indexdate"]; var timeSort=this.timeSortSelector.value(); if (timeSort=="DESC") { diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js index b6dae8f8..fe76997a 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js @@ -1282,6 +1282,11 @@ var mvcObj={ return jsonObj["host"]; } + //if only has 监控代理程序 then display host name + if (tags=="监控代理程序,") { + return jsonObj["host"]; + } + return tags; }, //------------------------------MAC--------------------------------------- From 295079880321bf534bbf3ad8cdbf55e7ef3a3f78 Mon Sep 17 00:00:00 2001 From: lichong Date: Tue, 17 Oct 2017 15:11:31 +0800 Subject: [PATCH 10/14] dubbo random port support --- .../uav/hook/dubbo/DubboHookProxy.java | 2 +- .../uav/hook/dubbo/interceptors/DubboIT.java | 26 ++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/com.creditease.uav.hook.dubbo/src/main/java/com/creditease/uav/hook/dubbo/DubboHookProxy.java b/com.creditease.uav.hook.dubbo/src/main/java/com/creditease/uav/hook/dubbo/DubboHookProxy.java index be34ee3a..3fcc6230 100644 --- a/com.creditease.uav.hook.dubbo/src/main/java/com/creditease/uav/hook/dubbo/DubboHookProxy.java +++ b/com.creditease.uav.hook.dubbo/src/main/java/com/creditease/uav/hook/dubbo/DubboHookProxy.java @@ -93,7 +93,7 @@ public void process(CtMethod m) throws Exception { if ("onApplicationEvent".equals(m.getName())) { dpInstall.defineLocalVal(m, "mObj", DubboIT.class); - m.insertBefore( + m.insertAfter( "{mObj=new DubboIT(\"" + appid + "\");mObj.doProfiling(new Object[]{this,$1});}"); } diff --git a/com.creditease.uav.hook.dubbo/src/main/java/com/creditease/uav/hook/dubbo/interceptors/DubboIT.java b/com.creditease.uav.hook.dubbo/src/main/java/com/creditease/uav/hook/dubbo/interceptors/DubboIT.java index afa62163..442c3029 100644 --- a/com.creditease.uav.hook.dubbo/src/main/java/com/creditease/uav/hook/dubbo/interceptors/DubboIT.java +++ b/com.creditease.uav.hook.dubbo/src/main/java/com/creditease/uav/hook/dubbo/interceptors/DubboIT.java @@ -26,7 +26,6 @@ import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.config.ProtocolConfig; import com.alibaba.dubbo.config.spring.ServiceBean; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; @@ -365,16 +364,25 @@ else if ("".equals(group) && !"".equals(version)) { dspi.setGroup(group); dspi.setVersion(version); - List plist = sb.getProtocols(); + @SuppressWarnings("unchecked") + List urlList = sb.getExportedUrls(); - if (plist != null) { - for (ProtocolConfig pc : plist) { + if (urlList != null) { + for (URL url : urlList) { DubboServiceProfileInfo.Protocol pro = new DubboServiceProfileInfo.Protocol(); - pro.setpName(pc.getName()); - pro.setPort(pc.getPort()); - pro.setCharset(pc.getCharset()); - pro.setContextpath(pc.getContextpath()); - pro.setSerialization(pc.getSerialization()); + pro.setPort(url.getPort()); + pro.setpName(url.getProtocol()); + int pathLength = url.getPath().length(); + // 长度加1为了去除反斜杠/ + int interfaceLength = url.getServiceInterface().length() + 1; + String contextpath = null; + if (pathLength > interfaceLength + 1) { + contextpath = url.getPath().substring(0, pathLength - interfaceLength); + } + pro.setContextpath(contextpath); + pro.setCharset(url.getParameter("charset")); + // dubbo当前默认的序列化方式为hessian2,不知道日后会不会变,故此处不进行默认赋值 + pro.setSerialization(url.getParameter("serialization")); dspi.addProtocol(pro); } } From 53108746996d13c9966183f98637236a0e4a6bfc Mon Sep 17 00:00:00 2001 From: lbay Date: Thu, 19 Oct 2017 17:49:40 +0800 Subject: [PATCH 11/14] Tomcat 7.0.0~7.0.23 has no getStartStopExecutor method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix 结果: TomcatPlusIT.java onDeployUAVApp 方法中 tomcat7.0.30(不包含)小版本以下版本(到tomcat7.0.10)都统一和tomcat6进行一样的逻辑处理 --- .../adaptors/TomcatAdaptor.java | 6 +- .../tomcat/plus/interceptor/TomcatPlusIT.java | 76 ++++++++++++------- 2 files changed, 53 insertions(+), 29 deletions(-) diff --git a/com.creditease.uav.monitorframework.agent/src/main/java/com/creditease/uav/monitorframework/adaptors/TomcatAdaptor.java b/com.creditease.uav.monitorframework.agent/src/main/java/com/creditease/uav/monitorframework/adaptors/TomcatAdaptor.java index 9d522fae..179afcb6 100644 --- a/com.creditease.uav.monitorframework.agent/src/main/java/com/creditease/uav/monitorframework/adaptors/TomcatAdaptor.java +++ b/com.creditease.uav.monitorframework.agent/src/main/java/com/creditease/uav/monitorframework/adaptors/TomcatAdaptor.java @@ -31,6 +31,7 @@ public class TomcatAdaptor extends AbstractAdaptor { private String currentVersion = ""; + private String currentVersionDetailed = ""; private void detectTomcatVersion() { @@ -70,6 +71,7 @@ private void detectTomcatVersion() { } currentVersion = ver; + currentVersionDetailed = version; } @Override @@ -322,6 +324,7 @@ public String getMethodName() { else if (className.equals("org.apache.catalina.startup.HostConfig")) { final String curVersion = this.currentVersion; + final String currentVersionDetailed = this.currentVersionDetailed; return this.inject(className, new String[] { "com.creditease.tomcat.plus.interceptor" }, new AdaptorProcessor[] { new AdaptorProcessor() { @@ -337,7 +340,8 @@ public void process(CtMethod m) throws Exception { aa.addLocalVar(m, "mObj", "com.creditease.tomcat.plus.interceptor.TomcatPlusIT"); m.insertAfter( "{mObj=new TomcatPlusIT();mObj.onDeployUAVApp(new Object[]{this,this.host,$1,\"" - + uavMofRoot + "\",\"" + curVersion + "\"});}"); + + uavMofRoot + "\",\"" + curVersion + "\",\"" + currentVersionDetailed + + "\"});}"); } } }); diff --git a/com.creditease.uav.tomcat.plus.core/src/main/java/com/creditease/tomcat/plus/interceptor/TomcatPlusIT.java b/com.creditease.uav.tomcat.plus.core/src/main/java/com/creditease/tomcat/plus/interceptor/TomcatPlusIT.java index 76831dab..09d63857 100644 --- a/com.creditease.uav.tomcat.plus.core/src/main/java/com/creditease/tomcat/plus/interceptor/TomcatPlusIT.java +++ b/com.creditease.uav.tomcat.plus.core/src/main/java/com/creditease/tomcat/plus/interceptor/TomcatPlusIT.java @@ -448,7 +448,7 @@ public void onServletStop(Object... args) { @SuppressWarnings("unused") public void onDeployUAVApp(Object... args) { - if (System.getProperty("com.creditease.uav.iapp.install") != null) { + if (System.getProperty("com.creditease.uav.iapp.install") != null) { return; } @@ -457,46 +457,66 @@ public void onDeployUAVApp(Object... args) { final File appBase = (File) args[2]; final String mofRoot = (String) args[3]; String curVersion = (String) args[4]; + String currentVersionDetailed = (String) args[5]; + String[] versions = currentVersionDetailed.split("\\."); - // Tomcat 6 - if (curVersion.equalsIgnoreCase("6")) { + int action = 0; - File dir = new File(mofRoot + "/com.creditease.uav"); - - ReflectHelper.invoke("org.apache.catalina.startup.HostConfig", hc, "deployDirectory", - new Class[] { String.class, File.class, String.class }, - new Object[] { "com.creditease.uav", dir, mofRoot + "/com.creditease.uav" }, - hc.getClass().getClassLoader()); + if (curVersion.equals("6")) { + /** + * tomcat6 + */ + action = 0; + } + else if (curVersion.equals("7") && versions[1].equals("0") + && (Integer.parseInt(versions[2].substring(0, 1)) < 3)) { + /** + * tomcat7.并且小版本0.30.0 (不包含)以下。小版本号使用substring是因为存在beta版本,取第一位即可。 + */ + action = 0; } - // after Tomcat 7 else { - ExecutorService es = host.getStartStopExecutor(); + action = 1; + } - Future f = es.submit(new Runnable() { + switch (action) { + case 0: + File dir = new File(mofRoot + "/com.creditease.uav"); - @Override - public void run() { + ReflectHelper.invoke("org.apache.catalina.startup.HostConfig", hc, "deployDirectory", + new Class[] { String.class, File.class, String.class }, + new Object[] { "com.creditease.uav", dir, mofRoot + "/com.creditease.uav" }, + hc.getClass().getClassLoader()); + break; + case 1: + ExecutorService es = host.getStartStopExecutor(); - ContextName cn = new ContextName("com.creditease.uav", ""); + Future f = es.submit(new Runnable() { - ReflectHelper.setField(ContextName.class, cn, "baseName", mofRoot + "/com.creditease.uav"); + @Override + public void run() { - File dir = new File(mofRoot + "/com.creditease.uav"); + ContextName cn = new ContextName("com.creditease.uav", ""); - ReflectHelper.invoke("org.apache.catalina.startup.HostConfig", hc, "deployDirectory", - new Class[] { ContextName.class, File.class }, new Object[] { cn, dir }, - hc.getClass().getClassLoader()); + ReflectHelper.setField(ContextName.class, cn, "baseName", mofRoot + "/com.creditease.uav"); - } + File dir = new File(mofRoot + "/com.creditease.uav"); - }); + ReflectHelper.invoke("org.apache.catalina.startup.HostConfig", hc, "deployDirectory", + new Class[] { ContextName.class, File.class }, new Object[] { cn, dir }, + hc.getClass().getClassLoader()); - try { - f.get(); - } - catch (Exception e) { - // ignore - } + } + + }); + + try { + f.get(); + } + catch (Exception e) { + // ignore + } + break; } System.setProperty("com.creditease.uav.iapp.install", "true"); From e50a50b9f6998882148dc7bb1d7e965f0002d78a Mon Sep 17 00:00:00 2001 From: dehuaduan Date: Thu, 19 Oct 2017 19:10:06 +0800 Subject: [PATCH 12/14] https://github.com/uavorg/uavstack/issues/38 --- .../bin/start.bat | 6 +- .../exlib/Jpcap.dll | Bin 0 -> 89600 bytes .../exlib/Packet.dll | Bin 0 -> 107768 bytes .../exlib/jpcap.jar | Bin 0 -> 18192 bytes .../exlib/npf.sys | Bin 0 -> 36600 bytes .../exlib/wpcap.dll | Bin 0 -> 370424 bytes .../pom.xml | 2 + com.creditease.uav.agent.heartbeat/pom.xml | 8 +- .../procdetectagent/NetworkIoDetector.java | 152 +++++++++++++++--- 9 files changed, 143 insertions(+), 25 deletions(-) create mode 100644 com.creditease.uav.agent.buildComponent/exlib/Jpcap.dll create mode 100644 com.creditease.uav.agent.buildComponent/exlib/Packet.dll create mode 100644 com.creditease.uav.agent.buildComponent/exlib/jpcap.jar create mode 100644 com.creditease.uav.agent.buildComponent/exlib/npf.sys create mode 100644 com.creditease.uav.agent.buildComponent/exlib/wpcap.dll diff --git a/com.creditease.uav.agent.buildComponent/bin/start.bat b/com.creditease.uav.agent.buildComponent/bin/start.bat index 0a4bebfa..e2cc24dc 100644 --- a/com.creditease.uav.agent.buildComponent/bin/start.bat +++ b/com.creditease.uav.agent.buildComponent/bin/start.bat @@ -12,7 +12,11 @@ if not [%2] == [] set appID=%2 if not "%JAVA_HOME%" == "" set executeJava="%JAVA_HOME%/bin/java" cd .. +if not exist C:\Windows\System32\Packet.dll (move lib\Packet.dll C:\Windows\System32) +if not exist C:\Windows\System32\wpcap.dll (move lib\wpcap.dll C:\Windows\System32) +if not exist C:\Windows\System32\drivers\npf.sys (move lib\npf.sys C:\Windows\System32\drivers) + set CLASSPATH=bin/com.creditease.uav.base-1.0-boot.jar set javaAgent="-javaagent:../uavmof/com.creditease.uav.agent/com.creditease.uav.monitorframework.agent-1.0-agent.jar" set javaOpts=-server -Xms64m -Xmx256m -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+CMSIncrementalPacing -XX:CMSIncrementalDutyCycleMin=0 -XX:CMSIncrementalDutyCycle=10 -XX:+UseParNewGC -%executeJava% %javaAgent% %javaOpts% -DNetCardIndex=0 -DJAppID=%appID% -DJAppGroup=UAV -classpath "%CLASSPATH%" com.creditease.mscp.boot.MSCPBoot -p %profile% +java %javaAgent% %javaOpts% -Djava.library.path=./lib -DNetCardIndex=0 -DJAppID=%appID% -DJAppGroup=UAV -classpath "%CLASSPATH%" com.creditease.mscp.boot.MSCPBoot -p %profile% diff --git a/com.creditease.uav.agent.buildComponent/exlib/Jpcap.dll b/com.creditease.uav.agent.buildComponent/exlib/Jpcap.dll new file mode 100644 index 0000000000000000000000000000000000000000..0ab8aa17ec855fc08e8895c8aca8124690b8e486 GIT binary patch literal 89600 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 literal 0 HcmV?d00001 diff --git a/com.creditease.uav.agent.buildComponent/exlib/Packet.dll b/com.creditease.uav.agent.buildComponent/exlib/Packet.dll new file mode 100644 index 0000000000000000000000000000000000000000..a8bbfa4e4bc545f61757a9338c478a1ac3590ba2 GIT binary patch literal 107768 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 bep3(RBtid36$60$@zefcMBx69kpBMw%c?iZ literal 0 HcmV?d00001 diff --git a/com.creditease.uav.agent.buildComponent/exlib/npf.sys b/com.creditease.uav.agent.buildComponent/exlib/npf.sys new file mode 100644 index 0000000000000000000000000000000000000000..761c90c93411f67ffec91400446680331438aaae GIT binary patch literal 36600 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 literal 0 HcmV?d00001 diff --git a/com.creditease.uav.agent.buildComponent/exlib/wpcap.dll b/com.creditease.uav.agent.buildComponent/exlib/wpcap.dll new file mode 100644 index 0000000000000000000000000000000000000000..eabb73ddd4f76cead8db0acb56751b20d9159399 GIT binary patch literal 370424 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 NQ`i6U^2 + + diff --git a/com.creditease.uav.agent.heartbeat/pom.xml b/com.creditease.uav.agent.heartbeat/pom.xml index ec2e9af0..e3c93d2e 100644 --- a/com.creditease.uav.agent.heartbeat/pom.xml +++ b/com.creditease.uav.agent.heartbeat/pom.xml @@ -35,7 +35,13 @@ com.creditease.uav.cache.redis - + + jpcap + jpcap + 1.0 + system + ${basedir}/../com.creditease.uav.agent.buildComponent/exlib/jpcap.jar + diff --git a/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/procdetectagent/NetworkIoDetector.java b/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/procdetectagent/NetworkIoDetector.java index a73304c4..f11c9fd9 100644 --- a/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/procdetectagent/NetworkIoDetector.java +++ b/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/procdetectagent/NetworkIoDetector.java @@ -20,12 +20,22 @@ package com.creditease.agent.feature.procdetectagent; +import java.text.DecimalFormat; +import java.util.HashMap; + +import com.creditease.agent.helpers.JSONHelper; import com.creditease.agent.helpers.JVMToolHelper; import com.creditease.agent.helpers.NetworkHelper; import com.creditease.agent.helpers.RuntimeHelper; import com.creditease.agent.spi.AbstractTimerWork; import com.creditease.agent.spi.AgentFeatureComponent; +import jpcap.JpcapCaptor; +import jpcap.NetworkInterface; +import jpcap.NetworkInterfaceAddress; +import jpcap.packet.Packet; +import jpcap.packet.TCPPacket; + public class NetworkIoDetector extends AbstractTimerWork { private String portList; @@ -39,49 +49,98 @@ public NetworkIoDetector(String cName, String feature) { @Override public void run() { - /** - * NOTE: not support windows yet - */ - if (JVMToolHelper.isWindows()) { + if (portList == null) { return; } - if (countDown != 0) { - countDown--; - return; + + String result = null; + String networkdetectTime = this.getConfigManager().getFeatureConfiguration(this.feature, + "networkDetect.collectTime"); + String ip = NetworkHelper.getLocalIP(); + + // windows + if (JVMToolHelper.isWindows()) { + + try { + String Local_ip = "/" + ip; + // ˿ + HashMap counter = new HashMap(); + String[] split_ProtList = portList.split(" "); + for (String str : split_ProtList) { + counter.put("in_" + str, 0); + counter.put("out_" + str, 0); + } + // ȡ豸б + NetworkInterface[] devices = JpcapCaptor.getDeviceList(); + // ȷ豸ӿ + boolean true_devices = false; + int i = 0; + for (; i < devices.length; i++) { + for (NetworkInterfaceAddress nia : devices[i].addresses) { + if (Local_ip.equals(nia.address.toString())) { + true_devices = true; + break; + } + + } + if (true_devices) { + break; + } + } + NetworkInterface nc = devices[i]; + // 豸 ijϵץȡ,Ϊ65535 + JpcapCaptor jpcap = JpcapCaptor.openDevice(nc, 65535, false, 20); + jpcap.setFilter("tcp", true);// ù + + // ץ ͳ + result = portFlux(jpcap, counter, nc, networkdetectTime, Local_ip); + + } + catch (Exception e) { + log.err(this, "NetworkIo Monitor runs FAIL.", e); + } + } - if (portList != null) { + + // linux + else { + + if (countDown != 0) { + countDown--; + return; + } + try { - String networkdetectTime = this.getConfigManager().getFeatureConfiguration(this.feature, - "networkDetect.collectTime"); - String ip = NetworkHelper.getLocalIP(); + String netcardName = NetworkHelper.getNetCardName(ip); String command = "cd bin; sh networkIoDetect.sh " + netcardName + " " + ip + " " + networkdetectTime + " " + portList; - String result = RuntimeHelper.exec(10000, "/bin/sh", "-c", command); + result = RuntimeHelper.exec(10000, "/bin/sh", "-c", command); if (!result.contains("in_") || result.toLowerCase().contains("error") || result.toLowerCase().contains("traceback")) { log.err(this, "NetworkIo Monitor runs FAIL with TechError: error=" + result); countDown = 100; return; } - - AgentFeatureComponent afc = (AgentFeatureComponent) this.getConfigManager().getComponent(this.feature, - "ProcDetectAgent"); - if (null != afc) { - afc.exchange("procscan.nodeinfo.portFlux", result, System.currentTimeMillis()); - } - - if (log.isDebugEnable()) { - log.debug(this, "NetworkIo Monitor Result: " + result); - } - } catch (Exception e) { log.err(this, "NetworkIo Monitor runs FAIL.", e); countDown = 100; } + } + + AgentFeatureComponent afc = (AgentFeatureComponent) this.getConfigManager().getComponent(this.feature, + "ProcDetectAgent"); + if (null != afc) { + afc.exchange("procscan.nodeinfo.portFlux", result, System.currentTimeMillis()); + } + + if (log.isDebugEnable()) { + log.debug(this, "NetworkIo Monitor Result: " + result); + } + } public void setPortList(String portList) { @@ -89,4 +148,51 @@ public void setPortList(String portList) { this.portList = portList; } + public String portFlux(JpcapCaptor jpcap, HashMap counter, NetworkInterface nc, + String networkdetectTime, String Local_ip) { + + Packet packet; + + int int_networkdetectTime = 1024 * Integer.parseInt(networkdetectTime) / 1000; + long time = Long.parseLong(networkdetectTime); + long startTime = System.currentTimeMillis(); + while (startTime + time >= System.currentTimeMillis()) { + // ץ + packet = jpcap.getPacket(); + if (null == packet) { + continue; + } + TCPPacket p = (TCPPacket) packet; + // ˿ڲprotList + String dst_ip = p.dst_ip.toString(); + String src_ip = p.src_ip.toString(); + // ͳ + if (dst_ip.equals(Local_ip)) { + String in_port = "in_" + p.dst_port; + if (counter.containsKey(in_port)) { + int in_value = counter.get(in_port) + p.len; + counter.put(in_port, in_value); + } + } + // ͳƳ + if (src_ip.equals(Local_ip)) { + String out_port = "out_" + p.src_port; + if (counter.containsKey(out_port)) { + int out_value = counter.get(out_port) + p.len; + counter.put(out_port, out_value); + } + } + } + + HashMap counterValueIntToString = new HashMap(); + // ֽתkb/s + for (String key : counter.keySet()) { + DecimalFormat df = new DecimalFormat("#0.00"); + Double value = Double.valueOf(df.format(counter.get(key) / int_networkdetectTime * 1.0)); + counterValueIntToString.put(key, value.toString()); + } + // hashmap תΪjson + return JSONHelper.toString(counterValueIntToString); + } + } From e91605fdc447087adaed6bbd8f02bb1c7de7203d Mon Sep 17 00:00:00 2001 From: yongbiaofeng Date: Mon, 23 Oct 2017 15:49:10 +0800 Subject: [PATCH 13/14] https://github.com/uavorg/uavstack/issues/41 1.Bug Fix #41 the MSCP node has no version information after the upgrade. 2.Changed the default name of OSProcess from "UNKOWN" to "UNKNOWN". 3.Filter the empty disk information. --- .../agent/feature/hbagent/handlers/HBClientDefaultHandler.java | 3 +++ .../agent/feature/procdetectagent/OSProcessScanner.java | 2 +- .../src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js | 1 + .../java/com/creditease/agent/helpers/osproc/OSProcess.java | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/hbagent/handlers/HBClientDefaultHandler.java b/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/hbagent/handlers/HBClientDefaultHandler.java index 9e400063..f25b5e32 100644 --- a/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/hbagent/handlers/HBClientDefaultHandler.java +++ b/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/hbagent/handlers/HBClientDefaultHandler.java @@ -294,6 +294,9 @@ private String getIODiskInfo() throws Exception { Map> resultMap = new HashMap>(); for (int i = 0; i < roots.length; i++) { File file = roots[i]; + if (0 == file.getTotalSpace()) + continue; + Map temp = new HashMap(); temp.put("free", String.valueOf(Math.round((double) (file.getFreeSpace() / 1024)))); temp.put("total", String.valueOf(Math.round((double) (file.getTotalSpace() / 1024)))); diff --git a/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/procdetectagent/OSProcessScanner.java b/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/procdetectagent/OSProcessScanner.java index b381289b..8ec01b0e 100644 --- a/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/procdetectagent/OSProcessScanner.java +++ b/com.creditease.uav.agent.heartbeat/src/main/java/com/creditease/agent/feature/procdetectagent/OSProcessScanner.java @@ -312,7 +312,7 @@ public void scanWindowsProcesses(Map procs, StringBuffer port proc.addPort(port); portList = portList.append(port).append(" "); - if (!"UNKOWN".equals(proc.getName())) { + if (!"UNKNOWN".equals(proc.getName())) { continue; } diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js index fe76997a..f5942605 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/uavnetwork/js/uav.network.js @@ -1144,6 +1144,7 @@ var mvcObj={ "node.pid":"info/node.pid", "node.procs":"info/node.procs", "node.services":"info/node.services", + "node.version":"info/node.version", "node.docker.info": "info/node.docker.info", "node.docker.container": "info/node.docker.container" } diff --git a/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/osproc/OSProcess.java b/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/osproc/OSProcess.java index f1a992fe..3d31fa8b 100644 --- a/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/osproc/OSProcess.java +++ b/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/osproc/OSProcess.java @@ -34,7 +34,7 @@ public class OSProcess { private Set ports = new HashSet(); // program name - private String name = "UNKOWN"; + private String name = "UNKNOWN"; // extract info to describe the process private Map tags = new LinkedHashMap(); From 80a026a7401120c554efd75d6786f990f26d4eb9 Mon Sep 17 00:00:00 2001 From: lichong Date: Thu, 26 Oct 2017 11:00:42 +0800 Subject: [PATCH 14/14] fix can not access a member of class --- .../com/creditease/monitor/proxy/spi/JDKProxyInvokeHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/com.creditease.uav.monitorframework/src/main/java/com/creditease/monitor/proxy/spi/JDKProxyInvokeHandler.java b/com.creditease.uav.monitorframework/src/main/java/com/creditease/monitor/proxy/spi/JDKProxyInvokeHandler.java index 0f950575..d9f8002f 100644 --- a/com.creditease.uav.monitorframework/src/main/java/com/creditease/monitor/proxy/spi/JDKProxyInvokeHandler.java +++ b/com.creditease.uav.monitorframework/src/main/java/com/creditease/monitor/proxy/spi/JDKProxyInvokeHandler.java @@ -65,6 +65,7 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl } try { + method.setAccessible(true); res = method.invoke(this.target, args); } catch (InvocationTargetException e) {