본문으로 건너뛰기
버전: 3.4.4

헤더파싱프로그램

프로그램용도구현할 Java인터페이스적용할 설정화면유의사항
라우터 프로그램UnmarshalProcessor라우터정보>처리프로그램전문을 BXI가 이해할 수 있도록 변환하는 경우
라우터 프로그램MarshalProcessor라우터정보>처리프로그램BXI의 내부전문을 기관 혹은 채널에 전송할 경우

공통부 전문이 JSON, FLD, XML이 아니거나 전문 포맷이 특수한 형태인 경우, 헤더파싱 프로그램을 개발하여 적용할 수 있다.

개발방법

아래 예제는 Nexacro단말에서 사용하는 전문의 헤더를 Unmarshal하는 예제 프로그램이다. Nexacro단말의 전문 형식은 일반적인 XML과는 다르므로, 단말에서 제공하는 xapi를 시용하여 전문을 Unmarshal해야 한다.

Nexacro단말 전문 형식
<?xml version="1.0" encoding="UTF-8"?>
<Root xmlns="http://www.nexacroplatform.com/platform/dataset">
<Parameters />
<Dataset id="_ds_cmmHeader">
<ColumnInfo>
<Column id="stdMsgLen" type="STRING" size="8" />
<Column id="stdMsgVer" type="STRING" size="3" />
<Column id="guid" type="STRING" size="32" />
<Column id="guidSeq" type="STRING" size="3" />

<Column id="sq1RpesDeptCd" type="STRING" size="4" />
</ColumnInfo>
<Rows>
<Row>
<Col id="stdMsgLen">123</Col>
<Col id="stdMsgVer">123</Col>
<Col id="guid">abcdefg123456789123113</Col>
<Col id="guidSeq">1</Col>
<Col id="fstGuid">hijklmn1234567321312312</Col>
<Col id="recpSysCd">CORE1</Col>
<Col id="recpTrnsCd">SVC0011</Col>
<Col id="rsltRecpTrnsCd"></Col>
<Col id="msgClssCd">S</Col>
<Col id="syncClssCd">1234567</Col>

</Row>
</Rows>
</Dataset>
<Dataset id="ds_root">
<ColumnInfo>
<Column id="nodeNm" type="STRING" size="64" />
<Column id="instanceNm" type="STRING" size="64" />
<Column id="instCd" type="STRING" size="16" />

</ColumnInfo>
<Rows>
<Row>
<Col id="nodeNm">test</Col>
<Col id="instanceNm">testnode04</Col>
<Col id="instCd">A200</Col>

</Row>
</Rows>
</Dataset>
</Root>

1. Unmarshal 메소드

@Override
public void unmarshal(ProcessorExchange exchange) throws Exception {
// Check input parameter
ExchangeMessage bxiMessage = exchange.getBxiMessage();
if (ObjectUtil.isEmpty(bxiMessage)) {
return;
}
}

헤더 전문을 Unmarshal하는 메소드이다. ProcessorExchange객체에는 전문을 Unmarshal하는데 필요한 정보가 저장되어 있다.

2. 채널 수신 데이터 검증

// The message received from the Nexacro terminal is received via getMessage()
String message = bxiMessage.getMessage(String.class);
if (StringUtil.isEmpty(message)) {
ErrorLogger.errorLogging(bxiMessage, "BXIE02144");
throw new BxiException("BXIE02144");
}

BXI는 대외기관이나 단말에서 수신한 전문을 ExchangeMessage의 message필드에 저장한다.

전문의 헤더부 Unmarshal은 전체 전문이 저장된 message에서 데이터를 참조하여 헤더부를 Unmarshal하면 된다. 수신된 전문이 없으면 헤더부를 Unmarshal할 수 없으므로 전문 데이터가 있는지 검증하는 부분이다.

3. 채널 전문 헤더 레이아웃 조회

/** Query header layout information of system where Nexacro terminal is defined.
* The header layout uses the information registered in the common header layout
* of the system-specific business information
*/
BxiIntrnlSysBizIO intrnlSysBizInfo = getHeader(CamelHeader.INTERNAL_SYS_BIZ_INFO,
BxiIntrnlSysBizIO.class);

// Query message layout
String headerLayout = intrnlSysBizInfo.getStdMsgHdrLayout();
BxiMsgLayoutMngIO msgTrnsfrmInfo = LayoutUtil.selectMessageManagement(headerLayout);
if (ObjectUtil.isEmpty(msgTrnsfrmInfo)) {
ErrorLogger.errorLogging(bxiMessage, "BXIE02113", headerLayout);
throw new BxiException("BXIE02113", headerLayout);
}
Map<String, BxiMsgLayoutIO> layoutMap = LayoutUtil.selectBxiMsgLayout(headerLayout);

전문의 헤더부를 Unmarshal하려면 헤더 레이아웃을 알아야 한다. 채널단의 헤더 레이아웃은 FEP는 기관별업무정보에서 관리하고, MCI나 EAI는 시스템별업무정보에서 관리한다.

위의 프로그램은 MCI가 단말에서 수신된 헤더부를 Unmarshal하는 부분으로 시스템별업무정보를 조회하고, 시스템별업무정보의 공통 헤더 레이아웃으로 전문정보 레이아웃을 조회하였다.

4. Nexacro 단말에서 수신한 데이터 추출

// Extract data received from Nexacro terminal
InputStream inStream = new ByteArrayInputStream(message.getBytes());
HttpPlatformRequest xrequest = new HttpPlatformRequest(inStream);
xrequest.receiveData();

// Extract XML data from Request for Nexacro
PlatformData xdata = xrequest.getData();
logger.debug("request input xml data = [{}]", xdata.saveXml());

