539 lines
17 KiB
Java
539 lines
17 KiB
Java
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<String> ncNodesIpStrSet;
|
||
|
||
/**
|
||
* 向DC管理的所有有效服务器节点发送脚本文件
|
||
*
|
||
* @param dpluginScriptDir 脚本文件临时存储目录
|
||
*/
|
||
public ChangePluginScriptFile(File pluginScriptDir) {
|
||
this.pluginScriptDir = pluginScriptDir;
|
||
}
|
||
|
||
/**
|
||
* 向指定的NC节点发送脚本文件
|
||
*
|
||
* @param pluginScriptDir 脚本文件临时存储目录
|
||
* @param ncNodesIpStrSet 待接收脚本的NC节点列表
|
||
*/
|
||
public ChangePluginScriptFile(File pluginScriptDir, Set<String> ncNodesIpStrSet) {
|
||
this.pluginScriptDir = pluginScriptDir;
|
||
this.ncNodesIpStrSet = ncNodesIpStrSet;
|
||
}
|
||
|
||
|
||
/*
|
||
* 用于统计向特定节点发送的脚本文件
|
||
*/
|
||
private Map<String, List<File>> sendRecordList = new HashMap<String, List<File>>();
|
||
|
||
/*
|
||
* 统计文件剩余发送次数(用于清理DC临时脚本文件)
|
||
*/
|
||
private Map<String, Integer> fileSendLastCount = new HashMap<String, Integer>();
|
||
|
||
|
||
@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<File> files = FileUtils.listFiles(pluginScriptDir, null, false);
|
||
|
||
if (ncNodesIpStrSet == null) {
|
||
// 未指定接收的NC节点时,根据检测设置确定待接收脚本的NC节点
|
||
Map<String, SetInfo> setInfoMap = new HashMap<String, SetInfo>();
|
||
List<SetInfo> 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<NodeModel> 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<File> files = new ArrayList<File>();
|
||
files.add(pluginFile);
|
||
sendRecordList.put(nodeIp, files);
|
||
}
|
||
}
|
||
|
||
protected class SendPluginScriptFile extends SocketUtils implements Callable<Object> {
|
||
private String cmd;
|
||
private List<File> fileList;
|
||
|
||
public SendPluginScriptFile(String ip, List<File> 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<String, String> recordContent = new HashMap<String, String>();
|
||
HashSet<String> pluginFileNames = new HashSet<String>();
|
||
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<String> prefixNameList = new ArrayList<String>();
|
||
try {
|
||
Set<String> ipList = new HashSet<String>(1);
|
||
ipList.add(ip);
|
||
task = new ChangePluginScriptFile(tempPluginDir, ipList);
|
||
|
||
dao = new CommonDao();
|
||
CommonService service = new CommonService(dao);
|
||
List<SetInfo> 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<String, String> recordContent = new HashMap<String, String>();
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 解析失败暂存信息,重新发送脚本文件<br/>
|
||
*
|
||
* @param mrlList
|
||
*/
|
||
public static void sendPluginFileBaseOnEventRecord(List<EventRecordLibrary> recordList) {
|
||
if(recordList == null || recordList.isEmpty()) {
|
||
return;
|
||
}
|
||
|
||
// W2S [脚本名前缀,...]
|
||
Set<String> w2sDetecSetInfos = new HashSet<String>();
|
||
|
||
// S2C key:NC地址, value:[脚本名前缀,...]
|
||
Map<String, Set<String>> s2cDetecSetInfos = new HashMap<String, Set<String>>();
|
||
|
||
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<String> scriptNameSet = s2cDetecSetInfos.get(ip);
|
||
if(scriptNameSet == null) {
|
||
scriptNameSet = new HashSet<String>();
|
||
}
|
||
scriptNameSet.add(scriptName);
|
||
s2cDetecSetInfos.put(ip, scriptNameSet);
|
||
}
|
||
}
|
||
}
|
||
|
||
changeService.deleteEventRecordByIds(record.getId() + "");
|
||
}
|
||
|
||
} catch (SQLException e) {
|
||
logger.error("Delete EventRecordLibrary", e);
|
||
} finally {
|
||
if (dao != null) {
|
||
dao.close();
|
||
dao = null;
|
||
}
|
||
}
|
||
|
||
|
||
// 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<String, String> recordContent = new HashMap<String, String>();
|
||
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<Entry<String, Set<String>>> it = s2cDetecSetInfos.entrySet().iterator();
|
||
while(it.hasNext()) {
|
||
Entry<String, Set<String>> entry = it.next();
|
||
Set<String> recvIpSet = Sets.newHashSet(entry.getKey());
|
||
File tempPluginDir = ChangePluginScriptFile.getNewTempPluginDirectory();
|
||
ChangePluginScriptFile task = new ChangePluginScriptFile(tempPluginDir, recvIpSet);
|
||
Set<String> 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<String, String> recordContent = new HashMap<String, String>();
|
||
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());
|
||
task.new DeletePluginScriptDirAfterSending().run();
|
||
} 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<String> prefixNames) {
|
||
GetScriptFileFromWeb task = null;
|
||
task = this.new GetScriptFileFromWeb(dir, prefixNames);
|
||
FutureTask<Object> future = new FutureTask<Object>(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<String> 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<Entry<String, Integer>> iterator = fileSendLastCount.entrySet().iterator();
|
||
while (iterator.hasNext()) {
|
||
Entry<String, Integer> entry = iterator.next();
|
||
if(entry.getValue() == 0) {
|
||
iterator.remove();
|
||
}
|
||
}
|
||
try {
|
||
TimeUnit.SECONDS.sleep(2L);
|
||
} catch (InterruptedException e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
logger.debug("删除临时目录" + pluginScriptDir.getAbsolutePath());
|
||
FileUtils.deleteAllFiles(pluginScriptDir, true);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* web向DC下发脚本或DC向web请求脚本过程中,每次都创建新的临时目录<br/>
|
||
* (DC向NC下发脚本完成后将删除临时目录)
|
||
*
|
||
* @return
|
||
*/
|
||
public static File getNewTempPluginDirectory() {
|
||
File tempPluginDir = new File(Constants.PLUGIN_SCRIPT_FILE_DIR, System.currentTimeMillis()+"");
|
||
if (!tempPluginDir.exists()) {
|
||
tempPluginDir.mkdirs();
|
||
logger.debug("创建临时目录" + tempPluginDir.getAbsolutePath());
|
||
}
|
||
return tempPluginDir;
|
||
}
|
||
} |