Compare commits
10 Commits
60e6b30c9b
...
1240b24c90
| Author | SHA1 | Date | |
|---|---|---|---|
| 1240b24c90 | |||
| 7346c3070d | |||
| 9a597a52ac | |||
| 5653a183eb | |||
| 0e3a612bc0 | |||
| 68c29b962e | |||
| dafe80f8bc | |||
| 9e78a0e199 | |||
| 3ec18b17e8 | |||
| 90464ee33f |
@@ -30,7 +30,7 @@
|
||||
<filter-mapping>
|
||||
<filter-name>ApiRequestBodyFilter</filter-name>
|
||||
<url-pattern>/api/*</url-pattern> <!-- 필요한 URL 패턴 -->
|
||||
<url-pattern>/mapi/*</url-pattern> <!-- 필요한 URL 패턴 -->
|
||||
<url-pattern>/dj/*</url-pattern> <!-- 필요한 URL 패턴 -->
|
||||
</filter-mapping>
|
||||
|
||||
|
||||
|
||||
+1
-1
Submodule elink-online-common updated: f3c2e64191...037fcd6302
+1
-1
Submodule elink-online-core updated: 8f7513865e...658f2a0485
@@ -1,7 +1,6 @@
|
||||
package com.eactive.eai.adapter.controller;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -9,14 +8,10 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
// jwhong
|
||||
import org.json.simple.JSONObject;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@@ -24,25 +19,23 @@ import com.eactive.eai.adapter.AdapterGroupVO;
|
||||
import com.eactive.eai.adapter.AdapterManager;
|
||||
import com.eactive.eai.adapter.AdapterPropManager;
|
||||
import com.eactive.eai.adapter.AdapterVO;
|
||||
import com.eactive.eai.adapter.handler.AdapterErrorMessageHandler;
|
||||
import com.eactive.eai.adapter.handler.AdapterErrorMessageHandlerFactory;
|
||||
import com.eactive.eai.adapter.http.HttpStatusException;
|
||||
import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey;
|
||||
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey;
|
||||
import com.eactive.eai.adapter.http.dynamic.HttpDynamicInAdapterManager;
|
||||
import com.eactive.eai.adapter.http.dynamic.HttpDynamicInAdapterUri;
|
||||
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilter;
|
||||
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilterFactory;
|
||||
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException;
|
||||
import com.eactive.eai.adapter.service.DJErpApiAdapterService;
|
||||
import com.eactive.eai.common.TransactionContextKeys;
|
||||
import com.eactive.eai.common.exception.ExceptionUtil;
|
||||
import com.eactive.eai.common.server.EAIServerManager;
|
||||
import com.eactive.eai.common.stdmessage.STDMessageManager;
|
||||
import com.eactive.eai.common.stdmessage.STDMsgInfoAddOnVO;
|
||||
import com.eactive.eai.common.util.DatetimeUtil;
|
||||
import com.eactive.eai.common.util.InboundErrorLogger;
|
||||
import com.eactive.eai.common.util.Logger;
|
||||
import com.eactive.eai.common.util.MessageUtil;
|
||||
import com.eactive.eai.common.util.TxFileLogger;
|
||||
import com.eactive.eai.common.util.TxSiftContext;
|
||||
import com.eactive.eai.common.util.UUIDGenerator;
|
||||
import com.eactive.eai.inbound.error.InboundErrorInfoVO;
|
||||
|
||||
@@ -116,7 +109,8 @@ public class DJErpApiAdapterController implements HttpAdapterServiceKey {
|
||||
Properties transactionProp = new Properties();
|
||||
String uuid = UUIDGenerator.getUUID().toString().replaceAll("-", "");
|
||||
transactionProp.setProperty(TransactionContextKeys.TRANSACTION_UUID, uuid);
|
||||
MDC.put(Logger.DISCRIMINATOR, transactionProp.getProperty(TransactionContextKeys.TRANSACTION_UUID));
|
||||
|
||||
TxSiftContext.begin(uuid);
|
||||
|
||||
// jwhong, put api received time, eaiSvcCode
|
||||
transactionProp.put(INBOUND_REQUESTED_TIME, receivedTimeStr);
|
||||
@@ -140,27 +134,18 @@ public class DJErpApiAdapterController implements HttpAdapterServiceKey {
|
||||
|
||||
String errorMsg = null;
|
||||
|
||||
if(e instanceof HttpStatusException ) {
|
||||
errorMsg = genErrorResponseMessage(adapterGroupName, adapterName,
|
||||
transactionProp, e, adptMsgType, encode, errorResponseFormat);
|
||||
if (e instanceof HttpStatusException) {
|
||||
logger.warn("ApiAdapterController] " + adapterGroupName + "-" + adapterName + ">>" + e.getMessage());
|
||||
HttpStatusException e1 = (HttpStatusException) e;
|
||||
errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode,
|
||||
MessageUtil.ERROR_CODE_AP_ERROR, e1.getMessage(), errorResponseFormat);
|
||||
responseEntity = ResponseEntity.status(e1.getStatus()).contentType(mediaType).body(errorMsg);
|
||||
}
|
||||
else if( e instanceof JwtAuthException )
|
||||
{
|
||||
} else if (e instanceof JwtAuthException) {
|
||||
logger.error(adapterGroupName + "-" + adapterName + ">>" + e.getMessage(), e);
|
||||
errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode,
|
||||
MessageUtil.ERROR_CODE_AUTH_FAIL, e.getMessage(), errorResponseFormat);
|
||||
responseEntity = ResponseEntity.status(HttpStatus.UNAUTHORIZED).contentType(mediaType).body(errorMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
logger.error(adapterGroupName + "-" + adapterName + ">>" + e.getMessage(), e);
|
||||
errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode,
|
||||
MessageUtil.ERROR_CODE_AP_ERROR, e.getMessage(), errorResponseFormat);
|
||||
responseEntity = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(mediaType)
|
||||
.body(errorMsg);
|
||||
responseEntity = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(mediaType).body(errorMsg);
|
||||
}
|
||||
responseData = errorMsg;
|
||||
|
||||
@@ -171,16 +156,38 @@ public class DJErpApiAdapterController implements HttpAdapterServiceKey {
|
||||
*/
|
||||
try {
|
||||
TxFileLogger.logTxFile(transactionProp, responseData, "[IN_SEND]");
|
||||
MDC.remove(Logger.DISCRIMINATOR);
|
||||
|
||||
servletRequest.setAttribute(TransactionContextKeys.TRANSACTION_PROP, transactionProp);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.warn("http header db logging fail.", e);
|
||||
} finally {
|
||||
TxSiftContext.end();
|
||||
}
|
||||
}
|
||||
return responseEntity;
|
||||
}
|
||||
|
||||
private String genErrorResponseMessage(String adapterGroupName, String adapterName,
|
||||
Properties callProp, Throwable e, String adptMsgType, String encode, String errorResponseFormat) {
|
||||
String errorHandlerClass = AdapterPropManager.getInstance().getProperty(adapterName, "ERR_MSG_HANDLER");
|
||||
if (StringUtils.isNotBlank(errorHandlerClass)) {
|
||||
if (logger.isInfo())
|
||||
logger.info("ExceptionHandler] errorSyncSend ERR_MSG_HANDLER=" + errorHandlerClass);
|
||||
AdapterErrorMessageHandler handler = AdapterErrorMessageHandlerFactory.createHandler(errorHandlerClass);
|
||||
if (handler != null) {
|
||||
Object resposne;
|
||||
try {
|
||||
resposne = handler.generateNonStandardInboundErrorResponseMessage(adapterGroupName, adapterName,
|
||||
callProp, null, null, e);
|
||||
return (String)resposne;
|
||||
} catch (Exception e1) {
|
||||
logger.warn("AdapterErrorMessageHandler error.", e);
|
||||
// handler 실패시 아래에서 처리한
|
||||
}
|
||||
}
|
||||
}
|
||||
return MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode,
|
||||
MessageUtil.ERROR_CODE_AP_ERROR, e.getMessage(), errorResponseFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* url에서 뒤쪽 /이후를 제거하면서 찾는다.<br>
|
||||
@@ -260,21 +267,21 @@ public class DJErpApiAdapterController implements HttpAdapterServiceKey {
|
||||
InboundErrorLogger.error(errorInfoVO);
|
||||
}
|
||||
|
||||
private String makeResponseBodyMsg() {
|
||||
|
||||
Map<String, Object> dataMap = new HashMap<>();
|
||||
dataMap.put("result", 1);
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
|
||||
map.put("code", "200");
|
||||
map.put("data", dataMap);
|
||||
map.put("message", "정상 처리 되었습니다.");
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
json.putAll(map);
|
||||
|
||||
return json.toJSONString();
|
||||
}
|
||||
// private String makeResponseBodyMsg() {
|
||||
//
|
||||
// Map<String, Object> dataMap = new HashMap<>();
|
||||
// dataMap.put("result", 1);
|
||||
// Map<String, Object> map = new HashMap<>();
|
||||
//
|
||||
// map.put("code", "200");
|
||||
// map.put("data", dataMap);
|
||||
// map.put("message", "정상 처리 되었습니다.");
|
||||
//
|
||||
// JSONObject json = new JSONObject();
|
||||
// json.putAll(map);
|
||||
//
|
||||
// return json.toJSONString();
|
||||
// }
|
||||
|
||||
/*
|
||||
* private String makeResponseBodyMsg(String asyncMsgStyle) {
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
package com.eactive.eai.custom.adapter.handler;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import com.eactive.eai.adapter.AdapterGroupVO;
|
||||
import com.eactive.eai.adapter.AdapterManager;
|
||||
import com.eactive.eai.adapter.handler.AdapterErrorMessageHandler;
|
||||
import com.eactive.eai.common.message.MessageType;
|
||||
import com.eactive.eai.message.StandardMessage;
|
||||
import com.eactive.eai.message.manager.StandardMessageManager;
|
||||
import com.eactive.eai.message.service.InterfaceMapper;
|
||||
import com.ext.eai.common.stdmessage.STDMessageKeys;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
public class LonErrorMsgHandler implements AdapterErrorMessageHandler {
|
||||
|
||||
@Override
|
||||
public Object generateNonStandardErrorResponseMessage(String inboudnAdapterGroupName, String inboudnAdapterName,
|
||||
Properties callProp, Object outboundRequestData, StandardMessage resStandardMessage) throws Exception{
|
||||
|
||||
if(resStandardMessage != null && isErrorMessage(resStandardMessage)) {
|
||||
AdapterGroupVO adapterGroupVO = AdapterManager.getInstance().getAdapterGroupVO(inboudnAdapterGroupName);
|
||||
if(MessageType.JSON.equals(adapterGroupVO.getMessageType())) {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
String requestMessage = (String) outboundRequestData;
|
||||
JsonNode requestJson = objectMapper.readTree(requestMessage);
|
||||
String alncInstCd = requestJson.get("dataCmn").get("alncInstCd").asText();
|
||||
|
||||
ObjectNode responseJson = objectMapper.createObjectNode();
|
||||
ObjectNode dataCmnNode = objectMapper.createObjectNode();
|
||||
responseJson.set("dataCmn", dataCmnNode);
|
||||
dataCmnNode.put("fnclInstCd", "KBK");
|
||||
dataCmnNode.put("alncInstCd", alncInstCd);
|
||||
dataCmnNode.put("tlgrRspnsCd", "0210");
|
||||
|
||||
return responseJson.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private boolean isErrorMessage(StandardMessage standardMessage) {
|
||||
InterfaceMapper mapper = StandardMessageManager.getInstance().getMapper();
|
||||
String responseType = mapper.getResponseType(standardMessage);
|
||||
return STDMessageKeys.RESPONSE_TYPE_CODE_E.equals(responseType);
|
||||
}
|
||||
|
||||
}
|
||||
//package com.eactive.eai.custom.adapter.handler;
|
||||
//
|
||||
//import java.util.Properties;
|
||||
//
|
||||
//import com.eactive.eai.adapter.AdapterGroupVO;
|
||||
//import com.eactive.eai.adapter.AdapterManager;
|
||||
//import com.eactive.eai.adapter.handler.AdapterErrorMessageHandler;
|
||||
//import com.eactive.eai.common.message.MessageType;
|
||||
//import com.eactive.eai.message.StandardMessage;
|
||||
//import com.eactive.eai.message.manager.StandardMessageManager;
|
||||
//import com.eactive.eai.message.service.InterfaceMapper;
|
||||
//import com.ext.eai.common.stdmessage.STDMessageKeys;
|
||||
//import com.fasterxml.jackson.databind.JsonNode;
|
||||
//import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
//import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
//
|
||||
//public class LonErrorMsgHandler implements AdapterErrorMessageHandler {
|
||||
//
|
||||
// @Override
|
||||
// public Object generateNonStandardErrorResponseMessage(String inboudnAdapterGroupName, String inboudnAdapterName,
|
||||
// Properties callProp, Object outboundRequestData, StandardMessage resStandardMessage) throws Exception{
|
||||
//
|
||||
// if(resStandardMessage != null && isErrorMessage(resStandardMessage)) {
|
||||
// AdapterGroupVO adapterGroupVO = AdapterManager.getInstance().getAdapterGroupVO(inboudnAdapterGroupName);
|
||||
// if(MessageType.JSON.equals(adapterGroupVO.getMessageType())) {
|
||||
// ObjectMapper objectMapper = new ObjectMapper();
|
||||
// String requestMessage = (String) outboundRequestData;
|
||||
// JsonNode requestJson = objectMapper.readTree(requestMessage);
|
||||
// String alncInstCd = requestJson.get("dataCmn").get("alncInstCd").asText();
|
||||
//
|
||||
// ObjectNode responseJson = objectMapper.createObjectNode();
|
||||
// ObjectNode dataCmnNode = objectMapper.createObjectNode();
|
||||
// responseJson.set("dataCmn", dataCmnNode);
|
||||
// dataCmnNode.put("fnclInstCd", "KBK");
|
||||
// dataCmnNode.put("alncInstCd", alncInstCd);
|
||||
// dataCmnNode.put("tlgrRspnsCd", "0210");
|
||||
//
|
||||
// return responseJson.toString();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// return "";
|
||||
// }
|
||||
//
|
||||
// private boolean isErrorMessage(StandardMessage standardMessage) {
|
||||
// InterfaceMapper mapper = StandardMessageManager.getInstance().getMapper();
|
||||
// String responseType = mapper.getResponseType(standardMessage);
|
||||
// return STDMessageKeys.RESPONSE_TYPE_CODE_E.equals(responseType);
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.eactive.eai.custom.inbound.processor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -9,8 +13,13 @@ import com.eactive.eai.common.inflow.InflowTargetVO;
|
||||
import com.eactive.eai.common.inflow.dual.DualBucket;
|
||||
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
|
||||
import com.eactive.eai.common.message.EAIMessage;
|
||||
import com.eactive.eai.common.property.PropManager;
|
||||
import com.eactive.eai.common.util.Logger;
|
||||
import com.eactive.eai.custom.inflow.ClientDualBucket;
|
||||
import com.eactive.eai.inbound.processor.ProcessVO;
|
||||
import com.eactive.eai.inbound.processor.RequestProcessor;
|
||||
import com.eactive.eai.message.StandardItem;
|
||||
import com.eactive.eai.message.StandardMessage;
|
||||
|
||||
/**
|
||||
* 어댑터/인터페이스/클라이언트 유량제어 차단 시 어느 버킷(PER_SECOND/THRESHOLD)에서
|
||||
@@ -24,6 +33,81 @@ import com.eactive.eai.inbound.processor.RequestProcessor;
|
||||
* <p>Spring Bean 등록 후 기존 RequestProcessor 대신 이 클래스를 어댑터에 설정한다.
|
||||
*/
|
||||
public class DJBRequestProcessor extends RequestProcessor {
|
||||
|
||||
static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
|
||||
|
||||
@Override
|
||||
protected void afterFoundEaiMessage(EAIMessage eaiMsg, ProcessVO vo, Properties prop) {
|
||||
logger.debug("DJBRequestProcessor interface found.");
|
||||
try {
|
||||
this.resolveStandardHeaderMapping(eaiMsg, prop);
|
||||
} catch (Exception e) {
|
||||
logger.warn("DJBRequestProcessor header set failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveStandardHeaderMapping(EAIMessage eaiMsg, Properties prop) {
|
||||
StandardMessage standardMessage = eaiMsg.getStandardMessage();
|
||||
HashMap<String, String> headerMapping = getPropertyMap("DJB_IN_HTTHEAD_STDHEAD_MAPPING", eaiMsg.getSngSysItfTp());
|
||||
|
||||
for (Entry<String, String> entry : headerMapping.entrySet()) {
|
||||
String stdHeaderPath = entry.getKey();
|
||||
int dotIdx = stdHeaderPath.indexOf('.');
|
||||
if(dotIdx > 0) {
|
||||
String firstPath = stdHeaderPath.substring(0, dotIdx);
|
||||
StandardItem topLevelItem = standardMessage.findItem(firstPath);
|
||||
topLevelItem.setHidden(false);
|
||||
}
|
||||
StandardItem item = standardMessage.findItem(entry.getKey());
|
||||
|
||||
String value = resolveNestedValue(prop, entry.getValue());
|
||||
if (item != null && value != null)
|
||||
item.setValue(value);
|
||||
else
|
||||
logger.debug("header mapping item not found : {} ", entry);
|
||||
}
|
||||
}
|
||||
|
||||
private HashMap<String, String> getPropertyMap(String propertyGroupName, String prefix) {
|
||||
Properties prop = PropManager.getInstance().getProperties(propertyGroupName);
|
||||
Set<String> keys = prop.stringPropertyNames();
|
||||
HashMap<String, String> tmpToJsonArrayInterface = new HashMap<>();
|
||||
for (String key : keys) {
|
||||
if (StringUtils.startsWith(key, prefix + ".")) {
|
||||
String propValue = prop.getProperty(key);
|
||||
String replacedKey = StringUtils.replace(key, prefix + ".", "");
|
||||
tmpToJsonArrayInterface.put(replacedKey, propValue);
|
||||
}
|
||||
}
|
||||
return tmpToJsonArrayInterface;
|
||||
}
|
||||
|
||||
private String resolveNestedValue(Map<?, ?> map, String keyPath) {
|
||||
int dotIdx = keyPath.indexOf('.');
|
||||
if (dotIdx < 0) {
|
||||
Object val = map.get(keyPath);
|
||||
if (val == null)
|
||||
return null;
|
||||
if (val instanceof String)
|
||||
return (String) val;
|
||||
return val.toString();
|
||||
}
|
||||
|
||||
String first = keyPath.substring(0, dotIdx);
|
||||
String rest = keyPath.substring(dotIdx + 1);
|
||||
Object val = map.get(first);
|
||||
if (val instanceof Map) {
|
||||
return resolveNestedValue((Map<?, ?>) val, rest);
|
||||
}
|
||||
|
||||
// 폴백: 전체 keyPath를 단일 키로 조회
|
||||
Object direct = map.get(keyPath);
|
||||
if (direct == null)
|
||||
return null;
|
||||
if (direct instanceof String)
|
||||
return (String) direct;
|
||||
return direct.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String checkCustomInflow(Bucket bucket, EAIMessage eaiMsg, Properties prop) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.eactive.eai.custom.message;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.eactive.eai.common.property.PropManager;
|
||||
import com.eactive.eai.common.server.EAIServerManager;
|
||||
import com.eactive.eai.message.StandardMessage;
|
||||
import com.eactive.eai.message.service.DefaultInterfaceMapper;
|
||||
@@ -28,17 +29,24 @@ public class InterfaceMapperDJB extends DefaultInterfaceMapper {
|
||||
// 처리결과구분코드 DJBank 값
|
||||
private static final String PROCS_RSLT_SUCCESS = "S";
|
||||
private static final String PROCS_RSLT_FAIL = "F";
|
||||
|
||||
private static String API_ID_PREFIX = StringUtils
|
||||
.defaultString(PropManager.getInstance().getProperty("API_ID_PREFIX"));
|
||||
|
||||
@Override
|
||||
public String getEaiSvcCode(StandardMessage standardMessage) {
|
||||
String interfaceId = getInterfaceId(standardMessage);
|
||||
if(StringUtils.isNotBlank(standardMessage.getEaiSvcCd()))
|
||||
return standardMessage.getEaiSvcCd();
|
||||
|
||||
// String interfaceId = getInterfaceId(standardMessage);
|
||||
String txId = getServiceId(standardMessage);
|
||||
String sendRecvDvcd = getSendRecvDivision(standardMessage); // S | R
|
||||
String inExDivision = getInExDivision(standardMessage); // 1 | 2
|
||||
|
||||
if(StringUtils.isEmpty(txId))
|
||||
throw new RuntimeException("not found txid");
|
||||
|
||||
if (interfaceId == null) interfaceId = "";
|
||||
interfaceId = interfaceId.trim();
|
||||
|
||||
return interfaceId + sendRecvDvcd + StringUtils.defaultString(inExDivision);
|
||||
return API_ID_PREFIX + txId + sendRecvDvcd + StringUtils.defaultString(inExDivision);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
@@ -5,7 +5,10 @@ import java.net.NetworkInterface;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -15,6 +18,7 @@ import com.eactive.eai.common.util.MessageUtil;
|
||||
import com.eactive.eai.inbound.processor.ProcessVO;
|
||||
import com.eactive.eai.message.StandardItem;
|
||||
import com.eactive.eai.message.StandardMessage;
|
||||
import com.eactive.eai.message.StandardType;
|
||||
import com.eactive.eai.message.manager.StandardMessageManager;
|
||||
import com.eactive.eai.message.service.DefaultStandardMessageCoordinator;
|
||||
import com.eactive.eai.message.service.InterfaceMapper;
|
||||
@@ -36,6 +40,10 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
|
||||
private static final DateTimeFormatter FMT_DATE = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
private static final DateTimeFormatter FMT_TIME_MILLIS = DateTimeFormatter.ofPattern("HHmmssSSS");
|
||||
|
||||
// ${callProp.key} 또는 ${callProp.key:기본값} 패턴
|
||||
private static final Pattern CALL_PROP_PATTERN =
|
||||
Pattern.compile("\\$\\{callProp\\.([^}:]+)(?::([^}]*))?\\}");
|
||||
|
||||
// HEAD 필드 경로
|
||||
private static final String HEAD_FRST_MESG_DMAN_DT = "HEAD.frst_mesg_dman_dt";
|
||||
private static final String HEAD_FRST_MESG_DMAN_TIME = "HEAD.frst_mesg_dman_time";
|
||||
@@ -67,9 +75,15 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
|
||||
|
||||
// DATA 영역 경로
|
||||
private static final String DATA_SCOP_LEN = "DATA.data_scop_len";
|
||||
|
||||
private String[] netInfo;
|
||||
|
||||
@Override
|
||||
public void coordinateAfterParsing(StandardMessage standardMessage, Object paramObject, Properties prop) {
|
||||
// TODO 표준전문을 수신할 경우, 전문의 interface id로 가져온 eaiSvcCd가 다른 값으로 치환되어야 할 수도 있다.
|
||||
// 수신한 if_id를 기준으로 api gw의 eaiSvcCd를 매핑하는 프러퍼티가 있어야 한다.
|
||||
// PropGroup : DJB_IN_STDHEAD_IFID_MAPPING, DJB_IN_HTTHEAD_STDHEAD_MAPPING
|
||||
// standardMessage.setEaiSvcCd(mappedIfId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,7 +92,7 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
|
||||
InterfaceMapper mapper = manager.getMapper();
|
||||
|
||||
// GUID 생성 (40자) 및 설정
|
||||
String guid = GUIDGeneratorDJB.getGUID("EAI");
|
||||
String guid = GUIDGeneratorDJB.getGUID("OPA");
|
||||
mapper.setGuid(standardMessage, guid);
|
||||
|
||||
// GUID 진행번호 초기화 (최초=001)
|
||||
@@ -112,6 +126,9 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
|
||||
if (ezdataItem != null && evaluateBlockCondition(standardMessage, ezdataItem)) {
|
||||
setEzdataFields(standardMessage, ezdataItem, ipv4, mac);
|
||||
}
|
||||
|
||||
// refValue="${callProp.키}" 필드에 Properties 값 주입
|
||||
resolveCallPropRefValues(standardMessage, prop);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -230,6 +247,67 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
|
||||
// private helpers
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
private void resolveCallPropRefValues(StandardMessage standardMessage, Properties prop) {
|
||||
if (prop == null) return;
|
||||
resolveCallPropInChilds(standardMessage.getChilds(), prop);
|
||||
}
|
||||
|
||||
private void resolveCallPropInChilds(LinkedHashMap<String, StandardItem> childs, Properties prop) {
|
||||
if (childs == null) return;
|
||||
for (StandardItem item : childs.values()) {
|
||||
int type = item.getType();
|
||||
if (type == StandardType.FIELD) {
|
||||
String refValue = item.getRefValue();
|
||||
if (refValue == null) continue;
|
||||
Matcher m = CALL_PROP_PATTERN.matcher(refValue);
|
||||
if (m.matches()) {
|
||||
String key = m.group(1);
|
||||
String defaultVal = m.group(2) != null ? m.group(2) : "";
|
||||
String resolved = resolveCallPropValue(prop, key);
|
||||
item.setValue(resolved != null ? resolved : defaultVal);
|
||||
}
|
||||
} else if (type == StandardType.GROUP) {
|
||||
resolveCallPropInChilds(item.getChilds(), prop);
|
||||
}
|
||||
// GRID, FARRAY, BIZDATA: 배열/업무데이터 영역은 건너뜀
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties/Map 중첩 구조에서 점(.) 구분 keyPath로 값을 탐색한다.
|
||||
* Properties는 Map을 구현하므로 Map<?,?> 단일 메서드로 통일한다.
|
||||
* - "aaa.bbb" : map.get("aaa")가 Map(Properties 포함)이면 그 안에서 "bbb" 재귀 조회
|
||||
* - 중간 값이 Map이 아니면 전체 keyPath로 폴백 조회
|
||||
* - 값을 찾지 못하면 null 반환
|
||||
*/
|
||||
private String resolveCallPropValue(Properties props, String keyPath) {
|
||||
return resolveNestedValue(props, keyPath);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private String resolveNestedValue(Map<?, ?> map, String keyPath) {
|
||||
int dotIdx = keyPath.indexOf('.');
|
||||
if (dotIdx < 0) {
|
||||
Object val = map.get(keyPath);
|
||||
if (val == null) return null;
|
||||
if (val instanceof String) return (String) val;
|
||||
return val.toString();
|
||||
}
|
||||
|
||||
String first = keyPath.substring(0, dotIdx);
|
||||
String rest = keyPath.substring(dotIdx + 1);
|
||||
Object val = map.get(first);
|
||||
if (val instanceof Map) {
|
||||
return resolveNestedValue((Map<?, ?>) val, rest);
|
||||
}
|
||||
|
||||
// 폴백: 전체 keyPath를 단일 키로 조회
|
||||
Object direct = map.get(keyPath);
|
||||
if (direct == null) return null;
|
||||
if (direct instanceof String) return (String) direct;
|
||||
return direct.toString();
|
||||
}
|
||||
|
||||
private String getSysEnvDvcd(EAIServerManager server) {
|
||||
if (server.isPEAIServer()) return "P"; // 운영
|
||||
if (server.isSEAIServer()) return "T"; // 검증/테스트
|
||||
@@ -237,6 +315,9 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
|
||||
}
|
||||
|
||||
private String[] collectNetworkInfo() {
|
||||
if(this.netInfo != null)
|
||||
return this.netInfo;
|
||||
|
||||
String ipv4 = "";
|
||||
String mac = "";
|
||||
try {
|
||||
@@ -257,7 +338,8 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
|
||||
} catch (Exception e) {
|
||||
if (logger.isWarn()) logger.warn("Failed to collect network info", e);
|
||||
}
|
||||
return new String[]{ipv4, mac};
|
||||
this.netInfo = new String[]{ipv4, mac};
|
||||
return this.netInfo;
|
||||
}
|
||||
|
||||
private void setEzdataFields(StandardMessage standardMessage, StandardItem ezdataItem, String ipv4, String mac) {
|
||||
|
||||
@@ -24,3 +24,4 @@ ERROR_MSG=MSG.MAIN_MSG.outp_msg_ctnt
|
||||
RESPONSE_TYPE=HEAD.procs_rslt_dvcd
|
||||
RETURN_VALUE=
|
||||
RETURN_SERVICE_ID=
|
||||
BIZ_DATA=DATA[0].BIZ_DATA
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
package com.eactive.eai;
|
||||
|
||||
import com.eactive.eai.common.EAITable;
|
||||
import com.eactive.eai.common.util.MessageUtil;
|
||||
import org.json.simple.JSONValue;
|
||||
|
||||
/**
|
||||
* 테스트용 메시지 키 검증 클래스
|
||||
*/
|
||||
public class MessageKeyTest {
|
||||
|
||||
|
||||
/**
|
||||
* XML 또는 JSON 메시지의 성공 여부를 검증하는 테스트용 메소드
|
||||
* 추출된 값을 배열로 반환
|
||||
*/
|
||||
public static TestResult isSuccessMessageTest(String messageType, Object message, String path, String expectedValue) {
|
||||
try {
|
||||
String extractedValue = "";
|
||||
|
||||
if(EAITable.XML_TYPE.equals(messageType)) {
|
||||
if(message instanceof byte[]) {
|
||||
extractedValue = extractXmlValue(new String((byte[])message), path);
|
||||
} else if(message instanceof String) {
|
||||
extractedValue = extractXmlValue((String)message, path);
|
||||
}
|
||||
}
|
||||
else if(EAITable.JSON_TYPE.equals(messageType)) {
|
||||
Object json = JSONValue.parse((String)message);
|
||||
extractedValue = extractJsonValue(json, path);
|
||||
}
|
||||
|
||||
if(extractedValue == null) extractedValue = "";
|
||||
boolean result = compareMessageValue(extractedValue, expectedValue);
|
||||
|
||||
return new TestResult(result, extractedValue);
|
||||
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
return new TestResult(false, "오류 발생: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 테스트 결과를 담는 클래스
|
||||
static class TestResult {
|
||||
boolean success;
|
||||
String extractedValue;
|
||||
|
||||
TestResult(boolean success, String extractedValue) {
|
||||
this.success = success;
|
||||
this.extractedValue = extractedValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 메시지 값 비교를 수행하는 메소드
|
||||
*/
|
||||
private static boolean compareMessageValue(String actualValue, String expectedValue) {
|
||||
if(actualValue == null) actualValue = "";
|
||||
if(expectedValue == null) return false;
|
||||
|
||||
// 예약어로 시작하는 경우
|
||||
if(expectedValue.startsWith("@")) {
|
||||
return compareWithReservedWord(actualValue, expectedValue);
|
||||
}
|
||||
|
||||
// 일반 equals 비교
|
||||
return actualValue.equals(expectedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 예약어를 포함한 값 비교 처리
|
||||
*/
|
||||
private static boolean compareWithReservedWord(String actualValue, String definition) {
|
||||
if (actualValue == null) actualValue = "";
|
||||
if (definition == null) return false;
|
||||
|
||||
try {
|
||||
// 1. 기본 비교
|
||||
if (definition.startsWith("@eq:")) {
|
||||
return actualValue.equals(definition.substring(4));
|
||||
}
|
||||
if (definition.startsWith("@ne:")) {
|
||||
return !actualValue.equals(definition.substring(4));
|
||||
}
|
||||
if ("@null".equals(definition)) {
|
||||
return actualValue.isEmpty();
|
||||
}
|
||||
if ("@!null".equals(definition)) {
|
||||
return !actualValue.isEmpty();
|
||||
}
|
||||
|
||||
// 2. 문자열 패턴
|
||||
if (definition.startsWith("@contains:")) {
|
||||
String[] values = definition.substring(10).split(",");
|
||||
for (String value : values) {
|
||||
if (actualValue.equals(value.trim())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (definition.startsWith("@!contains:")) {
|
||||
String[] values = definition.substring(11).split(",");
|
||||
for (String value : values) {
|
||||
if (actualValue.equals(value.trim())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (definition.startsWith("@starts:")) {
|
||||
return actualValue.startsWith(definition.substring(8));
|
||||
}
|
||||
if (definition.startsWith("@ends:")) {
|
||||
return actualValue.endsWith(definition.substring(6));
|
||||
}
|
||||
|
||||
// 3. 숫자 비교
|
||||
if (definition.startsWith("@gt:") ||
|
||||
definition.startsWith("@lt:") ||
|
||||
definition.startsWith("@ge:") ||
|
||||
definition.startsWith("@le:")) {
|
||||
|
||||
double actualNum = Double.parseDouble(actualValue);
|
||||
if (definition.startsWith("@gt:")) {
|
||||
double defNum = Double.parseDouble(definition.substring(4));
|
||||
return actualNum > defNum;
|
||||
}
|
||||
if (definition.startsWith("@lt:")) {
|
||||
double defNum = Double.parseDouble(definition.substring(4));
|
||||
return actualNum < defNum;
|
||||
}
|
||||
if (definition.startsWith("@ge:")) {
|
||||
double defNum = Double.parseDouble(definition.substring(4));
|
||||
return actualNum >= defNum;
|
||||
}
|
||||
if (definition.startsWith("@le:")) {
|
||||
double defNum = Double.parseDouble(definition.substring(4));
|
||||
return actualNum <= defNum;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* XML 값 추출 메소드
|
||||
*/
|
||||
private static String extractXmlValue(String xmlMessage, String path) {
|
||||
if(path == null) return "";
|
||||
|
||||
// XPath 형식인 경우
|
||||
if(path.startsWith("//") || path.startsWith("/")) {
|
||||
return MessageUtil.getXmlFldByXPath(xmlMessage, path);
|
||||
}
|
||||
|
||||
// 단순 태그명인 경우
|
||||
return MessageUtil.getXmlFld(xmlMessage, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON 값 추출 메소드
|
||||
*/
|
||||
private static String extractJsonValue(Object json, String path) {
|
||||
if(path == null) return "";
|
||||
|
||||
// JSONPath 형식인 경우
|
||||
if(path.startsWith("$.")) {
|
||||
return MessageUtil.getJSONValueByPath(json, path);
|
||||
}
|
||||
|
||||
// 단순 키인 경우
|
||||
return MessageUtil.getJSONValue(json, path);
|
||||
}
|
||||
|
||||
private static void testXml() {
|
||||
// System.out.println("\n=== XML 테스트 ===");
|
||||
|
||||
// 단순 경로 테스트
|
||||
String xml1 = "<root><status>SUCCESS</status></root>";
|
||||
test("XML 단순 경로",
|
||||
EAITable.XML_TYPE,
|
||||
xml1,
|
||||
"status",
|
||||
"SUCCESS");
|
||||
|
||||
// 중첩 경로 테스트 (일반 방식)
|
||||
String xml2 = "<root><response><header><resultCode>0000</resultCode></header></response></root>";
|
||||
test("XML 중첩 경로 (일반)",
|
||||
EAITable.XML_TYPE,
|
||||
xml2,
|
||||
"resultCode",
|
||||
"0000");
|
||||
|
||||
// 중첩 경로 테스트 (XPath 방식)
|
||||
test("XML 중첩 경로 (XPath)",
|
||||
EAITable.XML_TYPE,
|
||||
xml2,
|
||||
"//response/header/resultCode",
|
||||
"0000");
|
||||
|
||||
// 네임스페이스가 있는 XML
|
||||
String xml3 = "<ns:root xmlns:ns=\"http://test.com\"><ns:status>OK</ns:status></ns:root>";
|
||||
test("XML 네임스페이스",
|
||||
EAITable.XML_TYPE,
|
||||
xml3,
|
||||
"//ns:status",
|
||||
"OK");
|
||||
|
||||
// 실패 케이스
|
||||
test("XML 실패 케이스",
|
||||
EAITable.XML_TYPE,
|
||||
xml1,
|
||||
"status",
|
||||
"FAIL");
|
||||
|
||||
// 존재하지 않는 경로
|
||||
test("XML 없는 경로",
|
||||
EAITable.XML_TYPE,
|
||||
xml1,
|
||||
"nonexistent",
|
||||
"SUCCESS");
|
||||
}
|
||||
|
||||
private static void testJson() {
|
||||
// System.out.println("\n=== JSON 테스트 ===");
|
||||
|
||||
// 단순 경로 테스트
|
||||
String json1 = "{\"status\":\"success\"}";
|
||||
test("JSON 단순 경로",
|
||||
EAITable.JSON_TYPE,
|
||||
json1,
|
||||
"status",
|
||||
"success");
|
||||
|
||||
// 중첩 경로 테스트 (일반 방식)
|
||||
String json2 = "{\"response\":{\"header\":{\"resultCode\":\"0000\"}}}";
|
||||
test("JSON 중첩 경로 (일반)",
|
||||
EAITable.JSON_TYPE,
|
||||
json2,
|
||||
"resultCode",
|
||||
"0000");
|
||||
|
||||
// 중첩 경로 테스트 (JSONPath 방식)
|
||||
test("JSON 중첩 경로 (JSONPath)",
|
||||
EAITable.JSON_TYPE,
|
||||
json2,
|
||||
"$.response.header.resultCode",
|
||||
"0000");
|
||||
|
||||
// 배열이 포함된 JSON
|
||||
String json3 = "{\"responses\":[{\"status\":\"success\"},{\"status\":\"pending\"}]}";
|
||||
test("JSON 배열 경로",
|
||||
EAITable.JSON_TYPE,
|
||||
json3,
|
||||
"$.responses[0].status",
|
||||
"success");
|
||||
|
||||
// 실패 케이스
|
||||
test("JSON 실패 케이스",
|
||||
EAITable.JSON_TYPE,
|
||||
json1,
|
||||
"status",
|
||||
"failure");
|
||||
|
||||
// 존재하지 않는 경로
|
||||
test("JSON 없는 경로",
|
||||
EAITable.JSON_TYPE,
|
||||
json1,
|
||||
"nonexistent",
|
||||
"success");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
testXml();
|
||||
testJson();
|
||||
testReservedWords();
|
||||
}
|
||||
|
||||
private static void testReservedWords() {
|
||||
// System.out.println("\n=== 예약어 테스트 ===");
|
||||
|
||||
// 1. 기본 비교 테스트
|
||||
test("예약어 - eq",
|
||||
EAITable.XML_TYPE,
|
||||
"<root><code>SUCCESS</code></root>",
|
||||
"code",
|
||||
"@eq:SUCCESS");
|
||||
|
||||
test("예약어 - ne",
|
||||
EAITable.XML_TYPE,
|
||||
"<root><code>SUCCESS</code></root>",
|
||||
"code",
|
||||
"@ne:FAIL");
|
||||
|
||||
test("예약어 - null",
|
||||
EAITable.XML_TYPE,
|
||||
"<root><code></code></root>",
|
||||
"code",
|
||||
"@null");
|
||||
|
||||
test("예약어 - !null",
|
||||
EAITable.XML_TYPE,
|
||||
"<root><code>SUCCESS</code></root>",
|
||||
"code",
|
||||
"@!null");
|
||||
|
||||
// 2. 문자열 패턴 테스트
|
||||
test("예약어 - contains",
|
||||
EAITable.JSON_TYPE,
|
||||
"{\"status\":\"success\"}",
|
||||
"status",
|
||||
"@contains:success,ok,done");
|
||||
|
||||
test("예약어 - !contains",
|
||||
EAITable.JSON_TYPE,
|
||||
"{\"status\":\"success\"}",
|
||||
"status",
|
||||
"@!contains:fail,error,invalid");
|
||||
|
||||
test("예약어 - starts",
|
||||
EAITable.JSON_TYPE,
|
||||
"{\"code\":\"SUCCESS_001\"}",
|
||||
"code",
|
||||
"@starts:SUCCESS");
|
||||
|
||||
test("예약어 - ends",
|
||||
EAITable.JSON_TYPE,
|
||||
"{\"code\":\"ERR_001\"}",
|
||||
"code",
|
||||
"@ends:001");
|
||||
|
||||
// 3. 숫자 비교 테스트
|
||||
test("예약어 - gt",
|
||||
EAITable.JSON_TYPE,
|
||||
"{\"value\":\"100\"}",
|
||||
"value",
|
||||
"@gt:50");
|
||||
|
||||
test("예약어 - lt",
|
||||
EAITable.JSON_TYPE,
|
||||
"{\"value\":\"100\"}",
|
||||
"value",
|
||||
"@lt:150");
|
||||
|
||||
test("예약어 - ge",
|
||||
EAITable.JSON_TYPE,
|
||||
"{\"value\":\"100\"}",
|
||||
"value",
|
||||
"@ge:100");
|
||||
|
||||
test("예약어 - le",
|
||||
EAITable.JSON_TYPE,
|
||||
"{\"value\":\"100\"}",
|
||||
"value",
|
||||
"@le:100");
|
||||
|
||||
// 4. 실패 케이스
|
||||
test("예약어 - 잘못된 숫자",
|
||||
EAITable.JSON_TYPE,
|
||||
"{\"value\":\"invalid\"}",
|
||||
"value",
|
||||
"@gt:50");
|
||||
|
||||
test("예약어 - 잘못된 패턴",
|
||||
EAITable.JSON_TYPE,
|
||||
"{\"status\":\"success\"}",
|
||||
"status",
|
||||
"@invalid:pattern");
|
||||
}
|
||||
|
||||
private static void test(String testName, String type, String message, String path, String expected) {
|
||||
TestResult result = isSuccessMessageTest(type, message, path, expected);
|
||||
// System.out.println(String.format( "테스트: %s\n결과: %s\n메시지: %s\n경로: %s\n기대값: %s\n추출된 값: [%s]\n",testName, result.success ? "성공" : "실패",message,path,expected,result.extractedValue ));
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,9 @@ import static org.mockito.ArgumentMatchers.anyString;
|
||||
import java.lang.reflect.Field;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -20,6 +23,7 @@ import com.eactive.eai.common.monitor.EAIServiceMonitor;
|
||||
import com.eactive.eai.common.property.PropManager;
|
||||
import com.eactive.eai.common.server.EAIServerManager;
|
||||
import com.eactive.eai.common.util.ApplicationContextProvider;
|
||||
import com.eactive.eai.message.StandardItem;
|
||||
import com.eactive.eai.message.StandardMessage;
|
||||
import com.eactive.eai.message.manager.StandardMessageManager;
|
||||
import com.eactive.eai.message.service.InterfaceMapper;
|
||||
@@ -354,4 +358,142 @@ class StandardMessageCoordinatorDJBTest {
|
||||
assertNotNull(scopLen, "msg_scop_len이 null");
|
||||
assertTrue(Integer.parseInt(scopLen.trim()) >= 0, "msg_scop_len은 0 이상이어야 함: " + scopLen);
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// resolveCallPropRefValues — ${callProp.키} 치환
|
||||
// ================================================================
|
||||
|
||||
@Test
|
||||
void callProp_refValue_단순키_값_주입() throws Exception {
|
||||
// chnl_dtls_clcd: CSV 기본값 없음, refValue를 ${callProp.CHNL_CD}로 주입
|
||||
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.CHNL_CD}");
|
||||
|
||||
Properties prop = new Properties();
|
||||
prop.setProperty("CHNL_CD", "MOB");
|
||||
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
|
||||
|
||||
assertEquals("MOB", message.findItemValue("HEAD.chnl_dtls_clcd"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void callProp_refValue_기본값_키_없을때_기본값_사용() throws Exception {
|
||||
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.MISSING:IB1}");
|
||||
|
||||
coordinator.coordinateAfterCreateMessageByRule(message, null, new Properties());
|
||||
|
||||
assertEquals("IB1", message.findItemValue("HEAD.chnl_dtls_clcd"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void callProp_refValue_기본값_키_있을때_prop값으로_덮어씀() throws Exception {
|
||||
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.CHNL_CD:IB1}");
|
||||
|
||||
Properties prop = new Properties();
|
||||
prop.setProperty("CHNL_CD", "ATM");
|
||||
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
|
||||
|
||||
assertEquals("ATM", message.findItemValue("HEAD.chnl_dtls_clcd"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void callProp_refValue_prop_null이면_setValue_호출_안함() throws Exception {
|
||||
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.CHNL_CD}");
|
||||
|
||||
coordinator.coordinateAfterCreateMessageByRule(message, null, null);
|
||||
|
||||
String val = message.findItemValue("HEAD.chnl_dtls_clcd");
|
||||
assertTrue(val == null || val.trim().isEmpty(),
|
||||
"prop=null이면 callProp refValue 치환하지 않아야 함: " + val);
|
||||
}
|
||||
|
||||
@Test
|
||||
void callProp_refValue_패턴_불일치_필드는_skip() throws Exception {
|
||||
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "PLAIN");
|
||||
|
||||
Properties prop = new Properties();
|
||||
prop.setProperty("chnl_dtls_clcd", "SHOULD_NOT_SET");
|
||||
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
|
||||
|
||||
assertNotEquals("SHOULD_NOT_SET", message.findItemValue("HEAD.chnl_dtls_clcd"),
|
||||
"패턴 불일치 refValue는 치환하지 않아야 함");
|
||||
}
|
||||
|
||||
@Test
|
||||
void callProp_refValue_여러_필드_동시_주입() throws Exception {
|
||||
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.CHNL_CD}");
|
||||
setRefValue(message.findItem("HEAD.xtis_cd"), "${callProp.XTIS_CD}");
|
||||
|
||||
Properties prop = new Properties();
|
||||
prop.setProperty("CHNL_CD", "IB1");
|
||||
prop.setProperty("XTIS_CD", "OBK");
|
||||
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
|
||||
|
||||
assertEquals("IB1", message.findItemValue("HEAD.chnl_dtls_clcd"));
|
||||
assertEquals("OBK", message.findItemValue("HEAD.xtis_cd"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void callProp_중첩_Properties_점경로_조회() throws Exception {
|
||||
// prop.get("OUTBOUND") = subProps, subProps.getProperty("IF_ID") = "SVC001"
|
||||
// → ${callProp.OUTBOUND.IF_ID} → "SVC001"
|
||||
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.OUTBOUND.IF_CD}");
|
||||
|
||||
Properties subProps = new Properties();
|
||||
subProps.setProperty("IF_CD", "IB1");
|
||||
Properties prop = new Properties();
|
||||
prop.put("OUTBOUND", subProps);
|
||||
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
|
||||
|
||||
assertEquals("IB1", message.findItemValue("HEAD.chnl_dtls_clcd"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void callProp_중첩_Map_점경로_조회() throws Exception {
|
||||
// prop.get("CTX") = Map{"CHNL":"MOB"}
|
||||
// → ${callProp.CTX.CHNL} → "MOB"
|
||||
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.CTX.CHNL}");
|
||||
|
||||
Map<String, Object> ctxMap = new HashMap<>();
|
||||
ctxMap.put("CHNL", "MOB");
|
||||
Properties prop = new Properties();
|
||||
prop.put("CTX", ctxMap);
|
||||
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
|
||||
|
||||
assertEquals("MOB", message.findItemValue("HEAD.chnl_dtls_clcd"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void callProp_중간값_비Properties_폴백_전체키_조회() throws Exception {
|
||||
// prop.get("aaa") = "plain" (Properties가 아님) → 전체 키 "aaa.bbb" 폴백
|
||||
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.aaa.bbb}");
|
||||
|
||||
Properties prop = new Properties();
|
||||
prop.setProperty("aaa", "plain");
|
||||
prop.setProperty("aaa.bbb", "ATM");
|
||||
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
|
||||
|
||||
assertEquals("ATM", message.findItemValue("HEAD.chnl_dtls_clcd"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void callProp_중첩_키_없을때_기본값_사용() throws Exception {
|
||||
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.OUTBOUND.MISSING:IB1}");
|
||||
|
||||
Properties subProps = new Properties(); // MISSING 키 없음
|
||||
Properties prop = new Properties();
|
||||
prop.put("OUTBOUND", subProps);
|
||||
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
|
||||
|
||||
assertEquals("IB1", message.findItemValue("HEAD.chnl_dtls_clcd"));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// 헬퍼
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
private static void setRefValue(StandardItem item, String refValue) throws Exception {
|
||||
Field f = StandardItem.class.getDeclaredField("refValue");
|
||||
f.setAccessible(true);
|
||||
f.set(item, refValue);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user