feat: StandardMessageCoordinatorDJB에 callProp refValue 값 주입 기능 추가

- coordinateAfterCreateMessageByRule에서 StandardItem의 refValue가
   \${callProp.키} 패턴이면 Properties에서 값을 꺼내 setValue로 설정한다.
- \${callProp.키:기본값} 구문으로 기본값 지정 가능
- 점(.) 구분으로 Properties/Map 중첩 구조 탐색 지원
- GROUP 타입 재귀 순회, GRID/FARRAY는 건너뜀
This commit is contained in:
curry772
2026-06-05 17:20:09 +09:00
parent dafe80f8bc
commit 68c29b962e
2 changed files with 214 additions and 0 deletions
@@ -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);
}
}