채널에서 수신한 데이터는 Nexacro 전문 형식을 사용한다. Nexacro 전문 형식의 데이터 추출은 입력 스트림을 만들어 사용하므로 입력 스트림을 생성한다.

다음으로 Nexacro 전문 형식에서 Platform데이터를 추출한다.

5. 헤더부 전문 Unmarshal

// Extract the header data from the extracted layout data
// and store it in Unmarshal and comHeader
Map<String, Object> header = new LinkedHashMap<String, Object>();
DataSet ds = xdata.getDataSet(FieldName.HEADER_DATASET_NAME); // "_ds_cmmHeader"
if (ds != null) {
// Nexacro header unmarshal
unmarshalHeader(ds, layoutMap, headerLayout, header);
} else {
ErrorLogger.errorLogging(bxiMessage, "BXIE02113", "nexacro");
throw new BxiException("BXIE02113", "nexacro");
}
if (ObjectUtil.isEmpty(header)) {
ErrorLogger.errorLogging(bxiMessage, "BXIE02113", headerLayout);
throw new BxiException("BXIE02113", headerLayout);
}
// Unmarshal data should be stored in comHeader.
bxiMessage.setComHeader(header);

앞의 Nexacro 전문 형식을 보면, Platform데이터에서 헤더부는 _ds_cmmHeader로 정의되어 있고, 개별부는 ds_root로 정의되어 있다.

이중 헤더부 데이터를 조회하여 전문 레이아웃에 정의된 필드 단위로 데이터를 추출하여 Map형식으로 변환한다. 실질적인 변환은 unmarshalHeader메소드를 참고한다.

이렇게 변환한 Map 형식의 헤더부는 다음 처리를 위하여 comHeader에 저장한다.

6. 전문정보 저장

// Save layout information
XmlTypeInfo xmlInfo = LayoutUtil.makeXmlTypeInfo(msgTrnsfrmInfo, 0);
bxiMessage.setComHeaderMsgInfo(xmlInfo);

전문정보는 BXI엔진에서 인터페이스를 식별하기 위해 전문에서 필요 데이터를 추출해야 한다.

보통은 채널 전문 헤더 레이아웃 조회에서 사용한 것처럼 시스템별업무정보에 등록된 레이아웃을 조회해서 사용할 수 있지만, Customizing 프로그램에서 다른 레이아웃을 사용할 수도 있으므로 사용한 전문 레이아웃 정보를 저장해야 한다.

Map 데이터를 'comHeader'에 저장 했으므로 전문 레이아웃 정보도 헤더부 영역인 'comHeaderMsgInfo'에 저장한다.

7. 개별부 전문분리

// Originally, we had to separate the header message from the whole message.
// but Nexacro can not be detached, so you can save the entire message as Body Message
bxiMessage.setBodyMessage(message);

헤더부를 Unmarshal한 이후에 전문에서 헤더부를 분리하고, 나머지 개별부만 bodyMessage에 저장하여 다음 처리인 개별부 Unmarshal를 해야한다.

위와 같이 처리하는 이유는 개별부를 Unmarshal하지 않은 상태에서 헤더부와 개별부를 분리하지 않으면, 개별부를 대내시스템에 전송할 수 없기 때문이다.

따라서 개별부를 Unmarshal하지 않는다면, 반드시 전문에서 헤더부를 분리하고 개별부만 bodyMessage에 저장해야 한다.

8. Nexacro 헤더부 전문 변환 처리

/**
* The layout field data is a field name defined in the layout
* and is retrieved from the dataset and stored in the map.
* If you are in a Sub layout, create a Map for the Sub layout and unmarshal it in the same way.
*/
private void unmarshalHeader(DataSet ds, Map<String, BxiMsgLayoutIO> layoutMap,
String headerLayout, Map<String, Object> colData) {

if (ObjectUtil.isEmpty(layoutMap)) {
// Inquiry message layout details
layoutMap = LayoutUtil.selectBxiMsgLayout(headerLayout);
if (ObjectUtil.isEmpty(layoutMap)) {
ErrorLogger.errorLogging("BXIE02158", headerLayout);
throw new BxiException("BXIE02158", headerLayout);
}
}

for (Entry<String, BxiMsgLayoutIO> entry : layoutMap.entrySet()) {
BxiMsgLayoutIO layout = entry.getValue();
JavaTypeEnum type = JavaTypeEnum.getByCode(layout.getFldTypeCd());
if (type == JavaTypeEnum.OMM) {
Map<String, Object> sub = new LinkedHashMap<String, Object>();
unmarshalHeader(ds, null, layout.getFldFormat(), sub);
colData.put(layout.getFldNm(), sub);
} else {
colData.put(layout.getFldNm(), ds.getObject(0, layout.getFldNm()));
}
}
}

Nexacro 전문을 레이아웃에 정의된 필드별로 Map으로 변환하는 부분이다.

레이아웃에 정의된 필드명으로 DataSet에서 데이터를 조회하여 필드명으로 Map에 저장한다. 레이아웃 내에 서브 레이아웃이 있으면 서브 레이아웃도 동일한 방식으로 변환한다.

전체 예제

헤더부 전문 Unmarshal 프로그램

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.nexacro17.xapi.data.DataSet;
import com.nexacro17.xapi.data.PlatformData;
import com.nexacro17.xapi.tx.HttpPlatformRequest;

import bxi.api.impl.UnmarshalProcessor;
import bxi.common.constant.CamelHeader;
import bxi.common.context.ErrorLogger;
import bxi.common.dao.dto.BxiIntrnlSysBizIO;
import bxi.common.dao.dto.BxiMsgLayoutIO;
import bxi.common.dao.dto.BxiMsgLayoutMngIO;
import bxi.common.enums.JavaTypeEnum;
import bxi.common.exception.BxiException;
import bxi.common.model.ExchangeMessage;
import bxi.common.model.XmlTypeInfo;
import bxi.common.utility.ObjectUtil;
import bxi.common.utility.StringUtil;
import bxi.extension.customizing.constant.FieldName;
import bxi.parser.base.LayoutUtil;

