diff --git a/axhub-common/src/main/java/io/shinhanlife/glow/util/GlowTrgmParser.java b/axhub-common/src/main/java/io/shinhanlife/glow/util/GlowTrgmParser.java new file mode 100644 index 0000000..247b4b1 --- /dev/null +++ b/axhub-common/src/main/java/io/shinhanlife/glow/util/GlowTrgmParser.java @@ -0,0 +1,92 @@ +package io.shinhanlife.glow.util; + +import io.shinhanlife.glow.GlowTrgmField; +import lombok.extern.slf4j.Slf4j; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +/** + * @package io.shinhanlife.glow.util + * @className GlowTrgmParser + * @description AX HUB 시스템 처리 클래스 + * @author 김형식 + * @create 2026.09.01 + *
+ * ---------- 개정이력 ----------
+ * 수정일      수정자    수정내용
+ * ---------- -------- ---------------------------
+ * 2026.09.01  김형식    최초생성
+ * 
+ * 
+ */ +@Slf4j +public class GlowTrgmParser { + + /** + * 고정 길이 문자열 전문을 @GlowTrgmField 어노테이션 정보에 따라 DTO 객체로 파싱합니다. + * @param trgmString 원본 전문 문자열 + * @param clazz 매핑할 DTO 클래스 + * @return 파싱된 DTO 인스턴스 + */ + public static T parse(String trgmString, Class clazz) { + if (trgmString == null || trgmString.isEmpty()) { + return null; + } + + try { + T instance = clazz.getDeclaredConstructor().newInstance(); + + List fields = new ArrayList<>(); + for (Field field : clazz.getDeclaredFields()) { + if (field.isAnnotationPresent(GlowTrgmField.class)) { + fields.add(field); + } + } + + fields.sort(Comparator.comparingInt(f -> f.getAnnotation(GlowTrgmField.class).order())); + + int currentIndex = 0; + for (Field field : fields) { + GlowTrgmField annotation = field.getAnnotation(GlowTrgmField.class); + int length = annotation.length(); + + if (currentIndex >= trgmString.length()) { + break; + } + + int endIndex = Math.min(currentIndex + length, trgmString.length()); + String value = trgmString.substring(currentIndex, endIndex).trim(); + + field.setAccessible(true); + setFieldValue(instance, field, value); + + currentIndex += length; + } + + return instance; + } catch (Exception e) { + log.error("GlowTrgmField 파싱 중 오류 발생: {}", e.getMessage(), e); + throw new RuntimeException("전문 파싱 오류", e); + } + } + + private static void setFieldValue(Object instance, Field field, String value) throws IllegalAccessException { + Class fieldType = field.getType(); + + if (fieldType == String.class) { + field.set(instance, value); + } else if (fieldType == int.class || fieldType == Integer.class) { + field.set(instance, value.isEmpty() ? 0 : Integer.parseInt(value)); + } else if (fieldType == long.class || fieldType == Long.class) { + field.set(instance, value.isEmpty() ? 0L : Long.parseLong(value)); + } else if (fieldType == boolean.class || fieldType == Boolean.class) { + field.set(instance, Boolean.parseBoolean(value)); + } else if (fieldType == double.class || fieldType == Double.class) { + field.set(instance, value.isEmpty() ? 0.0 : Double.parseDouble(value)); + } else { + field.set(instance, value); + } + } +} diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/connector/LegacyEimsConnector.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/connector/LegacyEimsConnector.java index 9408b63..1bf3703 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/connector/LegacyEimsConnector.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/connector/LegacyEimsConnector.java @@ -40,6 +40,7 @@ public class LegacyEimsConnector { private final EimsSender jspJsonEimsSender; // 41~50 (JSP JSON) private final EimsSender mciEimsSender; // 실시간 연계 (기존 HTTP/TCP 대체, 동기식 API) + private final EimsSender mciStringEimsSender; // 실시간 연계 (String 전문 버전) private final EimsSender eaiEimsSender; // 비동기/대용량 연계 (배치 통신 등) private final ObjectMapper jsonMapper; @@ -76,6 +77,10 @@ public class LegacyEimsConnector { log.info("[라우팅] JSP JSON 통신으로 전달"); legacyResponse = jspJsonEimsSender.send(interfaceId, payload); } + else if ("MCI_STRING".equalsIgnoreCase(routingType)) { + log.info("[라우팅] 실시간 AI 요청 -> MCI 연계 어댑터(String)를 통해 EIMS 전달"); + legacyResponse = mciStringEimsSender.send(interfaceId, payload); + } else { // 3. 아키텍처 규격에 맞춘 라우팅 (실시간 vs 비동기) if (isMciRouting(routingType, interfaceId)) { diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/sender/MciStringEimsSender.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/sender/MciStringEimsSender.java new file mode 100644 index 0000000..52b204a --- /dev/null +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/adapter/sender/MciStringEimsSender.java @@ -0,0 +1,58 @@ +package io.shinhanlife.axhub.biz.mcp.adapter.sender; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.util.StopWatch; +import org.springframework.web.client.RestClient; + +/** + * @package io.shinhanlife.axhub.biz.mcp.adapter.sender + * @className MciStringEimsSender + * @description AX HUB 시스템 처리 클래스 + * @author 김형식 + * @create 2026.09.01 + *
+ * ---------- 개정이력 ----------
+ * 수정일      수정자    수정내용
+ * ---------- -------- ---------------------------
+ * 2026.09.01  김형식    최초생성
+ * 
+ * 
+ */ +@Slf4j +@Service("mciStringEimsSender") +public class MciStringEimsSender implements EimsSender { + + private final RestClient restClient; + private final String mciUrl; + + public MciStringEimsSender(@Value("${eims.mci.url}") String mciUrl) { + this.mciUrl = mciUrl; + this.restClient = RestClient.create(); + } + + @Override + public String send(String interfaceId, String payload) throws Exception { + StopWatch stopWatch = new StopWatch(); stopWatch.start(); + + try { + log.info("🌐 [ESB 어댑터(String)] 전송 준비 완료 - RestClient 호출 시작 (Interface: {})", interfaceId); + + String response = restClient.post() + .uri(mciUrl) + .contentType(MediaType.TEXT_PLAIN) + .body(payload != null ? payload : "") + .retrieve() + .body(String.class); + + log.info("🌐 [ESB 어댑터(String)] 응답 수신 완료: {}", response); + return response != null ? response : ""; + + } finally { + stopWatch.stop(); + log.info("📊 [SLA 모니터링 - MCI(String)] 소요시간: {} ms", stopWatch.getTotalTimeMillis()); + } + } +} diff --git a/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/SampleStringReq.java b/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/SampleStringReq.java new file mode 100644 index 0000000..49d49cf --- /dev/null +++ b/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/SampleStringReq.java @@ -0,0 +1,24 @@ +package io.shinhanlife.axhub.biz.mcp.tool.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +/** + * @package io.shinhanlife.axhub.biz.mcp.tool.dto + * @className SampleStringReq + * @description AX HUB 시스템 처리 클래스 + * @author 김형식 + * @create 2026.09.01 + *
+ * ---------- 개정이력 ----------
+ * 수정일      수정자    수정내용
+ * ---------- -------- ---------------------------
+ * 2026.09.01  김형식    최초생성
+ * 
+ * 
+ */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class SampleStringReq { + private String query; +} diff --git a/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/SampleStringRes.java b/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/SampleStringRes.java new file mode 100644 index 0000000..0656cf1 --- /dev/null +++ b/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/SampleStringRes.java @@ -0,0 +1,35 @@ +package io.shinhanlife.axhub.biz.mcp.tool.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.shinhanlife.glow.GlowTrgmField; +import lombok.Data; + +/** + * @package io.shinhanlife.axhub.biz.mcp.tool.dto + * @className SampleStringRes + * @description AX HUB 시스템 처리 클래스 + * @author 김형식 + * @create 2026.09.01 + *
+ * ---------- 개정이력 ----------
+ * 수정일      수정자    수정내용
+ * ---------- -------- ---------------------------
+ * 2026.09.01  김형식    최초생성
+ * 
+ * 
+ */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class SampleStringRes { + @GlowTrgmField(order = 1, length = 10, description = "이름") + private String name; + + @GlowTrgmField(order = 2, length = 3, description = "나이") + private int age; + + @GlowTrgmField(order = 3, length = 8, description = "가입일자(YYYYMMDD)") + private String joinDate; + + @GlowTrgmField(order = 4, length = 2, description = "상태코드") + private String statusCode; +} diff --git a/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/SampleStringToolService.java b/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/SampleStringToolService.java new file mode 100644 index 0000000..26c42d9 --- /dev/null +++ b/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/SampleStringToolService.java @@ -0,0 +1,50 @@ +package io.shinhanlife.axhub.biz.mcp.tool.service; + +import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpFunction; +import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpTool; +import io.shinhanlife.axhub.biz.mcp.tool.dto.SampleStringReq; +import io.shinhanlife.axhub.biz.mcp.tool.dto.SampleStringRes; +import io.shinhanlife.glow.util.GlowTrgmParser; +import org.springframework.stereotype.Service; + +/** + * @package io.shinhanlife.axhub.biz.mcp.tool.service + * @className SampleStringToolService + * @description AX HUB 시스템 처리 클래스 + * @author 김형식 + * @create 2026.09.01 + *
+ * ---------- 개정이력 ----------
+ * 수정일      수정자    수정내용
+ * ---------- -------- ---------------------------
+ * 2026.09.01  김형식    최초생성
+ * 
+ * 
+ */ +@Service +@McpTool( + routingType = "MCI_STRING", + group = "COMMON" +) +public class SampleStringToolService extends AbstractMcpToolService { + + @McpFunction( + name = "get_sample_string", + description = "MCI String 버전과 GlowTrgmField 파싱을 테스트하는 샘플 툴입니다.", + prompt = "MCI 전문(String) 연계 및 고정 길이 파싱 테스트 해줘.", + mappingId = "TRGM_001" + ) + public Object execute(SampleStringReq req) { + // 1. EIMS(Legacy)를 통해 원본 고정 길이 문자열을 받아옵니다. + java.util.Map result = executeLegacy("MCI_STRING", "TRGM_001", req); + + if ("ERROR".equals(result.get("status"))) { + return result; + } + + String rawStringResponse = (String) result.get("legacy_response"); + + // 2. 받아온 고정 길이 전문(String)을 GlowTrgmParser를 이용해 DTO로 파싱합니다. + return GlowTrgmParser.parse(rawStringResponse, SampleStringRes.class); + } +} diff --git a/axhub-tool-other/src/main/resources/application-local.yml b/axhub-tool-other/src/main/resources/application-local.yml index 2257959..3373231 100644 --- a/axhub-tool-other/src/main/resources/application-local.yml +++ b/axhub-tool-other/src/main/resources/application-local.yml @@ -44,3 +44,7 @@ mcp: description: "고객상세 정보 조회" prompt: "이 고객의 상세 기본정보(주소, 연락처 등)를 알려줘." mappingId: "CRM_002" + get_sample_string: + description: "MCI String 버전과 GlowTrgmField 파싱을 테스트하는 샘플 툴입니다." + prompt: "MCI 전문(String) 연계 및 고정 길이 파싱 테스트 해줘." + mappingId: "TRGM_001"