Merge branch 'feature/msg-block-parse-skip'
- JsonReader: 수신 전문에 존재하는 블록을 ref 조건으로 버리지 않도록 수정 - 표준 오류응답 메시지 형식을 PropManager 에서 조회하도록 변경 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UnybKuxcuPafGhVGh4wqkZ
This commit is contained in:
@@ -119,6 +119,19 @@ public class JsonReader implements StandardReader {
|
|||||||
|
|
||||||
switch(currentNode.getNodeType()) {
|
switch(currentNode.getNodeType()) {
|
||||||
case OBJECT:
|
case OBJECT:
|
||||||
|
// refPath/refValue 는 "이 블록이 전문에 들어있는가" 를 판단하기 위한 조건이다.
|
||||||
|
// 고정길이(FLAT)는 블록의 존재를 알려주는 키가 없어 이 조건이 유일한 근거지만,
|
||||||
|
// JSON 은 키의 존재 자체가 답이다. 여기에 도달했다는 것은 수신 전문에 이 블록이
|
||||||
|
// 실제로 들어있다는 뜻이므로, 조건으로 다시 걸러내면 받은 데이터를 잃는다.
|
||||||
|
//
|
||||||
|
// 실제 사고(2026-09): 상대가 오류응답을 procs_rslt_dvcd=F 로 보내면서 요청응답구분
|
||||||
|
// dman_rspn_dvcd 는 요청값 S 를 그대로 에코백했다(표준은 응답 시 R). MSG 블록의
|
||||||
|
// 조건이 !S 라 MSG 이하가 통째로 버려졌고, 그 결과
|
||||||
|
// - MAIN_MSG 가 레이아웃 기본값으로 남아 오류가 "정상처리되었습니다." 로 보고되고
|
||||||
|
// - 거래로그는 StandardMessage 재직렬화본이라 MSG 부 이후가 통째로 누락됐다.
|
||||||
|
//
|
||||||
|
// 조건 불일치는 상대 헤더의 오류로 보고, 경고만 남기고 파싱은 계속한다.
|
||||||
|
// (FlatReader 는 조건이 존재 판단에 반드시 필요하므로 그대로 둔다.)
|
||||||
if( currentItem != null && currentItem.getSize() == 0
|
if( currentItem != null && currentItem.getSize() == 0
|
||||||
&& StringUtils.isNotBlank(currentItem.getRefPath())
|
&& StringUtils.isNotBlank(currentItem.getRefPath())
|
||||||
&& StringUtils.isNotBlank(currentItem.getRefValue()) ) {
|
&& StringUtils.isNotBlank(currentItem.getRefValue()) ) {
|
||||||
@@ -131,26 +144,21 @@ public class JsonReader implements StandardReader {
|
|||||||
|
|
||||||
if (refItemValue != null) refItemValue = refItemValue.trim();
|
if (refItemValue != null) refItemValue = refItemValue.trim();
|
||||||
String refValue = currentItem.getRefValue();
|
String refValue = currentItem.getRefValue();
|
||||||
if (refValue.startsWith("!")) { // 느낌표가 들어가면 다음에 나오는게 아닌경우
|
boolean negate = refValue.startsWith("!"); // 느낌표가 들어가면 다음에 나오는게 아닌경우
|
||||||
|
if (negate) {
|
||||||
refValue = refValue.substring(1);
|
refValue = refValue.substring(1);
|
||||||
if (refValue.equals(refItemValue)) {
|
}
|
||||||
logger.warn("@GROUP name={} SKIPPED.", currentItem.getName());
|
boolean matched = refValue.equals(refItemValue);
|
||||||
currentItem.setHidden(true);
|
if (negate) {
|
||||||
break;
|
matched = !matched;
|
||||||
} else {
|
}
|
||||||
|
if (!matched) {
|
||||||
|
logger.warn("@GROUP name={} 조건 불일치({}=[{}], 기대=[{}]). 수신 전문에 존재하므로 파싱은 계속한다.",
|
||||||
|
currentItem.getName(), currentItem.getRefPath(), refItemValue,
|
||||||
|
currentItem.getRefValue());
|
||||||
|
}
|
||||||
currentItem.setHidden(false);
|
currentItem.setHidden(false);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (!currentItem.getRefValue().equals(refItemValue)) {
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
logger.warn("@GROUP name={} SKIPPED.", currentItem.getName());
|
|
||||||
currentItem.setHidden(true);
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
currentItem.setHidden(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Iterator<String> fieldNames = currentNode.fieldNames();
|
Iterator<String> fieldNames = currentNode.fieldNames();
|
||||||
while(fieldNames.hasNext()) {
|
while(fieldNames.hasNext()) {
|
||||||
fieldName = fieldNames.next();
|
fieldName = fieldNames.next();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.eactive.eai.common.header.HeaderActionKeys;
|
|||||||
import com.eactive.eai.common.message.EAIMessage;
|
import com.eactive.eai.common.message.EAIMessage;
|
||||||
import com.eactive.eai.common.message.EAIMessageKeys;
|
import com.eactive.eai.common.message.EAIMessageKeys;
|
||||||
import com.eactive.eai.common.message.MessageType;
|
import com.eactive.eai.common.message.MessageType;
|
||||||
|
import com.eactive.eai.common.property.PropManager;
|
||||||
import com.eactive.eai.common.routing.Process;
|
import com.eactive.eai.common.routing.Process;
|
||||||
import com.eactive.eai.common.server.EAIServerManager;
|
import com.eactive.eai.common.server.EAIServerManager;
|
||||||
import com.eactive.eai.common.submessage.SubMessageManager;
|
import com.eactive.eai.common.submessage.SubMessageManager;
|
||||||
@@ -43,6 +44,12 @@ public abstract class DefaultProcess extends Process {
|
|||||||
protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
|
protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
|
||||||
protected static Logger esbLogger = Logger.getLogger(Logger.LOGGER_ESBFW);
|
protected static Logger esbLogger = Logger.getLogger(Logger.LOGGER_ESBFW);
|
||||||
|
|
||||||
|
/** 표준 오류응답 메시지 형식을 조회할 프로퍼티 그룹/키. 없으면 기본형식을 쓴다. */
|
||||||
|
public static final String PROP_GROUP = "DefaultProcess";
|
||||||
|
public static final String PROP_STD_ERR_MSG_FORMAT = "std.error.msg.format";
|
||||||
|
/** 인자 순서: 1=오류코드, 2=오류메시지, 3=오류상세 */
|
||||||
|
public static final String DEFAULT_STD_ERR_MSG_FORMAT = "[%s] %s";
|
||||||
|
|
||||||
protected String guidLogPrefix = this.getClass().getSimpleName() + "] ";
|
protected String guidLogPrefix = this.getClass().getSimpleName() + "] ";
|
||||||
|
|
||||||
protected static ThreadLocal local = new ThreadLocal(); // 경과시간 동기화를 위한 ThreadLocal
|
protected static ThreadLocal local = new ThreadLocal(); // 경과시간 동기화를 위한 ThreadLocal
|
||||||
@@ -689,7 +696,7 @@ public abstract class DefaultProcess extends Process {
|
|||||||
String errorCode = mapper.getErrorCode(resStandardMessage);
|
String errorCode = mapper.getErrorCode(resStandardMessage);
|
||||||
String errorMsg = StringUtils.trim(mapper.getErrorMsg(resStandardMessage));
|
String errorMsg = StringUtils.trim(mapper.getErrorMsg(resStandardMessage));
|
||||||
String errorDesc = StringUtils.trim(resStandardMessage.findItemValue("MSG.MAIN_MSG.outp_msg_desc"));
|
String errorDesc = StringUtils.trim(resStandardMessage.findItemValue("MSG.MAIN_MSG.outp_msg_desc"));
|
||||||
this.resEaiMsg.setRspErr("RECEAIINA001", String.format("[%s] %s (%s)", errorCode, errorMsg, errorDesc));
|
this.resEaiMsg.setRspErr("RECEAIINA001", formatStdErrorMessage(errorCode, errorMsg, errorDesc));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
this.resEaiMsg.setRspErr("RECEAIINA001", "비표준 오류 응답 수신");
|
this.resEaiMsg.setRspErr("RECEAIINA001", "비표준 오류 응답 수신");
|
||||||
@@ -707,7 +714,7 @@ public abstract class DefaultProcess extends Process {
|
|||||||
String errorCode = mapper.getErrorCode(resStandardMessage);
|
String errorCode = mapper.getErrorCode(resStandardMessage);
|
||||||
String errorMsg = StringUtils.trim(mapper.getErrorMsg(resStandardMessage));
|
String errorMsg = StringUtils.trim(mapper.getErrorMsg(resStandardMessage));
|
||||||
String errorDesc = StringUtils.trim(resStandardMessage.findItemValue("MSG.MAIN_MSG.outp_msg_desc"));
|
String errorDesc = StringUtils.trim(resStandardMessage.findItemValue("MSG.MAIN_MSG.outp_msg_desc"));
|
||||||
this.resEaiMsg.setRspErr("RECEAIINA001", String.format("[%s] %s (%s)", errorCode, errorMsg, errorDesc));
|
this.resEaiMsg.setRspErr("RECEAIINA001", formatStdErrorMessage(errorCode, errorMsg, errorDesc));
|
||||||
} else {
|
} else {
|
||||||
this.resEaiMsg.setRspErr("RECEAIINA001", "비표준 오류 응답 수신");
|
this.resEaiMsg.setRspErr("RECEAIINA001", "비표준 오류 응답 수신");
|
||||||
}
|
}
|
||||||
@@ -720,6 +727,37 @@ public abstract class DefaultProcess extends Process {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 표준 오류응답 메시지를 조립한다.
|
||||||
|
*
|
||||||
|
* 형식은 PropManager 의 {@code DefaultProcess / std.error.msg.format} 에서 가져온다.
|
||||||
|
* 프로퍼티는 에이전트의 ReloadPropertyCommand 로 무중단 갱신될 수 있으므로,
|
||||||
|
* 캐시하지 않고 호출할 때마다 조회한다. 그룹이나 키가 없으면
|
||||||
|
* {@link #DEFAULT_STD_ERR_MSG_FORMAT} 를 쓴다.
|
||||||
|
*
|
||||||
|
* 형식 문자열은 운영에서 편집 가능하므로 잘못된 형식(예: %s 개수 불일치)이 들어올 수 있다.
|
||||||
|
* 이 메서드는 오류응답 경로에서 호출되므로 여기서 예외가 나면 오류 자체를 못 내려보낸다.
|
||||||
|
* 따라서 조립에 실패하면 경고만 남기고 기본형식으로 되돌린다.
|
||||||
|
*
|
||||||
|
* @param errorCode 오류코드 (형식 인자 1)
|
||||||
|
* @param errorMsg 오류메시지 (형식 인자 2)
|
||||||
|
* @param errorDesc 오류상세 (형식 인자 3)
|
||||||
|
*/
|
||||||
|
protected String formatStdErrorMessage(String errorCode, String errorMsg, String errorDesc) {
|
||||||
|
String format = PropManager.getInstance().getProperty(
|
||||||
|
PROP_GROUP, PROP_STD_ERR_MSG_FORMAT, DEFAULT_STD_ERR_MSG_FORMAT);
|
||||||
|
if (StringUtils.isBlank(format)) {
|
||||||
|
format = DEFAULT_STD_ERR_MSG_FORMAT;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return String.format(format, errorCode, errorMsg, errorDesc);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warn(guidLogPrefix + " 표준 오류응답 형식이 잘못되어 기본형식으로 대체한다. ["
|
||||||
|
+ PROP_GROUP + "/" + PROP_STD_ERR_MSG_FORMAT + "=" + format + "] - " + e.getMessage());
|
||||||
|
return String.format(DEFAULT_STD_ERR_MSG_FORMAT, errorCode, errorMsg, errorDesc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isTgtTranCall() {
|
public boolean isTgtTranCall() {
|
||||||
return this.isTgtTran;
|
return this.isTgtTran;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user