/* * 著作権表記 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.DeliveryMode; 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 org.springframework.util.StringUtils; 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.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; } /** * 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); cih.setVersion(Integer.parseInt(model.getMqcih().getVersion())); cih.setFormat(model.getMqcih().getFormat()); cih.setFlags(Integer.parseInt(model.getMqcih().getFlags())); cih.setReturnCode(Integer.parseInt(model.getMqcih().getReturnCode())); cih.setCompCode(Integer.parseInt(model.getMqcih().getCompCode())); cih.setReason(Integer.parseInt(model.getMqcih().getReason())); cih.setOutputDataLength(Integer.parseInt(model.getMqcih().getOutputDataLength())); cih.setADSDescriptor(Integer.parseInt(model.getMqcih().getAdsDescriptor())); cih.setTaskEndStatus(Integer.parseInt(model.getMqcih().getTaskEndStatus())); cih.setFunction(model.getMqcih().getFunction()); cih.setAbendCode(model.getMqcih().getAbendCode()); cih.setReplyToFormat(model.getMqcih().getReplyToFormat()); cih.setFacilityLike(model.getMqcih().getFacilityLike()); cih.setAttentionId(model.getMqcih().getAttentionId()); cih.setStartCode(model.getMqcih().getStartCode()); cih.setCancelCode(model.getMqcih().getCancelCode()); cih.setErrorOffset(Integer.parseInt(model.getMqcih().getErrorOffset())); } 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 { boolean adsExistFlag = true; if (ads.isEmpty()) { adsExistFlag = false; } if (recMapVecModel != null) { convRecMapVec = characterCodeConverter.encodeVectorData(transactionId, recMapVecModel, 48, adsExistFlag); } if (adsExistFlag) { 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())); // Set Expiry and Persistence) String str = model.getMqmd().getExpiry(); long expiry = StringUtils.hasLength(str) ? Long.parseLong(str) : 1200000; logger.info("Expiry = " + expiry ); if(expiry > 1000) { // Set expiry when 1 second over jmsProducer.setTimeToLive(expiry); } str = model.getMqmd().getPersistence(); int deliveryMode = StringUtils.hasLength(str) ? Integer.parseInt(str) : DeliveryMode.PERSISTENT; logger.info("DeliveryMode = " + deliveryMode ); if(deliveryMode == DeliveryMode.NON_PERSISTENT) { jmsProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); } 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; } /** * 画面コードチェック *

* トランザクション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> TelegramInfoMap = telegramInfoComponent.getTelegramInfoMap(); if (!TelegramInfoMap.containsKey(transactionId)) { logger.error(messageSource.getMessage(MqSpringMessageId.SYS7063E)); throw new MqSpringException(MqSpringMessageId.SYS7063E, HttpStatus.BAD_REQUEST); } } }