@Component
public class NexacroHeaderUnmarshalProcessor extends UnmarshalProcessor {
private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Override
public void unmarshal(ExchangeMessage bxiMessage) throws Exception {
// Check input parameter
if (ObjectUtil.isEmpty(bxiMessage)) {
return;
}
logger.debug("Input getBody : {}", bxiMessage);

// The message received from the Nexacro terminal is received via getMessage()
String message = bxiMessage.getMessage(String.class);
if (StringUtil.isEmpty(message)) {
ErrorLogger.errorLogging(bxiMessage, "BXIE02144");
throw new BxiException("BXIE02144");
}
logger.debug("message : {}", message);

/** Query header layout information of system where Nexacro terminal is defined.
* The header layout uses the information registered in the common header layout
* of the system-specific business information
*/
BxiIntrnlSysBizIO intrnlSysBizInfo = getHeader(CamelHeader.INTERNAL_SYS_BIZ_INFO,
BxiIntrnlSysBizIO.class);

// Query message layout
String headerLayout = intrnlSysBizInfo.getStdMsgHdrLayout();
BxiMsgLayoutMngIO msgTrnsfrmInfo = LayoutUtil.selectMessageManagement(headerLayout);
if (ObjectUtil.isEmpty(msgTrnsfrmInfo)) {
ErrorLogger.errorLogging(bxiMessage, "BXIE02113", headerLayout);
throw new BxiException("BXIE02113", headerLayout);
}
Map<String, BxiMsgLayoutIO> layoutMap = LayoutUtil.selectBxiMsgLayout(headerLayout);

// Extract data received from Nexacro terminal
InputStream inStream = new ByteArrayInputStream(message.getBytes());
HttpPlatformRequest xrequest = new HttpPlatformRequest(inStream);
xrequest.receiveData();

// Extract XML data from Request for Nexacro
PlatformData xdata = xrequest.getData();
logger.debug("request input xml data = [{}]", xdata.saveXml());

// Extract the header data from the extracted layout data
// and store it in Unmarshal and comHeader
Map<String, Object> header = new LinkedHashMap<String, Object>();
DataSet ds = xdata.getDataSet(FieldName.HEADER_DATASET_NAME);
if (ds != null) {
// Nexacro header unmarshal
unmarshalHeader(ds, layoutMap, headerLayout, header);
} else {
ErrorLogger.errorLogging(bxiMessage, "BXIE02113", "nexacro");
throw new BxiException("BXIE02113", "nexacro");
}

if (ObjectUtil.isEmpty(header)) {
ErrorLogger.errorLogging(bxiMessage, "BXIE02113", headerLayout);
throw new BxiException("BXIE02113", headerLayout);
}
bxiMessage.setComHeader(header);
logger.debug("header : {}", header);

// Save layout information
XmlTypeInfo xmlInfo = LayoutUtil.makeXmlTypeInfo(msgTrnsfrmInfo, 0);
bxiMessage.setComHeaderMsgInfo(xmlInfo);

// Originally, we had to separate the header message from the whole message.
// but Nexacro can not be detached, so you can save the entire message as Body Message
bxiMessage.setBodyMessage(message);
}

/**
* Nexacro header unmarshal
*
* The layout field data is a field name defined in the layout
* and is retrieved from the dataset and stored in the map.
* If you are in a Sub layout, create a Map for the Sub layout and unmarshal it in the same way.
*
* @param ds
* @param layoutMap
* @param headerLayout
* @param colData
*/
private void unmarshalHeader(DataSet ds, Map<String, BxiMsgLayoutIO> layoutMap,
String headerLayout, Map<String, Object> colData) {

if (ObjectUtil.isEmpty(layoutMap)) {
// Inquiry message layout details
layoutMap = LayoutUtil.selectBxiMsgLayout(headerLayout);
if (ObjectUtil.isEmpty(layoutMap)) {
ErrorLogger.errorLogging("BXIE02158", headerLayout);
throw new BxiException("BXIE02158", headerLayout);
}
}

for (Entry<String, BxiMsgLayoutIO> entry : layoutMap.entrySet()) {
BxiMsgLayoutIO layout = entry.getValue();

JavaTypeEnum type = JavaTypeEnum.getByCode(layout.getFldTypeCd());
if (type == JavaTypeEnum.OMM) {
Map<String, Object> sub = new LinkedHashMap<String, Object>();
unmarshalHeader(ds, null, layout.getFldFormat(), sub);
colData.put(layout.getFldNm(), sub);
} else {
colData.put(layout.getFldNm(), ds.getObject(0, layout.getFldNm()));
}
}
}
}

전문 형식이 다른 경우 개별부 전문 Unmarshal 프로그램

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.nexacro17.xapi.data.DataSet;
import com.nexacro17.xapi.data.PlatformData;
import com.nexacro17.xapi.tx.HttpPlatformRequest;
import com.nexacro17.xapi.tx.PlatformException;

import bxi.api.impl.UnmarshalProcessor;
import bxi.common.constant.CamelHeader;
import bxi.common.context.ErrorLogger;
import bxi.common.dao.dto.BxiMsgLayoutIO;
import bxi.common.dao.dto.BxiMsgLayoutMngIO;
import bxi.common.dao.dto.BxiOnlineIntrfcIO;
import bxi.common.enums.JavaTypeEnum;
import bxi.common.enums.RequestResponseKindEnum;
import bxi.common.exception.BxiException;
import bxi.common.model.ExchangeMessage;
import bxi.common.model.XmlTypeInfo;
import bxi.common.utility.ObjectUtil;
import bxi.common.utility.StringUtil;
import bxi.extension.customizing.constant.FieldName;
import bxi.parser.base.LayoutUtil;

