package com.nms.server.thread.change; import static com.nms.server.common.Constants.WEB_SOCKET_IP; import static com.nms.server.common.Constants.WEB_SOCKET_PORT; import static com.nms.server.thread.socket.SocketCMD.DOWNLOAD_PLUGIN_SCRIPT; import static com.nms.server.thread.socket.SocketCMD.SEND_PLUGIN_SCRIPT_FILE; import java.io.File; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import net.sf.json.JSONObject; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import com.google.common.collect.Sets; import com.nms.server.bean.EventRecordLibrary; import com.nms.server.bean.NodeModel; import com.nms.server.bean.SetInfo; import com.nms.server.common.Common; import com.nms.server.common.Constants; import com.nms.server.dao.CommonDao; import com.nms.server.service.ChangeService; import com.nms.server.service.CommonService; import com.nms.server.util.FileUtils; import com.nms.server.util.StringUtil; import com.nms.server.util.socket.SSLSocketCallable; import com.nms.server.util.socket.SocketUtils; /** * 下发第三方监测脚本文件 */ public class ChangePluginScriptFile implements Runnable { private static final Logger logger = Logger.getLogger(ChangePluginScriptFile.class); /* * 脚本文件临时存储目录 */ private File pluginScriptDir; /* * 接收脚本文件的NC节点列表 */ private Set ncNodesIpStrSet; /** * 向DC管理的所有有效服务器节点发送脚本文件 * * @param dpluginScriptDir 脚本文件临时存储目录 */ public ChangePluginScriptFile(File pluginScriptDir) { this.pluginScriptDir = pluginScriptDir; } /** * 向指定的NC节点发送脚本文件 * * @param pluginScriptDir 脚本文件临时存储目录 * @param ncNodesIpStrSet 待接收脚本的NC节点列表 */ public ChangePluginScriptFile(File pluginScriptDir, Set ncNodesIpStrSet) { this.pluginScriptDir = pluginScriptDir; this.ncNodesIpStrSet = ncNodesIpStrSet; } /* * 用于统计向特定节点发送的脚本文件 */ private Map> sendRecordList = new HashMap>(); /* * 统计文件剩余发送次数(用于清理DC临时脚本文件) */ private Map fileSendLastCount = new HashMap(); @SuppressWarnings("unchecked") public void run() { CommonDao dao = null; try { dao = new CommonDao(); ChangeService changeService = new ChangeService(dao); // Thread.currentThread().setName("发送监测脚本文件"); Thread.currentThread().setName("Send A Monitoring Script File"); Collection files = FileUtils.listFiles(pluginScriptDir, null, false); if (ncNodesIpStrSet == null) { // 未指定接收的NC节点时,根据检测设置确定待接收脚本的NC节点 Map setInfoMap = new HashMap(); List setInfos = changeService.getAllSetInfo(1, 1); for (SetInfo setInfo : setInfos) { if("2".equals(setInfo.getIsControlStart())) { setInfoMap.put(setInfo.getProcessIden(), setInfo); } } for (File pluginFile : files) { String processIden = pluginFile.getName().replaceAll("\\w+_(\\w+)\\.\\w+", "$1"); SetInfo setInfo = setInfoMap.get(processIden); // 校验 变更范围的节点IP List ipNodeModelList = changeService.getNodeModelListBySetInfo(setInfo); for (NodeModel ip : ipNodeModelList) { // 仅向0服务器节点发送变更信息:0:服务器 if (ip != null && ip.getNodeIp() != null && ip.getNodeType().longValue() == 0l && Common.hasIpInIpSegment(ip.getNodeIp())) { addToSendRecordList(ip.getNodeIp(), pluginFile); // addTofileSendLastCount(pluginFile); // } } } ncNodesIpStrSet = sendRecordList.keySet(); } else { // 已指定待接收脚本的NC节点 for (File pluginFile : files) { for (String ip : ncNodesIpStrSet) { addToSendRecordList(ip, pluginFile); // 统计向特定节点发送的脚本文件 addTofileSendLastCount(pluginFile); // 统计文件剩余发送次数 } } } for (String ip : ncNodesIpStrSet) { Common.runChangeRunnable(new SendPluginScriptFile(ip, sendRecordList.get(ip))); } // 延时清理脚本 new Thread(new DeletePluginScriptDirAfterSending()).start(); } catch (Exception e) { logger.error("", e); } finally { if (dao != null) { dao.close(); dao = null; } } } private void addTofileSendLastCount(File pluginFile) { Integer count = fileSendLastCount.get(pluginFile.getName()); count = (count != null) ? count : 0; fileSendLastCount.put(pluginFile.getName(), count + 1); } private void addToSendRecordList(String nodeIp, File pluginFile) { if (sendRecordList.containsKey(nodeIp)) { sendRecordList.get(nodeIp).add(pluginFile); } else { List files = new ArrayList(); files.add(pluginFile); sendRecordList.put(nodeIp, files); } } protected class SendPluginScriptFile extends SocketUtils implements Callable { private String cmd; private List fileList; public SendPluginScriptFile(String ip, List fileList) { super(ip, Constants.SSL_CLIENT_PORT); this.cmd = SEND_PLUGIN_SCRIPT_FILE; this.fileList = fileList; } @Override public Object call() throws Exception { // Thread.currentThread().setName("发送文件 To:>" + ip); Thread.currentThread().setName("Send File To:>" + ip); CommonDao dao = null; try { if(fileList == null || fileList.size()<1){ logger.info("没有脚本文件需要发送"); return null; } createClientSocket(); this.sendMessage(cmd); logger.debug("cmd:> " + cmd + " 发送命令结果>> " + this.receiveMessage()); StringBuffer sb = new StringBuffer(); for (File file : fileList) { sb.append(",").append(file.getName()); } this.sendMessage(sb.substring(1)); this.receiveMessage(); this.bpSendFileByBath(fileList, pluginScriptDir.getCanonicalPath()); logger.debug("cmd:> " + cmd + " 发送脚本文件>> " + this.receiveMessage()); return true; } catch (Exception e) { String errorInfo = "Target communication:>" + ip + " create failure:" + e.getMessage(); logger.error(errorInfo, e); dao = new CommonDao(); ChangeService changeService = new ChangeService(dao); Map recordContent = new HashMap(); HashSet pluginFileNames = new HashSet(); for (File pluginFile : fileList) { pluginFileNames.add(pluginFile.getName()); } String content = StringUtils.join(pluginFileNames.iterator(), ","); recordContent.put("scriptNames", content); changeService.saveEventRecordLibrary(cmd, Common.getIpSeqIdMap().get(ip) + "" , "S2C", JSONObject.fromObject(recordContent).toString()); return false; } finally { close(); // close socket if(dao != null) { dao.close(); dao = null; } // 文件剩余发送次数为0时,由DeletePluginScriptDirAfterSending线程清理脚本 for (File file : fileList) { fileSendLastCount.put(file.getName(), fileSendLastCount.get(file.getName()) - 1); } } } } /** * NC初始化时发送脚本文件 * * @param ip 接收脚本的NC节点 */ public static void sendPluginFileWhenNcInit(final String ip) { ChangePluginScriptFile task = null; File tempPluginDir = ChangePluginScriptFile.getNewTempPluginDirectory(); CommonDao dao = null; List prefixNameList = new ArrayList(); try { Set ipList = new HashSet(1); ipList.add(ip); task = new ChangePluginScriptFile(tempPluginDir, ipList); dao = new CommonDao(); CommonService service = new CommonService(dao); List setInfoList = service.selectSetInfoList(1l, null, Common.getIpSeqIdMap().get(ip), null, null, 1l, null, 0l, true); for (SetInfo setInfo : setInfoList) { if("2".equals(setInfo.getIsControlStart())) { String prefixName = setInfo.getCheckTypeName() + "_" + setInfo.getProcessIden() + "."; prefixNameList.add(prefixName); } } } catch (SQLException e) { logger.error(e.getMessage(), e); } finally { if (dao != null) { dao.close(); dao = null; } } boolean bool = task.waitForGettingScriptFromWeb(tempPluginDir, prefixNameList); if (bool) { Common.service.execute(task); } else { // 向Web请求脚本失败,记录eventRecordLibrary try { dao = new CommonDao(); ChangeService changeService = new ChangeService(dao); Map recordContent = new HashMap(); String content = StringUtils.join(prefixNameList.iterator(), ","); recordContent.put("scriptNames", content); changeService.saveEventRecordLibrary(SEND_PLUGIN_SCRIPT_FILE, Common.getIpSeqIdMap().get(ip) + "", "S2C", JSONObject.fromObject(recordContent).toString()); } catch (SQLException e) { logger.error(e.getMessage(), e); } finally { if (dao != null) { dao.close(); dao = null; } } } } /** * 解析失败暂存信息,重新发送脚本文件
* * @param mrlList */ public static void sendPluginFileBaseOnEventRecord(List recordList) { if(recordList == null || recordList.isEmpty()) { return; } // W2S [脚本名前缀,...] Set w2sDetecSetInfos = new HashSet(); // S2C key:NC地址, value:[脚本名前缀,...] Map> s2cDetecSetInfos = new HashMap>(); CommonDao dao = null; try { dao = new CommonDao(); ChangeService changeService = new ChangeService(dao); for (EventRecordLibrary record : recordList) { if (SEND_PLUGIN_SCRIPT_FILE.equalsIgnoreCase(record.getRecordCommand())) { // 脚本下发 Map map = StringUtil.getMapFromJsonObjStr(record.getRecordContent()); String recordType = record.getRecordType(); String scriptNames = (String) map.get("scriptNames"); if("W2S".equals(recordType)) { for (String scriptName : scriptNames.split(",")) { w2sDetecSetInfos.add(scriptName); } } else if("S2C".equals(recordType)) { for (String scriptName : scriptNames.split(",")) { String ip = Common.getNodeIpByUUID(record.getSeqId()); Set scriptNameSet = s2cDetecSetInfos.get(ip); if(scriptNameSet == null) { scriptNameSet = new HashSet(); } scriptNameSet.add(scriptName); s2cDetecSetInfos.put(ip, scriptNameSet); } } } changeService.deleteEventRecordByIds(record.getId() + ""); } } catch (SQLException e) { logger.error("Delete EventRecordLibrary", e); } // W2S, 向DC管理的所有有效节点发送脚本文件 if(!w2sDetecSetInfos.isEmpty()) { File tempPluginDir = ChangePluginScriptFile.getNewTempPluginDirectory(); ChangePluginScriptFile task = new ChangePluginScriptFile(tempPluginDir); boolean bool = task.waitForGettingScriptFromWeb(tempPluginDir, w2sDetecSetInfos); if(bool) { Common.service.execute(task); } else { // 向Web请求脚本失败,记录eventRecordLibrary try { dao = new CommonDao(); ChangeService changeService = new ChangeService(dao); Map recordContent = new HashMap(); String content = StringUtils.join(w2sDetecSetInfos.iterator(), ","); recordContent.put("scriptNames", content); changeService.saveEventRecordLibrary(SEND_PLUGIN_SCRIPT_FILE, "", "W2S", JSONObject.fromObject(recordContent).toString()); } catch (SQLException e) { logger.error(e.getMessage(), e); } finally { if (dao != null) { dao.close(); dao = null; } } } } // S2C, 向指定节点发送脚本文件 Iterator>> it = s2cDetecSetInfos.entrySet().iterator(); while(it.hasNext()) { Entry> entry = it.next(); Set recvIpSet = Sets.newHashSet(entry.getKey()); File tempPluginDir = ChangePluginScriptFile.getNewTempPluginDirectory(); ChangePluginScriptFile task = new ChangePluginScriptFile(tempPluginDir, recvIpSet); Set prefixNames = entry.getValue(); boolean bool = task.waitForGettingScriptFromWeb(tempPluginDir, prefixNames); bool = false; if(bool) { Common.service.execute(task); } else { // 向Web请求脚本失败,记录eventRecordLibrary try { dao = new CommonDao(); ChangeService changeService = new ChangeService(dao); Map recordContent = new HashMap(); String content = StringUtils.join(prefixNames.iterator(), ","); recordContent.put("scriptNames", content); String ips = Common.getIpSeqIdMap().get(recvIpSet.iterator().next())+""; changeService.saveEventRecordLibrary(SEND_PLUGIN_SCRIPT_FILE, ips, "S2C", JSONObject.fromObject(recordContent).toString()); } catch (SQLException e) { logger.error(e.getMessage(), e); } finally { if (dao != null) { dao.close(); dao = null; } } } } } /** * 根据脚本名称从Web获取脚本文件,并等待脚本获取完成 * * @param dir * @param prefixNames * @return */ protected Boolean waitForGettingScriptFromWeb(File dir, Collection prefixNames) { GetScriptFileFromWeb task = null; task = this.new GetScriptFileFromWeb(dir, prefixNames); FutureTask future = new FutureTask(task); new Thread(future).start(); try { Object result = future.get(); if(result == null) { logger.debug("从Web服务器获取脚本失败,脚本列表:" + prefixNames); return false; } return (Boolean) result; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } return false; } protected class GetScriptFileFromWeb extends SSLSocketCallable { Logger logger = Logger.getLogger(GetScriptFileFromWeb.class); private File tempPluginDir; // 脚本存储目录 private String prefixNames; // 脚本名称列表(逗号分隔) public GetScriptFileFromWeb(File tempPluginDir, Collection prefixNames) { super(WEB_SOCKET_IP, WEB_SOCKET_PORT); this.tempPluginDir = tempPluginDir; if(prefixNames != null && prefixNames.size() > 0){ StringBuilder sb = new StringBuilder(); for(String s : prefixNames){ if(StringUtils.isNotBlank(s)){ sb.append(","); sb.append(s); } } if(sb.length() >0){ sb.deleteCharAt(0); this.prefixNames = sb.toString(); } } } @Override protected Object toDo() throws Exception { // Thread.currentThread().setName("下载第三方监测脚本文件"); Thread.currentThread().setName("Download Third Party Monitoring Script Files"); if(StringUtils.isBlank(prefixNames)){ return true; } this.sendMessage(DOWNLOAD_PLUGIN_SCRIPT); this.receiveMessage(); this.sendMessage(prefixNames); String fileName = this.receiveMessage(); // 重复请求脚本,Web无对应脚本时返回为空 if(FAIL.equalsIgnoreCase(fileName) || StringUtils.isBlank(fileName)) { logger.error("The Web server does not monitor " + prefixNames + "the corresponding script file!"); return false; } else { this.sendMessage(SUCCESS); this.bpReceiveFileByBath(tempPluginDir.getCanonicalPath()); logger.info("已接收脚本文件:" + Arrays.toString(tempPluginDir.list())); return true; } } } protected class DeletePluginScriptDirAfterSending implements Runnable { @Override public void run() { while (!fileSendLastCount.isEmpty()) { Iterator> iterator = fileSendLastCount.entrySet().iterator(); while (iterator.hasNext()) { Entry entry = iterator.next(); if(entry.getValue() == 0) { iterator.remove(); } } try { TimeUnit.SECONDS.sleep(2L); } catch (InterruptedException e) { e.printStackTrace(); } } FileUtils.deleteAllFiles(pluginScriptDir, true); } } /** * web向DC下发脚本或DC向web请求脚本过程中,每次都创建新的临时目录
* (DC向NC下发脚本完成后将删除临时目录) * * @return */ public static File getNewTempPluginDirectory() { File tempPluginDir = new File(Constants.PLUGIN_SCRIPT_FILE_DIR, System.currentTimeMillis()+""); if (!tempPluginDir.exists()) { tempPluginDir.mkdirs(); } return tempPluginDir; } }