/* * 著作権表記 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