package com.citic.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.HashMap;
import java.util.regex.Pattern;
import com.citic.util.comm.*;
import com.citic.util.MD5Util;
import com.ibm.mq.MQEnvironment;
import com.ibm.mq.MQException;
import com.ibm.mq.MQGetMessageOptions;
import com.ibm.mq.MQMessage;
import com.ibm.mq.MQPutMessageOptions;
import com.ibm.mq.MQQueue;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.constants.MQConstants;
/**
* 本类主要功能:实现MQ文件的发送和接收
* 因主要是对同一个MQ配置,所以相同的参数采用静态变量,如队列管理器创建非常占用时间
* ,所以静态处理,不管是发送还是接收都采用同一个
* runGoupReceier(int receivesize) 根据传入变量来指定获取MQ条数(可在config.properties中配置)
* runGoupReceier() 默认获取MQ条数20
* runGoupSender(String[] filelist) 根据数组中列出的全部文件名发送
* runGoupSender(String pattern) 根据模式匹配发送数据
* @author db2admin
*
*/
public class MQUtil implements IConstants{
final static int BUFFER_LEN = 1024 * 1024; // 定义发送文件的大小
private static MQQueueManager qmgr; // 连接到队列管理器
private static MQQueue queue; // 传输队列
private static String iqueueName,oqueueName; // 队列名称
private static String host = "127.0.0.1"; // 队列名称
private static String port = "1414"; // 侦听器的端口号
private static String channel = "SYSTEM.BKR.CONFIG"; // 通道名称
private static String qmgrName; // 队列管理器
private MQMessage message; // 创建消息缓冲
private static MQPutMessageOptions pmo; // 设置获取消息选项
private static MQGetMessageOptions gmo; // 设置获取消息选项
private static boolean rewriteflag=false; //收取MQ的文件时候是否需要对重复文件进行收取,false则不收
private static int opnOptn=0;
private static String ccsid ;
private String file_dir = null;
private static String dval=ConfigFileUtil.getValue("debuglevel");
private static int debuglevel=("".equals(dval)?ALL:Integer.parseInt(dval));
private char flag='S'; //S/R 发送或接收
private String pstr;
private File[] flist;
private static int readpertime = 20; // 每次读取MQ数量,默认为20条
private int readcnt=0; //每个周期实际读取MQ信息数,<=readpertime
private String[] strarr = null;
private HashMap<String,String> datahm=null;
private HashMap<String,String> md5map=new HashMap<String, String>();
private String charset=ConfigFileUtil.getValue("charset");
//实现对队列管理器的初始化
private static void getInstance(){
if(qmgr==null){
/* 连接到队列管理器 */
initproperty();
try {
qmgr = new MQQueueManager(qmgrName);
} catch (MQException e) {
CommFun.log(ERR, "创建"+qmgrName+"失败!退出!");
e.printStackTrace();
throw new RuntimeException();
} //经监控,此步大概需要10秒左右,所以重点优化
}
CommFun.log(INFO, "连接" + qmgrName + "成功![host:" + host + ",port:"
+ port + ",qmgrName:" + qmgrName + ",iqueueName:" + iqueueName
+ ",oqueueName:" + oqueueName + ",channel:" + channel
+ ",ccsid:" + ccsid + "]");
}
//队列初始化中
private void getInstance(String sflag){
if (!"".equals(sflag) && sflag != null && sflag.length() > 0) {
flag = sflag.charAt(0);
}
getInstance();
}
private void init(){
String queuename="";
file_dir = ConfigFileUtil.getInstance().getPathName();
if(flag=='S'){
/* 设置队列打开选项以输 */
opnOptn = MQConstants.MQOO_FAIL_IF_QUIESCING
| MQConstants.MQOO_OUTPUT;
// 只是单纯的收取数据,非破坏性
// opnOptn = MQConstants.MQOO_BROWSE
// | MQConstants.MQOO_FAIL_IF_QUIESCING
// | MQConstants.MQOO_INQUIRE;
queuename = oqueueName;
file_dir += "send";
} else {
/* 设置队列打开选项以输 */
opnOptn = MQConstants.MQOO_INPUT_AS_Q_DEF
| MQConstants.MQOO_FAIL_IF_QUIESCING
| MQConstants.MQOO_INQUIRE;
queuename = iqueueName;
file_dir += "receive";
}
try {
queue = qmgr.accessQueue(queuename, opnOptn, null, null, null);
CommFun.log(INFO, "queue's name:" + queuename + ",file_dir:["
+ file_dir + "]");
} catch (MQException e) {
CommFun.log(ERR, "队列访问失败:"+e.getReason());
commit();
throw new RuntimeException();
}
}
/**
* 发送的单条主程序
*
* @throws Exception
*/
private void sendMessages(String filename) {
/* 设置放置消息选项 */
message = new MQMessage();
pmo = new MQPutMessageOptions();
pmo.options = MQConstants.MQPMO_LOGICAL_ORDER
+ MQConstants.MQPMO_SYNCPOINT;
message.characterSet=Integer.parseInt(ccsid);;
try{
FileInputStream fis = new FileInputStream(new File(filename));
byte buffer[] = new byte[fis.available()];
int count = 0;
while (true) {
count = fis.read(buffer);
if (count == -1) {
break;
}
message.write(buffer);
System.out.println(buffer.length);
if (count < BUFFER_LEN) {
System.out.println("count:"+count);
}
queue.put(message, pmo);
// qmgr.commit();
}
fis.close();
}catch (MQException mqe) {
CommFun.log(ERR, "["+filename+"]MQ-put信息失败!");
mqe.printStackTrace();
commit();
throw new RuntimeException();
} catch (FileNotFoundException e) {
CommFun.log(ERR, "["+filename+"]文件不存在");
e.printStackTrace();
commit();
throw new RuntimeException();
} catch (IOException e) {
CommFun.log(ERR, "["+filename+"]文件操作错误");
e.printStackTrace();
commit();
throw new RuntimeException();
}
}
//批量发送
private void runGoupSender() {
//0.获取队列管理器
getInstance("S");
//1.初始化队列
init();
String filePath = file_dir;
File file = new File(filePath);
File[] filelist=flist;
// pstr="PSIS(900|802|1.*).*_S\\.xml";
if (pstr != null && !"".equals(pstr)) {
filelist = file.listFiles(new FilenameFilter() {
private Pattern pattern = Pattern.compile(pstr
.replace("_S", "") + ".*_S\\.xml");
@Override
public boolean accept(File dir, String name) {
return pattern.matcher(name).matches();
}
});
}
int fcount=1;
for (File f : filelist) {
CommFun.log(debuglevel, f.getAbsolutePath());
//sendMessages(filePath + File.separator + f.getName());
sendMessages(f.getAbsolutePath());
CommFun.log(INFO, "MQ发送第["+filelist.length+":"+(fcount++)+"]个文件完毕!");
}
//9.发送后处理
// commit();
System.out.println("\n Messages successfully Send ");
}
//主体获取MQ信息,对出现MD5值重复的数据进行处理,原则上全部收取下来,但是并不写入
private void getGroupMessages() {
/* 设置获取消息选项 */
CommFun.log(debuglevel);
gmo = new MQGetMessageOptions();
CommFun.log(debuglevel);
gmo.options = MQConstants.MQGMO_FAIL_IF_QUIESCING
+ MQConstants.MQGMO_SYNCPOINT + MQConstants.MQGMO_WAIT
+ MQConstants.MQGMO_ALL_MSGS_AVAILABLE
+ MQConstants.MQGMO_LOGICAL_ORDER;
/* 设置等待时间限制 */
gmo.waitInterval = 5000;
gmo.matchOptions = MQConstants.MQMO_MATCH_GROUP_ID;
int cnt = 0;
int counter=0;
int qdepth=getQueueDepth();
CommFun.log(debuglevel,"depth:"+getQueueDepth());
/**
* 20170515添加对接收的MD5值当天数据载入,重复文件不再接收
* 当前目录MD5.txt,其中的格式如FileOperation中
* 的stringbuffer2file(StringBuffer[] stb, String filename)方法
* "filename:"+filename+",strmd5:"+strmd5+",filemd5:"+filemd5
*/
String md5file=file_dir + File.separator + md5filename;
if(qdepth==0){
CommFun.log(debuglevel, "队列深度为0,不需要载入MD5文件");
}else{
CommFun.log(debuglevel, "MD5文件:"+md5file);
md5map=FileOperation.loadMD5txt(file_dir);
if(md5map==null||md5map.size()==0){
CommFun.log(debuglevel, "MD5文件:"+md5file+"不存在!");
}
}
/* 处理组消息 */
String fileName;
datahm=new HashMap<String, String>();
while (cnt < readpertime) {
try{
/* 创建消息缓冲 */
message = new MQMessage();
queue.get(message, gmo);
CommFun.log(INFO,"cnt:"+cnt+",read:"+readpertime);
int msgLength = message.getMessageLength();
byte[] buffer = new byte[msgLength];
CommFun.log(INFO,"msgLength:" + msgLength);
message.readFully(buffer);
String st1 = new String(buffer, ("".equals(charset)?"UTF-8":charset)).replaceAll("\\r", "");
CommFun.log(INFO, "获取MQ数据:第"+(counter++)+"次读取:当前有效条数:" + cnt + ":buffer:[" + buffer
+ "],str1:[" + st1.substring(0, 200) + "]");
// strarr[cnt]=new String(buffer,"GBK");
String filenameEx=file_dir + File.separator
+ "SUPIS" + CommFun.strNowRand() + ".xml";
CommFun.log(0,"strarr:" + cnt + ":[" + st1 + "]:inMsg:["+message+"]");
message.clearMessage();
String md5str=MD5Util.getMD5String(st1);
if(md5map.containsKey(md5str)){
CommFun.log(INFO, ":MD5["+md5str+"]根据MD5值计算重复,跳过!");
//MD5重复文件控制写入,从MQ上收取下来的数据很多重复,所以进行控制
if(rewriteflag){
StringBuffer[] sbf = { new StringBuffer(st1) };
FileOperation.stringbuffer2file(sbf, filenameEx);
}
continue;
}
//进行MD5值计算,用来对以后的数据去重
String oldvalue=ConfigFileUtil.getValue("md5");
ConfigFileUtil.setValue("md5", "true");
StringBuffer[] sbf = { new StringBuffer(st1) };
FileOperation.stringbuffer2file(sbf, filenameEx,md5str);
ConfigFileUtil.setValue("md5", oldvalue);
//strarr[cnt] = st1;
datahm.put(st1, filenameEx);
md5map.put(md5str,"");
readcnt=++cnt;
}catch(MQException mqe){
if(mqe.reasonCode!=MQConstants.MQRC_NO_MSG_AVAILABLE){
//如果出错,则进行重置参数
cnt=0;
readcnt=0;
strarr=null;
datahm=null;
try {
CommFun.log(ERR, "出问题,返回:"+mqe.getMessage());
qmgr.backout();
} catch (MQException e) {
CommFun.log(ERR, "出问题,返回:"+e.getMessage());
commit();
e.printStackTrace();
throw new RuntimeException();
}
}else{
readcnt=cnt;
// commit();
CommFun.log(INFO, "正常结束,队列取完,readcnt为:"+readcnt);
break;
}
}catch(Exception e){
CommFun.log(ERR,"出错:"+e.getMessage());
e.printStackTrace();
commit();
throw new RuntimeException();
}
CommFun.log(debuglevel);
}
CommFun.log(debuglevel,"字符串数据个数为:"+datahm.size()+",cnt:"+cnt+",队列中还剩余:["+Math.max(0,(qdepth-counter))+"]条!");
}
/**
* MQConfig.getInstance(key) 1生产2测试
*/
private static void initproperty() {
String mqkey = ConfigFileUtil.getValue("MQKEY");
mqkey = (mqkey == "" ? "2" : mqkey);
if (iqueueName == null) {
qmgrName = ConfigFileUtil.getValue(mqkey+"_MQ_MANAGER");
iqueueName = ConfigFileUtil.getValue(mqkey+"_MQ_IQUEUE_NAME");
oqueueName = ConfigFileUtil.getValue(mqkey+"_MQ_OQUEUE_NAME");
channel = ConfigFileUtil.getValue(mqkey+"_MQ_CHANNEL");
host = ConfigFileUtil.getValue(mqkey+"_MQ_HOST_NAME");
port = ConfigFileUtil.getValue(mqkey+"_MQ_PROT");
ccsid = ConfigFileUtil.getValue(mqkey+"_MQ_CCSID");
}
/* 为客户机连接设置MQEnvironment属性 */
MQEnvironment.hostname = host;
MQEnvironment.channel = channel;
MQEnvironment.port = Integer.parseInt(port);
MQEnvironment.CCSID = Integer.parseInt(ccsid);
}
//发送完后续处理
public void commit() {
CommFun.log(debuglevel, "提交后处理!");//
if (queue != null && queue.isOpen()) {
CommFun.log(debuglevel, "提交后处理,关闭队列!");
try {
queue.close();
} catch (MQException e) {
CommFun.log(ERR);
e.printStackTrace();
throw new RuntimeException();
}
}
if (qmgr != null && qmgr.isConnected()) {
CommFun.log(INFO, "提交后处理,关闭队列管理器!");
try {
qmgr.commit();
qmgr.disconnect();
} catch (MQException e) {
CommFun.log(debuglevel);
e.printStackTrace();
throw new RuntimeException();
}
}
CommFun.log(debuglevel, "提交后处理成功!");
}
//获取队列深度,一般接收时使用
public Integer getQueueDepth() {
Integer depth = 0;
try {
if (queue != null && queue.isOpen()) {
depth = queue.getCurrentDepth();
}
} catch (MQException e) {
e.printStackTrace();
commit();
throw new RuntimeException();
}
return depth;
}
//主体调用程序
//批量发送1:通过通配符
public void runGoupSender(String pattern) {
pstr=pattern;
runGoupSender();
}
//批量发送2:通过数组
public void runGoupSender(String[] filelist) {
CommFun.log(INFO, "############"+filelist.length);
if (filelist.length > 0) {
flist = new File[filelist.length];
for (int i = 0; i < filelist.length && filelist[i] != null
&& !"".equals(filelist[i]); i++) {
CommFun.log(debuglevel, filelist[i]);
flist[i] = new File(filelist[i]);
}
}
runGoupSender();
}
//接收MQ,设置接收个数
public HashMap<String,String> runGoupReceier(int inputSize) {
if (inputSize > 0) {
readpertime = inputSize;
}
return runGoupReceier();
}
//获取数据
public HashMap<String,String> runGoupReceier() {
// strarr = new String[readpertime];
CommFun.log(INFO, "此次所取的MQ条数为:[" + readpertime + "]");
// 0.获取队列管理器
getInstance("R");
// 1.初始化队列
init();
getGroupMessages();
CommFun.log(debuglevel);
//String[] strarr1 = new String[readcnt];
//System.arraycopy(strarr, 0, strarr1, 0, readcnt);
return datahm;
}
}