@Component
public class NexacroBodyUnmarshalProcessor extends UnmarshalProcessor {
private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Override
public void unmarshal(ExchangeMessage bxiMessage) throws Exception {
// Check input parameter
if (ObjectUtil.isEmpty(bxiMessage)) {
return;
}
logger.debug("Input getBody : {}", bxiMessage);

// The message received from the Nexacro terminal is received via getMessage()
String message = bxiMessage.getMessage(String.class);
if (StringUtil.isEmpty(message)) {
ErrorLogger.errorLogging(bxiMessage, "BXIE02144");
throw new BxiException("BXIE02144");
}
logger.debug("message : {}", message);

// Do not marshall the body unless transaction specific information is registered.
BxiOnlineIntrfcIO onlIntrfcInfo = getHeader(CamelHeader.ONLINE_INTERFACE_INFO,
BxiOnlineIntrfcIO.class);
String msgBodyLayout = bodyMsgLayout(onlIntrfcInfo, bxiMessage.getRqstRspsDscd());
if (StringUtil.isEmpty(msgBodyLayout)) {
return;
}

// Body message unmarshal
if (unmarshalBody(bxiMessage, msgBodyLayout)) {
throw new BxiException("BXIE02109");
}
}

/**
* Body message unmarshal
*
* @param bxiMessage
* @param msgBodyLayout
* @return
* @throws Exception
*/
private boolean unmarshalBody(ExchangeMessage bxiMessage, String msgBodyLayout)
throws Exception {

logger.debug("msgBodyLayout : {}", msgBodyLayout);

// Inquiry message layout
BxiMsgLayoutMngIO msgTrnsfrmInfo = LayoutUtil.selectMessageManagement(msgBodyLayout);
if (ObjectUtil.isEmpty(msgTrnsfrmInfo)) {
ErrorLogger.errorLogging(bxiMessage, "BXIE02109", msgBodyLayout);
return true;
}
Map<String, BxiMsgLayoutIO> layoutMap = LayoutUtil.selectBxiMsgLayout(msgBodyLayout);

// Extract data received from Nexacro terminal
PlatformData xdata = getNexacroXmlData(bxiMessage);

// Extract individual data from the extracted layout data
// and store it in body by Unmarshal
Map<String, Object> body = new LinkedHashMap<String, Object>();
setNexacroXmlToMap(body, layoutMap, xdata);
bxiMessage.setBody(body);

logger.debug("InternalBody : {}", body);

// Save layout information
XmlTypeInfo xmlInfo = LayoutUtil.makeXmlTypeInfo(msgTrnsfrmInfo, 0);
bxiMessage.setBodyMsgInfo(xmlInfo);

return false;
}

/**
* Extract data received from Nexacro terminal
*
* @param bxiMessage
* @return PltformData
* @throws PlatformException
* @throws UnsupportedEncodingException
*/
private PlatformData getNexacroXmlData(ExchangeMessage bxiMessage)
throws PlatformException, UnsupportedEncodingException {

// Request Extraction for Nexacro
byte[] byteMessage = ((String) bxiMessage.getMessage()).getBytes();
InputStream inStream = new ByteArrayInputStream(byteMessage);
HttpPlatformRequest xrequest = new HttpPlatformRequest(inStream);
xrequest.receiveData();

// Extract XML data from Request for Nexacro
logger.debug("request body input xml data = [{}]", xrequest.getData().saveXml());
return xrequest.getData();
}

/**
* Change Nexacro Xml data to Map
*
* @param body
* @param layoutMap
* @param xdata
*/
private void setNexacroXmlToMap(Map<String, Object> body, Map<String, BxiMsgLayoutIO> layoutMap,
PlatformData xdata) {

// All fields in the top-level layout are passed to the Root DataSet
DataSet dsRoot = xdata.getDataSet(FieldName.ROOT_DATASET_NAME);

// Parses Nexacro Xml data to Map to a defined layout
for (Entry<String, BxiMsgLayoutIO> entry : layoutMap.entrySet()) {
BxiMsgLayoutIO layout = entry.getValue();

JavaTypeEnum type = JavaTypeEnum.getByCode(layout.getFldTypeCd());
// List
if (!StringUtil.isEmpty(layout.getArrayRefNm())) {
List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();
DataSet dsTemp = xdata.getDataSet(layout.getFldNm());
if (!ObjectUtil.isEmpty(dsTemp)) {
for (int i = 0; i < dsTemp.getRowCount(); i++) {
Map<String, Object> row = new LinkedHashMap<String, Object>();
unmarshalNexacro(i, dsTemp, null, layout.getFldFormat(), row);

listMap.add(row);
}
body.put(layout.getFldNm(), listMap);
}
}
// OMM
else if (type == JavaTypeEnum.OMM) {
DataSet dsTemp = xdata.getDataSet(layout.getFldNm());
if (!ObjectUtil.isEmpty(dsTemp)) {
Map<String, Object> sub = new LinkedHashMap<String, Object>();
unmarshalNexacro(0, dsTemp, null, layout.getFldFormat(), sub);

body.put(layout.getFldNm(), sub);
}
}
// Field
else {
body.put(layout.getFldNm(), dsRoot.getObject(0, layout.getFldNm()));
}
}
}

/**
* Nexacro bidy unmarshal
*
* @param ds
* @param layoutMap
* @param colData
*/
private void unmarshalNexacro(int crow, DataSet ds, Map<String, BxiMsgLayoutIO> layoutMap,
String msgBodyLayout, Map<String, Object> colData) {

if (ObjectUtil.isEmpty(layoutMap)) {
// Inquiry message layout details
layoutMap = LayoutUtil.selectBxiMsgLayout(msgBodyLayout);

if (ObjectUtil.isEmpty(layoutMap)) {
ErrorLogger.errorLogging("BXIE02158", msgBodyLayout);
throw new BxiException("BXIE02158", msgBodyLayout);
}
}

for (Entry<String, BxiMsgLayoutIO> entry : layoutMap.entrySet()) {
BxiMsgLayoutIO layout = entry.getValue();

JavaTypeEnum type = JavaTypeEnum.getByCode(layout.getFldTypeCd());
if (type == JavaTypeEnum.OMM) {
Map<String, Object> sub = new LinkedHashMap<String, Object>();
unmarshalNexacro(crow, ds, null, layout.getFldFormat(), sub);
colData.put(layout.getFldNm(), sub);
} else {
colData.put(layout.getFldNm(), ds.getObject(crow, layout.getFldNm()));
}
}
}

/**
* Body DtoName Lookup
*
* @param onlIntrfcInfo
* @param rqstRspsDscd
*/
private String bodyMsgLayout(BxiOnlineIntrfcIO onlIntrfcInfo, String rqstRspsDscd) {
if (StringUtil.isEmpty(rqstRspsDscd)) {
return null;
}

RequestResponseKindEnum rqstRsps = RequestResponseKindEnum.getByCode(rqstRspsDscd);
if (rqstRsps == RequestResponseKindEnum.REQUEST) {
return onlIntrfcInfo.getRqstMsgLayout();
} else {
return onlIntrfcInfo.getRspsMsgLayout();
}
}
}

