/* * 著作権表記 TODO 要否をお客様に確認 */ package com.pgf.mqspring.service.impl; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.text.MessageFormat; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; import javax.jms.BytesMessage; import javax.jms.CompletionListener; import javax.jms.Destination; import javax.jms.JMSContext; import javax.jms.JMSException; import javax.jms.JMSProducer; import javax.jms.Message; import javax.xml.bind.DatatypeConverter; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.http.HttpStatus; import org.springframework.jms.core.JmsTemplate; import org.springframework.stereotype.Service; import com.ibm.mq.constants.CMQC; import com.ibm.mq.headers.MQCIH; import com.pgf.mqspring.component.CharacterCodeConverterComponent; import com.pgf.mqspring.component.MqSpringMessageSourceComponent; import com.pgf.mqspring.component.TelegramInfoComponent; import com.pgf.mqspring.constant.BytesMessageKey; import com.pgf.mqspring.constant.MqSpringConst; import com.pgf.mqspring.constant.MqSpringMessageId; import com.pgf.mqspring.exception.MqSpringException; import com.pgf.mqspring.model.ReceiveMapVectorRequestModel; import com.pgf.mqspring.model.ReplyRequestModel; import com.pgf.mqspring.model.TelegramInfoModel; import com.pgf.mqspring.model.TestModel; import com.pgf.mqspring.service.MqSendService; /** * MQ送信用サービス実装クラス *
* 指定されたキューに対しメッセージを送信する。 */ @Service @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class MqSendServiceImpl implements MqSendService { /** JMSテンプレート */ private JmsTemplate jmsTemplate = null; /** キュー */ private String queue = MqSpringConst.BLANK; /** メッセージID */ private String messageId = MqSpringConst.BLANK; /** キューフォーマット */ private static final String QUE_FORMAT = "queue:///{0}?targetClient=1"; /** ロガー */ private static final Logger logger = LogManager.getLogger(); /** 電文情報クラス */ @Autowired private TelegramInfoComponent telegramInfoComponent; /** 文字コード変換クラス */ @Autowired private CharacterCodeConverterComponent characterCodeConverter; /** MqSpringメッセージソースクラス */ @Autowired private MqSpringMessageSourceComponent messageSource; /** 受信キュー名 */ @Value("${ibm.mq.queueName.receive}") private String receiveQueueName; /** JMS_X_ユーザーID */ @Value("${ibm.mq.user}") private String jmsXUserId; /** * MQ送信用サービス実装クラスのコンストラクタ * * @param template Jmsテンプレート * @param commonService コード変換サービスクラス */ public MqSendServiceImpl(JmsTemplate template) { this.jmsTemplate = template; } // TODO ITa後削除対象(テスト時の問題切り分け用) public String sendRawData(TestModel model) { // final String msgId = "20220912093247445184"; final String correId = "AMQ!NEW_SESSION_CORRELID"; try { JMSProducer jmsProducer = jmsTemplate.getConnectionFactory().createContext().createProducer(); jmsProducer.setAsync(new CompletionListener() { @Override public void onCompletion(Message msg) { try { messageId = msg.getJMSMessageID(); logger.info("Send Message ID=" + messageId); } catch (JMSException e) { e.printStackTrace(); } System.out.println(messageId); } @Override public void onException(Message msg, Exception e) { System.out.println(e.getMessage()); } }); Destination dest = jmsTemplate.getConnectionFactory().createContext().createQueue(queue); Destination reply = jmsTemplate.getConnectionFactory().createContext().createQueue("QL.MDH01.REPLY"); BytesMessage bm = jmsTemplate.getConnectionFactory().createContext().createBytesMessage(); bm.writeBytes(createRawDataMessage(model)); bm.setStringProperty("JMS_IBM_Format", CMQC.MQFMT_CICS); bm.setIntProperty("JMS_IBM_Encoding", CMQC.MQENC_NATIVE); bm.setIntProperty("JMS_IBM_Character_Set", 932); //bm.setJMSMessageID(msgId); bm.setJMSCorrelationID(correId); bm.setJMSReplyTo(reply); bm.setStringProperty("JMSXUserID", "GETS"); jmsProducer.send(dest, bm); return "200"; } catch (Exception ex) { ex.printStackTrace(); return "500"; } } /** * Mqメッセージ送信処理 *
* 送信用キューにメッセージを送信する。
* リクエストパラメーターの画面コードチェックを行う。
* MQCIHの電文組立処理を行う。
* MQCIHの電文組立処理にて例外が発生した場合
* エラーログを出力する
* ・メッセージID:SYS7070E
* ・発生した例外:Exception
* MqSpringExceptionの例外をスローする。以下引数
* ・メッセージID:SYS7070E
* ・HttpStatus:BAD_REQUEST
* MQCIHの書き込み処理を行う。
* MQCIHの書き込み処理にて例外が発生した場合
* エラーログを出力する
* ・メッセージID:SYS7070EE
* ・発生した例外:IOException
* MqSpringExceptionの例外をスローする。以下引数
* ・メッセージID:SYS7070E
* ・HttpStatus:INTERNAL_SERVER_ERROR
* 送信メッセージの文字コードをSJISからEBCDICに変換する。
* 文字コードの変換処理にて例外が発生した場合
* エラーログを出力する
* ・メッセージID:SYS7070E
* ・発生した例外:Exception
* MqSpringExceptionの例外をスローする。以下引数
* ・メッセージID:SYS7070E
* ・HttpStatus:BAD_REQUEST
* メッセージ送信イベント処理(非同期)を指定します。
* メッセージが正常に送信された場合
* メッセージ送信後に採番されたJMSメッセージIDを取得する。
* JMSメッセージIDを設定する際に例外が発生した場合
* エラーログを出力する
* ・メッセージID:SYS7070E
* ・発生した例外:Exception
* 確認応答が受信されない場合
* エラーログを出力する
* ・メッセージID:SYS7007E
* ・発生した例外:Exception
* 編集した電文をログ出力し、指定されたキューへ送信する。
* 送信用キューへのメッセージ送信処理にて例外が発生した場合
* エラーログを出力する
* ・メッセージID:SYS7005E
* ・発生した例外:Exception
* MqSpringExceptionの例外をスローする。以下引数
* ・メッセージID:SYS7005E
* ・HttpStatus:BAD_REQUEST
*
* @param model 送信リクエスト格納用モデルクラス
* @return なし
*/
public void sendMqMessage(ReplyRequestModel model) {
logger.debug("sendMqMessage start");
ReceiveMapVectorRequestModel recMapVecModel = model.getSendMessage().getReceiveMapVector();
String ads = model.getSendMessage().getAds();
String transactionId = model.getMqcih().getTransactionId();
logger.debug("Ads encode前:" + ads);
// 画面コードチェック
checkDisplayCode(transactionId);
MQCIH cih = new MQCIH();
try {
cih.setUOWControl(Integer.parseInt(model.getMqcih().getUowControl()));
cih.setGetWaitInterval(Integer.parseInt(model.getMqcih().getGetWaitInterval()));
cih.setLinkType(Integer.parseInt(model.getMqcih().getLinkType()));
cih.setFacilityKeepTime(Integer.parseInt(model.getMqcih().getFacilityKeepTime()));
cih.setConversationalTask(Integer.parseInt(model.getMqcih().getConversationalTask()));
cih.setFacility(DatatypeConverter.parseHexBinary(model.getMqcih().getFacility()));
cih.setAuthenticator(model.getMqcih().getAutherticator());
cih.setTransactionId(transactionId);
} catch (Exception e) {
logger.error(messageSource.getMessage(MqSpringMessageId.SYS7070E), e);
throw new MqSpringException(MqSpringMessageId.SYS7070E, HttpStatus.BAD_REQUEST);
}
byte[] header = null;
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
cih.write(new DataOutputStream(out), CMQC.MQENC_NATIVE, 932);
header = out.toByteArray();
} catch (IOException e) {
logger.error(messageSource.getMessage(MqSpringMessageId.SYS7070E), e);
throw new MqSpringException(MqSpringMessageId.SYS7070E, HttpStatus.INTERNAL_SERVER_ERROR);
}
byte[] convRecMapVec = null;
byte[] convAds = null;
try {
if (recMapVecModel != null) {
convRecMapVec = characterCodeConverter.encodeVectorData(transactionId, recMapVecModel, 48);
}
if (!ads.isEmpty()) {
convAds = characterCodeConverter.encodeAdsData(transactionId, ads);
}
} catch (Exception e) {
logger.error(messageSource.getMessage(MqSpringMessageId.SYS7070E), e);
throw new MqSpringException(MqSpringMessageId.SYS7070E, HttpStatus.BAD_REQUEST);
}
logger.debug("Mqcih encode結果:" + Arrays.toString(header));
logger.debug("RecMapVec encode結果:" + Arrays.toString(convRecMapVec));
logger.debug("Ads encode結果:" + Arrays.toString(convAds));
try (JMSContext jmsContext = jmsTemplate.getConnectionFactory().createContext()) {
JMSProducer jmsProducer = jmsContext.createProducer();
jmsProducer.setAsync(new CompletionListener() {
/**
* メッセージ送信完了時処理
*
* メッセージ送信後に採番されたJMSメッセージIDを取得する。
* メッセージID取得処理で例外が発生した場合
* エラーログを出力する。以下引数
* ・メッセージID:SYS7073E
* ・発生した例外:JMSException
*
* @param msg メッセージ
*/
@Override
public void onCompletion(Message msg) {
try {
messageId = msg.getJMSMessageID();
logger.info("Send Message ID=" + messageId);
} catch (JMSException e) {
logger.error(messageSource.getMessage(MqSpringMessageId.SYS7073E), e);
}
}
/**
* 例外発生時処理
*
* エラーログを出力する。以下引数
* ・メッセージID:SYS7007E
* ・発生した例外:Exception
*
* @param msg JMSメッセージ
* @param e Exception
*/
@Override
public void onException(Message msg, Exception e) {
logger.error(messageSource.getMessage(MqSpringMessageId.SYS7007E), e);
}
});
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
Destination dest = jmsContext.createQueue(queue);
Destination reply = jmsContext.createQueue(receiveQueueName);
BytesMessage bm = jmsContext.createBytesMessage();
bm.writeBytes(header);
out.write(header);
if (convRecMapVec != null) {
bm.writeBytes(convRecMapVec);
out.write(convRecMapVec);
}
if (convAds != null) {
bm.writeBytes(convAds);
out.write(convAds);
}
bm.setStringProperty(BytesMessageKey.JMS_IBM_Format.name(), CMQC.MQFMT_CICS);
bm.setIntProperty(BytesMessageKey.JMS_IBM_Encoding.name(), CMQC.MQENC_NATIVE);
bm.setIntProperty(BytesMessageKey.JMS_IBM_Character_Set.name(), 943);
bm.setJMSCorrelationID(model.getMqmd().getCorrelId());
bm.setJMSReplyTo(reply);
bm.setStringProperty(BytesMessageKey.JMSXUserID.name(), jmsXUserId);
logger.info("(" + transactionId + ")MQPUT >>");
logger.info(DatatypeConverter.printHexBinary(out.toByteArray()));
jmsProducer.send(dest, bm);
}
logger.debug("sendMqMessage end");
} catch (Exception ex) {
logger.error(messageSource.getMessage(MqSpringMessageId.SYS7005E), ex);
throw new MqSpringException(MqSpringMessageId.SYS7005E, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
/**
* キュー取得
*
* キューを返却する * * @return キュー */ public String getQueue() { return queue; } /** * キュー設定 *
* メッセージフォーマットを行い、フォーマット結果をキューに設定する。以下引数
* ・キューフォーマット
* ・キュー
*
* @param que キュー
* @return 無し
*/
public void setQueue(String que) {
// example "queue:///QL.POC01.TEST2?targetClient=1"
queue = MessageFormat.format(QUE_FORMAT, que);
}
/**
* メッセージID取得
*
* メッセージIDを返却する * * @return メッセージID */ public String getMessageId() { return messageId; } /** * メッセージID設定 *
* メッセージIDを設定する * * @param messageId メッセージID * @return 無し */ public void setMessageId(String messageId) { this.messageId = messageId; } // TODO ITa後削除対象(テスト時の問題切り分け用) private byte[] createRawDataMessage(TestModel model) { final String mqcih1 = "4349482000000002000000b40000000000000000202020202020202000000000000000000000000000000000000001110002bf2000000002ffffffff000000b4000000000000000000000000" + model.getFacility()/*"0000000000000000"*/ + "202020202020202047455453333333332020202020202020202020202020202020202020202020204745303120202020202020202020202020202020202020202020202020202020202020202020202000000000000000000000000000000000"; final String mqcih2 = "4349482000000002000000b40000000000000000202020202020202000000000000000000000000000000000000001110002bf2000000002ffffffff000000b4000000000000000000000000" + model.getFacility()/*"0138000100000001"*/ + "202020202020202047455453333333332020202020202020202020202020202020202020202020204745303120202020202020202020202020202020202020202020202020202020202020202020202000000000000000000000000000000000"; final String mqcih3 = "4349482000000002000000b40000000000000000202020202020202000000000000000000000000000000000000001110002bf2000000002ffffffff000000b4000000000000000000000000" + model.getFacility()/*"0138000100000001"*/ + "202020202020202047455453333333332020202020202020202020202020202020202020202020204745303220202020202020202020202020202020202020202020202020202020202020202020202000000000000000000000000000000000"; final String mqcih4 = "4349482000000002000000b40000000000000000202020202020202000000000000000000000000000000000000001110002bf2000000002ffffffff000000b4000000000000000000000000" + model.getFacility()/*"0138000100000001"*/ + "202020202020202047455453333333332020202020202020202020202020202020202020202020204745303220202020202020202020202020202020202020202020202020202020202020202020202000000000000000000000000000000000"; final String mqcih5 = "4349482000000002000000b40000000000000000202020202020202000000000000000000000000000000000000001110002bf2000000002ffffffff000000b4000000000000000000000000" + model.getFacility()/*"0138000100000001"*/ + "20202020202020204745545333333333202020202020202020202020202020202020202020202020454d303420202020202020202020202020202020202020202020202020202020202020202020202000000000000000000000000000000000"; final String mqcih6 = "4349482000000002000000b40000000000000000202020202020202000000000000000000000000000000000000001110002bf2000000002ffffffff000000b4000000000000000000000000" + model.getFacility()/*"0138000100000001"*/ + "20202020202020204745545333333333202020202020202020202020202020202020202020202020454d303420202020202020202020202020202020202020202020202020202020202020202020202000000000000000000000000000000000"; final String vecAds2 = "000000ecf1f8f0f2c9404040f0f0f0f0e8404040d4c7c5f0f1f0f040d4c7c5f0f1f0f0407d40404000000000000000bb0000000000000000000000000000cc0000d4c7c5f0f1f0f0400000cc0000" + model.getDate()/*"f0f961f1f261f2f2"*/ + "0000cc0000" + model.getTime()/*"f0f97af3f27af4f4"*/ + "0000cc0000c7c5e3e2404040400000cc0000c7c5e3e2f3f3f3f30000cc000040404040404040400000cc000040404040404040400000cc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; final String vecAds4 = "000000f8f1f8f0f2c9404040f0f0f0f0e8404040d4c7c5f0f2f0f040d4c7c5f0f2f0f0407d40404000000000000000c60000000000000000000000000000cc000040404040404040400000cc0000" + model.getDate()/*"f0f961f1f261f2f2"*/ + "0000cc0000c5d4f0f40000cc00004040404040404040404040404040404040404040404040404040404040404040404040404040404040400000cc0000f0f97af3f27af4f40000cc000040400000cc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; final String vecAds6 = "000009ccf1f8f0f2c9404040f0f0f0f0e8404040d4c5d4f0f4f0f040d4c5d4f0f4f0f0407d404040000000000000099a0000000000000000000000000000cc0000c5d4f0f4404040400000cc000040404040404040400000cc000040404040404040404040400000cc000040404040404040400000cc000040404040404040404040400000cc000040404040404040404040400000cc0000f8f3f0f0f9f4f3f2f9f30000cc0000f2f0f2f3f0f3f1f60000cc000040404040404040400000cc0000400000cc0000400000cc0000404040404040400000cc00004040404040400000cc000040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040400000cc000040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040404040404040404040404040404040404040404040400000cc00004040404040404040404040400000cc000040404040404040404040400000cc000040404040404040404040400000cc000040404040404040400000cc00004040404040400000cc000040404040404040404040400000cc00004040404040404040404040400000cc00004040404040404040404040400000cc0000404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040404040400000"; logger.info("Send Destination=" + queue); logger.info("msgKind = " + model.getMsgKind()); logger.info("facility = " + model.getFacility()); logger.info("date = " + model.getDate()); logger.info("time = " + model.getTime()); byte[] bytes = null; switch (model.getMsgKind()) { case "1": bytes = DatatypeConverter.parseHexBinary(mqcih1); break; case "2": bytes = DatatypeConverter.parseHexBinary(mqcih2 + vecAds2); break; case "3": bytes = DatatypeConverter.parseHexBinary(mqcih3); break; case "4": bytes = DatatypeConverter.parseHexBinary(mqcih4 + vecAds4); break; case "5": bytes = DatatypeConverter.parseHexBinary(mqcih5); break; case "6": bytes = DatatypeConverter.parseHexBinary(mqcih6 + vecAds6); break; default: bytes = DatatypeConverter.parseHexBinary(mqcih1); break; } return bytes; } /** * 画面コードチェック *
* トランザクションIDがnull または トランザクションIDが空の場合
* メッセージID:SYS7027Eのエラーメッセージを出力する。
* MqSpringExceptionの例外をスローする。以下引数
* ・メッセージID:SYS7027E
* ・HttpStatus:BAD_REQUEST
* 電文情報マップを取得する
* トランザクションIDのキーが電文情報マップに存在しない場合
* メッセージID:SYS7063Eのエラーメッセージを出力する。
* MqSpringExceptionの例外をスローする。以下引数
* ・メッセージID:SYS7063E
* ・HttpStatus:BAD_REQUEST
*
* @param transactionId トランザクションID
* @return 無し
*/
private void checkDisplayCode(String transactionId) {
// 画面コードがセットされていない場合
if (Objects.isNull(transactionId) || transactionId.isEmpty()) {
logger.error(messageSource.getMessage(MqSpringMessageId.SYS7027E));
throw new MqSpringException(MqSpringMessageId.SYS7027E, HttpStatus.BAD_REQUEST);
}
// 画面コードに対するIBM電文定義マスタが存在しない場合
Map