전문 구조가 다른 경우 개별부 전문 Unmarshal 프로그램

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import bxi.api.impl.UnmarshalProcessor;
import bxi.common.constant.CamelHeader;
import bxi.common.constant.Constant;
import bxi.common.context.ErrorLogger;
import bxi.common.dao.dto.BxiIntrnlSysBizIO;
import bxi.common.dao.dto.BxiMsgLayoutMngIO;
import bxi.common.dao.dto.BxiOnlineIntrfcIO;
import bxi.common.enums.RequestResponseKindEnum;
import bxi.common.exception.BxiException;
import bxi.common.model.ExchangeMessage;
import bxi.common.model.XmlTypeInfo;
import bxi.common.utility.ObjectUtil;
import bxi.common.utility.StringUtil;
import bxi.extension.customizing.constant.FieldName;
import bxi.parser.Unmarshaller;
import bxi.parser.base.LayoutUtil;

@Component
public class BcMciBodyUnmarshalProcessor extends UnmarshalProcessor {
private final Logger logger = LoggerFactory.getLogger(this.getClass());

/**
* Body Message Parsing Processing
*/
@Override
public void unmarshal(ExchangeMessage bxiMessage) throws Exception {
// Check input parameter
if (ObjectUtil.isEmpty(bxiMessage)) {
return;
}
logger.debug("Input getBody : {}", bxiMessage);

// Verification of individual part except header part
if (ObjectUtil.isEmpty(bxiMessage.getBodyMessage())) {
logger.debug("BodyMessage is Null Or Space");
return;
}

// Online interface information inquiry
BxiOnlineIntrfcIO onlIntrfcInfo = getHeader(CamelHeader.ONLINE_INTERFACE_INFO,
BxiOnlineIntrfcIO.class);

// Unmarshal the message part only for the response
RequestResponseKindEnum rqstRsps = RequestResponseKindEnum.getByCode(
bxiMessage.getRqstRspsDscd());
if (rqstRsps == RequestResponseKindEnum.RESPONSE) {
// Message part unmarshal
BxiIntrnlSysBizIO intrnlSysBizInfo = getHeader(CamelHeader.INTERNAL_SYS_BIZ_INFO,
BxiIntrnlSysBizIO.class);
unmarshalResponseMessage(intrnlSysBizInfo, bxiMessage);
}

// Individual layout inquiry
String msgBodyLayout = bodyMsgLayout(onlIntrfcInfo, bxiMessage.getRqstRspsDscd());
if (StringUtil.isEmpty(msgBodyLayout)) {
return;
}

// Body message unmarshal
if (unmarshalBody(bxiMessage, msgBodyLayout)) {
throw new BxiException("BXIE02109");
}
}

/**
* Message part unmarshal
*
* @param intrnlSysBizInfo
* @param bxiMessage
* @return
* @throws Exception
*/
private Map<String, Object> unmarshalResponseMessage(BxiIntrnlSysBizIO intrnlSysBizInfo,
ExchangeMessage bxiMessage) throws Exception {

// Unmarshal message part
Map<String, Object> messageMap = Unmarshaller.unmarshal(intrnlSysBizInfo.getChlMsgTypeCd(),
FieldName.MESSAGE_LAYOUT_NAME, bxiMessage.getBodyMessage(),
intrnlSysBizInfo.getMsgCharSetCd(), false, null);

logger.debug("messageMap: {}", messageMap);

// Returns if there is no message part data
if (ObjectUtil.isEmpty(messageMap)) {
return null;
}

int length = (int) messageMap.get(Constant.MESSAGE_LENGTH_NAME);
messageMap.remove(Constant.MESSAGE_LENGTH_NAME);
bxiMessage.setErrMessage(messageMap);

// Save layout information
BxiMsgLayoutMngIO msgTrnsfrmInfo = LayoutUtil.selectMessageManagement(
FieldName.ADD_MESSAGE_LAYOUT_NAME);
XmlTypeInfo xmlInfo = LayoutUtil.makeXmlTypeInfo(msgTrnsfrmInfo, length);
bxiMessage.setErrMsgInfo(xmlInfo);

return messageMap;
}

/**
* Body message unmarshal
*
* @param bxiMessage
* @param msgBodyLayout
* @return
*/
private boolean unmarshalBody(ExchangeMessage bxiMessage, String msgBodyLayout) {
// System business information
BxiIntrnlSysBizIO intrnlSysBizInfo = getHeader(CamelHeader.INTERNAL_SYS_BIZ_INFO,
BxiIntrnlSysBizIO.class);

if (logger.isDebugEnabled()) {
logger.debug("messageType : {}", intrnlSysBizInfo.getChlMsgTypeCd());
logger.debug("msgBodyLayout : {}", msgBodyLayout);
logger.debug("bodyMessage : {}", bxiMessage.getBodyMessage());
}

// Query layout information
BxiMsgLayoutMngIO msgTrnsfrmInfo = LayoutUtil.selectMessageManagement(msgBodyLayout);
if (ObjectUtil.isEmpty(msgTrnsfrmInfo)) {
ErrorLogger.errorLogging(bxiMessage, "BXIE02109", msgBodyLayout);
return true;
}

// Unmarshal
Map<String, Object> body = Unmarshaller.unmarshal(intrnlSysBizInfo.getChlMsgTypeCd(),
msgBodyLayout, bxiMessage.getBodyMessage(), intrnlSysBizInfo.getMsgCharSetCd(),
false, null);
if (ObjectUtil.isEmpty(body)) {
ErrorLogger.errorLogging(bxiMessage, "BXIE02109", msgBodyLayout);
return true;
}
int length = (int) body.get(Constant.MESSAGE_LENGTH_NAME);
body.remove(Constant.MESSAGE_LENGTH_NAME);

// Save layout information
XmlTypeInfo xmlInfo = LayoutUtil.makeXmlTypeInfo(msgTrnsfrmInfo, length);
bxiMessage.setBodyMsgInfo(xmlInfo);

logger.debug("InternalBody : {}", body);

bxiMessage.setBodyMessage(null);
bxiMessage.setBody(body);

return false;
}

/**
* Body DtoName Lookup
*
* @param onlIntrfcInfo
* @param rqstRspsDscd
*/
private String bodyMsgLayout(BxiOnlineIntrfcIO onlIntrfcInfo, String rqstRspsDscd) {
if (StringUtil.isEmpty(rqstRspsDscd)) {
return null;
}

RequestResponseKindEnum rqstRsps = RequestResponseKindEnum.getByCode(rqstRspsDscd);
if (rqstRsps == RequestResponseKindEnum.REQUEST) {
return onlIntrfcInfo.getRqstMsgLayout();
} else {
return onlIntrfcInfo.getRspsMsgLayout();
}
}
}

전문 Marshal 프로그램

import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.nexacro17.xapi.data.DataSet;
import com.nexacro17.xapi.data.DataTypes;
import com.nexacro17.xapi.data.PlatformData;
import com.nexacro17.xapi.data.VariableList;
import com.nexacro17.xapi.tx.PlatformResponse;

import bxi.api.impl.MarshalProcessor;
import bxi.common.constant.CamelHeader;
import bxi.common.context.ErrorLogger;
import bxi.common.dao.dto.BxiIntrnlSysBizIO;
import bxi.common.dao.dto.BxiMsgLayoutIO;
import bxi.common.dao.dto.BxiOnlineIntrfcIO;
import bxi.common.enums.JavaTypeEnum;
import bxi.common.exception.BxiException;
import bxi.common.model.ExchangeMessage;
import bxi.common.utility.CharsetUtil;
import bxi.common.utility.ObjectUtil;
import bxi.common.utility.StringUtil;
import bxi.extension.customizing.constant.FieldName;
import bxi.online.common.DaoProcess;
import bxi.parser.base.LayoutUtil;

@Component
public class NexacroMarshalProcessor extends MarshalProcessor {
private final Logger logger = LoggerFactory.getLogger(this.getClass());

/** DaoProcess */
@Autowired
private DaoProcess daoProcess;

@Override
public void marshal(ExchangeMessage bxiMessage) throws Exception {
// Check input parameter
if (ObjectUtil.isEmpty(bxiMessage)) {
return;
}
logger.debug("Input getBody : {}", bxiMessage);

// System business information inquiry
BxiIntrnlSysBizIO intrnlSysBizInfo = internalSystemBizInfo(bxiMessage);

// Preparing to generate Nexacro Xml data
DataSet headerDS = new DataSet(FieldName.HEADER_DATASET_NAME);
PlatformData xdata = new PlatformData();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
PlatformResponse xresponse = new PlatformResponse(outStream);

// Convert header part to Nexacro layout format
marshalNexacroHeader(bxiMessage, intrnlSysBizInfo.getStdMsgHdrLayout(), headerDS, xdata);
xdata.addDataSet(headerDS);

// Convert message part to Nexacro layout format if message part exists
if (!ObjectUtil.isEmpty(bxiMessage.getErrMessage())) {
marshalNexacroMessage(bxiMessage.getComHeader(), bxiMessage.getErrMessage(), xdata);
}

// Convert individual parts to Nexacro layout format if separate parts exist
if (!ObjectUtil.isEmpty(bxiMessage.getBody())) {
BxiOnlineIntrfcIO onlIntrfcInfo = getHeader(CamelHeader.ONLINE_INTERFACE_INFO,
BxiOnlineIntrfcIO.class);
marshalNexacroBody(bxiMessage.getBody(), onlIntrfcInfo.getRspsMsgLayout(), xdata);
}

logger.debug("NexacroMarshal result : {}", xdata.saveXml());

// Save Nexacro Response Data
xresponse.setData(xdata);
xresponse.sendData();

logger.debug("Send Message : {}", outStream.toString());

// Setting Nexacro Response Data in BXI
bxiMessage.setMessage(outStream.toString().getBytes(CharsetUtil.DEFAULT_CHARSET));
}

/**
* Convert header part to Nexacro layout format
*
* @param bxiMessage
* @param headerLayout
* @param headerDS
* @param xdata
*/
private void marshalNexacroHeader(ExchangeMessage bxiMessage, String headerLayout,
DataSet headerDS, PlatformData xdata) {

// Query header layout information
Map<String, BxiMsgLayoutIO> layoutMap = LayoutUtil.selectBxiMsgLayout(headerLayout);

// Header data
Map<String, Object> mapHeader = bxiMessage.getComHeader();

// Generate Nexacro DataSet Column data for a defined layout layout
for (Entry<String, BxiMsgLayoutIO> entry : layoutMap.entrySet()) {
BxiMsgLayoutIO layout = entry.getValue();
int xformType = convertTypeDescriptor(layout.getFldTypeCd());
headerDS.addColumn(layout.getFldNm(), xformType, layout.getFldLen());
}

// Generate Nexacro DataSet Row data for a defined layout layout
int rowNumHeader = headerDS.newRow();
for (Entry<String, BxiMsgLayoutIO> entry : layoutMap.entrySet()) {
BxiMsgLayoutIO layout = entry.getValue();
int xformType = convertTypeDescriptor(layout.getFldTypeCd());
if (xformType == DataTypes.UNDEFINED) {
continue;
}

headerDS.set(rowNumHeader, layout.getFldNm(), mapHeader.get(layout.getFldNm()));
}
}

/**
* Convert message part to Nexacro layout format
*
* @param headerMap
* @param messageMap
* @param xdata
*/
private void marshalNexacroMessage(Map<String, Object> headerMap, Map<String, Object> messageMap,
PlatformData xdata) {

// Query message layout information
Map<String, BxiMsgLayoutIO> msgLayoutMap = LayoutUtil.selectBxiMsgLayout(
FieldName.MESSAGE_LAYOUT_NAME);

// Query message detail layout information
Map<String, BxiMsgLayoutIO> msgDetailLayoutMap = LayoutUtil.selectBxiMsgLayout(
FieldName.ADD_MESSAGE_LAYOUT_NAME);

DataSet dsMsg = new DataSet(FieldName.MESSAGE_DATASET_NAME);
addColumnMessageDataSet(dsMsg, msgLayoutMap, msgDetailLayoutMap, messageMap);

@SuppressWarnings("unchecked")
List<Map<String, Object>> list = (List<Map<String, Object>>) messageMap.get(
FieldName.ADD_MESSAGE_FIELD_NAME);

for (Map<String, Object> map : list) {
int rowNum = dsMsg.newRow();
for (Entry<String, BxiMsgLayoutIO> entryDetail : msgDetailLayoutMap.entrySet()) {
BxiMsgLayoutIO layoutDetail = entryDetail.getValue();
dsMsg.set(rowNum, layoutDetail.getFldNm(), map.get(layoutDetail.getFldNm()));
}
}
xdata.addDataSet(dsMsg);

// Insert ErrorCode value -1 in Nexacro Parameter if error response
// 1: System error, 2: Business error, 3: DB error
if ("1".equals(headerMap.get(FieldName.RESPONSE_DIVISION_CODE))
|| "2".equals(headerMap.get(FieldName.RESPONSE_DIVISION_CODE))
|| "3".equals(headerMap.get(FieldName.RESPONSE_DIVISION_CODE))) {

VariableList varList = xdata.getVariableList();
varList.add(FieldName.NEXACRO_ERR_CD, -1);
varList.add(FieldName.NEXACRO_ERR_MSG, dsMsg.saveXml());
}
}

/**
* Convert individual part to Nexacro layout format
*
* @param bodyMap
* @param msgBodyLayout
* @param xdata
*/
@SuppressWarnings("unchecked")
private void marshalNexacroBody(Map<String, Object> bodyMap, String msgBodyLayout,
PlatformData xdata) {

// Query individual layout information
Map<String, BxiMsgLayoutIO> bodyLayoutMap = LayoutUtil.selectBxiMsgLayout(msgBodyLayout);

DataSet dsRoot = new DataSet(FieldName.ROOT_DATASET_NAME);
addColumnDataSet(dsRoot, bodyLayoutMap, null);
int rootRowNum = dsRoot.newRow();

List<Map<String, Object>> list = null;
for (Entry<String, BxiMsgLayoutIO> entry : bodyLayoutMap.entrySet()) {
BxiMsgLayoutIO layout = entry.getValue();

JavaTypeEnum type = JavaTypeEnum.getByCode(layout.getFldTypeCd());
// List
if (!StringUtil.isEmpty(layout.getArrayRefNm())) {
DataSet dsTemp = new DataSet(layout.getFldNm());
addColumnDataSet(dsTemp, null, layout.getFldFormat());

list = (List<Map<String, Object>>) bodyMap.get(layout.getFldNm());
if (list != null) {
for (Map<String, Object> map : list) {
int rowNum = dsTemp.newRow();
addRowDataSet(rowNum, dsTemp, layout.getFldFormat(), map);
}
}
xdata.addDataSet(dsTemp);
}
// OMM
else if (type == JavaTypeEnum.OMM) {
Map<String, Object> sub = (Map<String, Object>) bodyMap.get(layout.getFldNm());
DataSet dsTemp = new DataSet(layout.getFldNm());
addColumnDataSet(dsTemp, null, layout.getFldFormat());

int rowNum = dsTemp.newRow();
addRowDataSet(rowNum, dsTemp, layout.getFldFormat(), sub);
xdata.addDataSet(dsTemp);
}
// Field
else {
dsRoot.set(rootRowNum, layout.getFldNm(), bodyMap.get(layout.getFldNm()));
}
}

logger.debug("NexacroMarshal result : {}", xdata.saveXml());
xdata.addDataSet(dsRoot);
}

/**
* Generate column information of message part DataSet
*
* @param dsTemp
* @param layoutMap
* @param layoutDetailMap
* @param messageMap
*/
private void addColumnMessageDataSet(DataSet dsTemp, Map<String, BxiMsgLayoutIO> layoutMap,
Map<String, BxiMsgLayoutIO> layoutDetailMap, Map<String, Object> messageMap) {

for (Entry<String, BxiMsgLayoutIO> entry : layoutMap.entrySet()) {
BxiMsgLayoutIO layout = entry.getValue();

if (!StringUtil.isEmpty(layout.getArrayRefNm())) {
for (Entry<String, BxiMsgLayoutIO> detailEntry : layoutDetailMap.entrySet()) {
BxiMsgLayoutIO layoutDetail = detailEntry.getValue();
int xformType = convertTypeDescriptor(layoutDetail.getFldTypeCd());
if (xformType == DataTypes.UNDEFINED) {
continue;
}
dsTemp.addColumn(layoutDetail.getFldNm(), xformType, layoutDetail.getFldLen());
}
} else {
dsTemp.addConstantColumn(layout.getFldNm(), messageMap.get(layout.getFldNm()));
}
}
}

/**
* Generate column information of individual part DataSet
*
* @param dsTemp
* @param layoutMap
* @param msgBodyLayout
*/
private void addColumnDataSet(DataSet dsTemp, Map<String, BxiMsgLayoutIO> layoutMap,
String msgBodyLayout) {

if (layoutMap == null) {
// Query message detail layout information
layoutMap = LayoutUtil.selectBxiMsgLayout(msgBodyLayout);
}

for (Entry<String, BxiMsgLayoutIO> entry : layoutMap.entrySet()) {
BxiMsgLayoutIO layout = entry.getValue();

int xformType = convertTypeDescriptor(layout.getFldTypeCd());
if (xformType == DataTypes.UNDEFINED) {
continue;
}
dsTemp.addColumn(layout.getFldNm(), xformType, layout.getFldLen());
}
}

/**
* Generate Row information of individual part DataSet
*
* @param rowNum
* @param dsTemp
* @param msgBodyLayout
* @param sub
*/
private void addRowDataSet(int rowNum, DataSet dsTemp, String msgBodyLayout,
Map<String, Object> sub) {

// Query message detail layout information
Map<String, BxiMsgLayoutIO> layoutMap = LayoutUtil.selectBxiMsgLayout(msgBodyLayout);

for (Entry<String, BxiMsgLayoutIO> entry : layoutMap.entrySet()) {
BxiMsgLayoutIO layout = entry.getValue();
dsTemp.set(rowNum, layout.getFldNm(), sub.get(layout.getFldNm()));
}
}

/**
* Extracting the field type for the DataSet
*
* @param type
* @return
*/
private int convertTypeDescriptor(String type) {
if (type.toUpperCase().equals("STRING")) {
return DataTypes.STRING;
} else if (type.toUpperCase().equals("BOOLEAN")) {
return DataTypes.BOOLEAN;
} else if (type.toUpperCase().equals("DOUBLE")) {
return DataTypes.DOUBLE;
} else if (type.toUpperCase().equals("FLOAT")) {
return DataTypes.FLOAT;
} else if (type.toUpperCase().equals("INTEGER")) {
return DataTypes.INT;
} else if (type.toUpperCase().equals("LONG")) {
return DataTypes.LONG;
} else if (type.toUpperCase().equals("DATE")) {
return DataTypes.DATE_TIME;
} else if (type.toUpperCase().equals("BIGDECIMAL")) {
return DataTypes.BIG_DECIMAL;
} else {
return DataTypes.UNDEFINED;
}
}

/**
* System business information inquiry
*
* @param bxiMessage
* @return
*/
private BxiIntrnlSysBizIO internalSystemBizInfo(ExchangeMessage bxiMessage) {
BxiIntrnlSysBizIO intrnlSysBizInfo = null;
String sysId = null;

if (bxiMessage.isErrorResponseFlag()) {
intrnlSysBizInfo = getHeader(CamelHeader.INTERNAL_SYS_BIZ_INFO,
BxiIntrnlSysBizIO.class);
sysId = bxiMessage.getSysId();
} else {
intrnlSysBizInfo = getHeader(CamelHeader.SEND_SYS_BIZ_INFO,
BxiIntrnlSysBizIO.class);
sysId = bxiMessage.getSendSysId();
}
if (!ObjectUtil.isEmpty(intrnlSysBizInfo)) {
return intrnlSysBizInfo;
}

intrnlSysBizInfo = daoProcess.selectInternalSystemBizInfo(bxiMessage, sysId,
bxiMessage.getBizCd());
if (ObjectUtil.isEmpty(intrnlSysBizInfo)) {
ErrorLogger.errorLogging(bxiMessage, "BXIE02025",
bxiMessage.getSendSysId(), bxiMessage.getBizCd());
throw new BxiException("BXIE02025",
bxiMessage.getSendSysId(), bxiMessage.getBizCd());
}

if (bxiMessage.isErrorResponseFlag()) {
setHeader(CamelHeader.INTERNAL_SYS_BIZ_INFO, intrnlSysBizInfo);
} else {
setHeader(CamelHeader.SEND_SYS_BIZ_INFO, intrnlSysBizInfo);
}

return intrnlSysBizInfo;
}
}