diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/util/PodScaffolder.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/util/PodScaffolder.java deleted file mode 100644 index d8425f648..000000000 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/util/PodScaffolder.java +++ /dev/null @@ -1,308 +0,0 @@ -package io.shinhanlife.dap.lib.util; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.Scanner; - -public class PodScaffolder { - - public static void main(String[] args) throws IOException { - Scanner scanner = new Scanner(System.in); - - System.out.println("========================================="); - System.out.println(" MCP Tool Pod Scaffolder (Java CLI) "); - System.out.println("=========================================\n"); - - String rawModuleName = getOrAsk(args, 0, scanner, "1. 생성할 모듈(Pod) 이름 (예: payment 또는 dap-was-payment): "); - String moduleName = rawModuleName.startsWith("dap-was-") ? rawModuleName : "dap-was-" + rawModuleName; - String portStr = getOrAsk(args, 1, scanner, "2. 사용할 포트 번호 (예: 8085): "); - String shortName = moduleName.replace("dap-was-", "").replace("-", ""); - - String defaultAuthor = System.getProperty("user.name"); - String defaultDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd")); - - String author = getOrAsk(args, 2, scanner, "3. 작성자 (엔터 입력 시 '" + defaultAuthor + "'): "); - if (author.trim().isEmpty()) author = defaultAuthor; - String createDate = getOrAsk(args, 3, scanner, "4. 작성일 (엔터 입력 시 '" + defaultDate + "'): "); - if (createDate.trim().isEmpty()) createDate = defaultDate; - - String result = scaffoldPod(moduleName, portStr, shortName, author, createDate); - System.out.println(result); - } - - private static String getOrAsk(String[] args, int index, Scanner scanner, String prompt) { - if (args.length > index) { - return args[index]; - } - System.out.print(prompt); - return scanner.nextLine().trim(); - } - - public static String scaffoldPod(String moduleName, String portStr, String shortName, String author, String createDate) throws IOException { - String envSourceDir = System.getenv("AXHUB_SOURCE_DIR"); - Path rootDir = envSourceDir != null ? Paths.get(envSourceDir) : Paths.get("."); - - Path modulePath = rootDir.resolve(Paths.get(moduleName)); - if (Files.exists(modulePath)) { - return "[오류] 이미 존재하는 모듈입니다: " + moduleName; - } - - StringBuilder log = new StringBuilder(); - log.append("[1/6] 모듈 디렉터리 생성 중...\n"); - Files.createDirectories(modulePath); - - log.append("[2/6] build.gradle 생성 중...\n"); - String buildGradle = """ - plugins { - id 'org.springframework.boot' - } - dependencies { - implementation project(':dap-was-core') - } - dependencies { - compileOnly 'org.projectlombok:lombok:1.18.32' - annotationProcessor 'org.projectlombok:lombok:1.18.32' - } - """; - Files.writeString(modulePath.resolve("build.gradle"), buildGradle); - - log.append("[3/6] Dockerfile 생성 중...\n"); - String dockerfile = """ - FROM eclipse-temurin:21-jdk-alpine - WORKDIR /app - COPY build/libs/%s-0.0.1-SNAPSHOT.jar app.jar - ENTRYPOINT ["java", "-jar", "app.jar"] - """.formatted(moduleName); - Files.writeString(modulePath.resolve("Dockerfile"), dockerfile); - - log.append("[4/6] Application 클래스 및 설정 파일 생성 중...\n"); - Path srcPath = modulePath.resolve("src/main/java/io/shinhanlife/dap/mcc/" + shortName); - Files.createDirectories(srcPath); - - String appClass = """ - package io.shinhanlife.dap.mcc.%s; - - import org.springframework.boot.SpringApplication; - import org.springframework.boot.autoconfigure.SpringBootApplication; - import org.springframework.boot.context.properties.ConfigurationPropertiesScan; - import org.springframework.cache.annotation.EnableCaching; - - /** - * @package io.shinhanlife.dap.mcc.%s - * @className DapWas%sApplication - * @description AX HUB 시스템 처리 클래스 - * @author %s - * @create %s - *
-             * ---------- 개정이력 ----------
-             * 수정일      수정자    수정내용
-             * ---------- -------- ---------------------------
-             * %s  %s    최초생성
-             * 
-             * 
- */ - @SpringBootApplication(scanBasePackages = {"io.shinhanlife.dap.mcc", "io.shinhanlife.dap.lib.adapter", "io.shinhanlife.dap.lib.mcp", "io.shinhanlife.dap.lib.config", "io.shinhanlife.dap.lib.integration"}) - @ConfigurationPropertiesScan(basePackages = {"io.shinhanlife.dap.mcc", "io.shinhanlife.dap.lib.adapter", "io.shinhanlife.dap.lib.mcp", "io.shinhanlife.dap.lib.config", "io.shinhanlife.dap.lib.integration"}) - @EnableCaching - public class DapWas%sApplication { - public static void main(String[] args) { - SpringApplication.run(DapWas%sApplication.class, args); - } - } - """.formatted(shortName, shortName, capitalize(shortName), author, createDate, createDate, author, capitalize(shortName), capitalize(shortName)); - Files.writeString(srcPath.resolve("DapTool" + capitalize(shortName) + "Application.java"), appClass); - - Path resPath = modulePath.resolve("src/main/resources"); - Files.createDirectories(resPath); - String applicationYml = """ - server: - port: %s - spring: - application: - name: %s - profiles: - active: local - logging: - level: - org.apache.kafka: ERROR - mcp: - namespace: "" - security: - tenant-domains: - TESTER-DEV: ALL - """.formatted(portStr, moduleName); - Files.writeString(resPath.resolve("application.yml"), applicationYml); - - String applicationLocalYml = """ - # Local 환경 전용 설정 (H2 메모리 DB 등) - spring: - datasource: - url: jdbc:p6spy:h2:mem:testdb;DB_CLOSE_DELAY=-1; - driverClassName: com.p6spy.engine.spy.P6SpyDriver - username: sa - password: password - h2: - console: - enabled: true - - eims: - http: - url: http://localhost:${server.port}/api/gateway - tcp: - host: 127.0.0.1 - port: 8090 - timeout: 5000 - jsp: - form: - url: http://localhost:${server.port}/mock/jsp-form - json: - url: http://localhost:${server.port}/mock/jsp-json - mci: - url: http://localhost:${server.port}/api/mock/esb/api - mcistring: - url: http://localhost:${server.port}/api/mock/esb/string - - mcp: - security: - tenant-domains: - mcp-client-1: CUSTOMER,COMMON - mcp-client-2: ALL - - axhub: - gateway: - url: http://localhost:8081 - tool: - url: ${AXHUB_TOOL_URL:http://localhost:${server.port}} - """; - Files.writeString(resPath.resolve("application-local.yml"), applicationLocalYml); - - String applicationDevYml = """ - # OCI 클라우드 환경 전용 설정 - server: - port: ${PORT:%s} - - axhub: - gateway: - url: https://axhubmcp.devjun.net - tool: - url: http://144.24.70.100:%s - - eims: - http: - url: http://localhost:${server.port}/api/gateway - tcp: - host: 127.0.0.1 - port: 8090 - timeout: 5000 - jsp: - form: - url: http://localhost:${server.port}/mock/jsp-form - json: - url: http://localhost:${server.port}/mock/jsp-json - mci: - url: http://localhost:${server.port}/api/mock/esb/api - mcistring: - url: http://localhost:${server.port}/api/mock/esb/string - - shinhan: - integration: - envrTypeCd: D - eai: - url: http://10.176.32.181 - internalMci: - url: http://10.176.32.173 - bancaMci: - url: http://10.176.32.117 - externalMci: - url: http://10.176.32.176 - """.formatted(portStr, portStr); - Files.writeString(resPath.resolve("application-dev.yml"), applicationDevYml); - - String logbackXml = """ - - - - - - ${LOG_PATTERN} - - - - logs/%s.log - - logs/%s-%%d{yyyy-MM-dd}.log - 30 - - - ${LOG_PATTERN} - - - - - - - - - """.formatted(moduleName, moduleName); - Files.writeString(resPath.resolve("logback-spring.xml"), logbackXml); - - log.append("[5/6] settings.gradle 에 모듈 등록 중...\n"); - Path settingsPath = rootDir.resolve(Paths.get("settings.gradle")); - if (Files.exists(settingsPath)) { - String settings = Files.readString(settingsPath); - if (!settings.contains("include '" + moduleName + "'")) { - Files.writeString(settingsPath, System.lineSeparator() + "include '" + moduleName + "'" + System.lineSeparator(), StandardOpenOption.APPEND); - } - } - - log.append("[6/6] docker-compose.yml 에 서비스 추가 중...\n"); - Path dockerComposePath = rootDir.resolve(Paths.get("docker-compose.yml")); - if (Files.exists(dockerComposePath)) { - String compose = Files.readString(dockerComposePath); - String serviceName = moduleName.replace("dap-", ""); // e.g. tool-payment - if (!compose.contains(" " + serviceName + ":")) { - String newService = """ - %s: - build: - context: . - dockerfile: %s/Dockerfile - ports: - - "%s:%s" - depends_on: - - redis - environment: - - TZ=Asia/Seoul - - SPRING_REDIS_HOST=redis - - SPRING_REDIS_PORT=6379 - - SPRING_DATA_REDIS_PORT=6379 - - AXHUB_TOOL_URL=http://%s:%s - - GLOW_COMMUNICATION_MCI_HOST=http://mci-mock - - GLOW_COMMUNICATION_MCI_PORT=8080 - - GLOW_COMMUNICATION_EXTMCI_HOST=http://mci-mock - - GLOW_COMMUNICATION_EXTMCI_PORT=8080 - - GLOW_COMMUNICATION_EAI_HOST=http://mci-mock - - GLOW_COMMUNICATION_EAI_PORT=8080 - """.formatted(serviceName, moduleName, portStr, portStr, serviceName, portStr); - Files.writeString(dockerComposePath, System.lineSeparator() + newService, StandardOpenOption.APPEND); - } - } - - log.append("\n=========================================\n"); - log.append(" Pod Scaffolding Complete! \n"); - log.append("=========================================\n"); - log.append("1. [새로운 모듈] ").append(moduleName).append(" 폴더가 생성되었습니다.\n"); - log.append("2. [ToolScaffolder]를 사용해 이 모듈 안에 툴을 추가하세요.\n"); - log.append("3. 실행 전 Gradle 동기화(Sync)를 한 번 진행해 주세요.\n"); - return log.toString(); - } - - private static String capitalize(String str) { - if (str == null || str.isEmpty()) return str; - return str.substring(0, 1).toUpperCase() + str.substring(1); - } -} diff --git a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/util/ToolScaffolder.java b/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/util/ToolScaffolder.java deleted file mode 100644 index ffcaacd53..000000000 --- a/dap-was-lib/src/main/java/io/shinhanlife/dap/lib/util/ToolScaffolder.java +++ /dev/null @@ -1,714 +0,0 @@ -package io.shinhanlife.dap.lib.util; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.Locale; -import java.util.Scanner; - -/** - * MCP Tool 코드를 자동 생성(Scaffolding)하는 유틸리티 클래스 - * - * [실행 방법] - * 방법 1. IDE(IntelliJ 등)에서 직접 실행 (대화형 모드 추천 ⭐) - * - 이 클래스(ToolScaffolder.java)를 열고 main 메서드를 직접 실행(Run)합니다. - * - 콘솔 창에 뜨는 질문에 차례대로 값을 입력하기만 하면 파일이 생성됩니다. - * - * 방법 2. 커맨드라인(터미널)에서 실행 (명령어 기반) - * - 컴파일: javac -encoding UTF-8 dap-was-core/src/main/java/io/shinhanlife/dap/mcc/util/ToolScaffolder.java - * - 실행: java -cp dap-was-core/src/main/java io.shinhanlife.dap.lib.util.ToolScaffolder [이름] [ID] "[설명]" "[그룹]" "[통신방식]" "[모듈명]" - */ -/** - * @package io.shinhanlife.dap.lib.util - * @className ToolScaffolder - * @description AX HUB 시스템 처리 클래스 - * @author 0986406 - * @create 2026.09.01 - *
- * ---------- 개정이력 ----------
- * 수정일      수정자    수정내용
- * ---------- -------- ---------------------------
- * 2026.09.01  0986406    최초생성
- * 
- * 
- */ -public class ToolScaffolder { - - private static final String BASE_PACKAGE = "io.shinhanlife.dap.mcc"; - private static final String BASE_PACKAGE_PATH = "src/main/java/io/shinhanlife/dap/mcc"; - - public static void main(String[] args) throws IOException { - Scanner scanner = new Scanner(System.in); - - System.out.println("========================================="); - System.out.println(" MCP Tool Scaffolder (Java CLI) "); - System.out.println("=========================================\n"); - - String baseName = getOrAsk(args, 0, scanner, "1. 생성할 Tool의 기본 이름 (예: ExchangeRate) [영문 PascalCase]: "); - String interfaceId = getOrAsk(args, 1, scanner, "2. 레거시 API 인터페이스 ID (예: EXCH_001): "); - String description = getOrAsk(args, 2, scanner, "3. Tool 기능 설명 (예: 환율 조회): "); - String group = getOrAsk(args, 3, scanner, "4. Tool 소속 그룹 (예: SAMPLE, NOTIFICATION, CLAIM, POLICY, HR, CONTRACT, CUSTOMER 등): "); - if (group.isEmpty()) group = "COMMON"; - String routingType = getOrAsk(args, 4, scanner, "5. 통신 프로토콜 (예: HTTP, TCP, MCI, EAI): "); - if (routingType.trim().isEmpty()) { - routingType = "HTTP"; - } - String moduleName = getOrAsk(args, 5, scanner, "6. 코드를 생성할 모듈 (기본: dap-was-oth): "); - if (moduleName.trim().isEmpty()) { - moduleName = "dap-was-oth"; - } - - String defaultAuthor = System.getProperty("user.name"); - String defaultDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd")); - - String author = getOrAsk(args, 6, scanner, "7. 작성자 (엔터 입력 시 '" + defaultAuthor + "'): "); - if (author.trim().isEmpty()) author = defaultAuthor; - String createDate = getOrAsk(args, 7, scanner, "8. 작성일 (엔터 입력 시 '" + defaultDate + "'): "); - if (createDate.trim().isEmpty()) createDate = defaultDate; - - String result = scaffold(baseName, interfaceId, description, group, routingType, moduleName, author, createDate, true, null); - System.out.println(result); - } - - private static String getOrAsk(String[] args, int index, Scanner scanner, String prompt) { - if (args.length > index) { - return args[index]; - } - System.out.print(prompt); - return scanner.nextLine().trim(); - } - - public static String scaffold(String baseName, String interfaceId, String description, String group, String routingType, String moduleName, String author, String createDate, boolean register, String clientSystemCode) throws IOException { - baseName = toPascalCase(baseName); - String envSourceDir = System.getenv("AXHUB_SOURCE_DIR"); - Path rootDir = envSourceDir != null ? Paths.get(envSourceDir) : Paths.get("."); - - Path usecaseDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, "biz", group.toLowerCase(), "usecase")); - Path usecaseImplDir = usecaseDir.resolve("impl"); - Path dtoDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, "biz", group.toLowerCase(), "dto")); - - Path legacyDtoDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, "biz", group.toLowerCase(), "legacy")); - Path converterDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, "biz", group.toLowerCase(), "converter")); - - String bizPackage = BASE_PACKAGE + ".biz." + group.toLowerCase(); - boolean isMci = "MCI".equalsIgnoreCase(routingType); - String mciGroupPath = "infra/itrf/mci/" + group.toLowerCase(); - String clientPkgSuffix = ""; - String clientPrefixCap = ""; - Path mciClientDir = null; - - if (isMci && clientSystemCode != null && clientSystemCode.length() == 4) { - String clientPrefix = clientSystemCode.toLowerCase(); - clientPkgSuffix = clientPrefix.substring(0, 3) + "." + clientPrefix.substring(3, 4); - clientPrefixCap = toPascalCase(clientSystemCode); - mciGroupPath = "infra/itrf/mci/" + clientPrefix.substring(0, 3) + "/" + clientPrefix.substring(3, 4); - mciClientDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, mciGroupPath)); - } - - Path mciIoDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, mciGroupPath, "io")); - - Files.createDirectories(usecaseDir); - Files.createDirectories(usecaseImplDir); - Files.createDirectories(dtoDir); - if (isMci) { - Files.createDirectories(mciIoDir); - if (mciClientDir != null) { - Files.createDirectories(mciClientDir); - } - } else { - Files.createDirectories(legacyDtoDir); - } - Files.createDirectories(converterDir); - - StringBuilder log = new StringBuilder(); - - // Generate Request DTO - String reqContent = """ - package %s.dto; - - import com.fasterxml.jackson.annotation.JsonInclude; - import io.shinhanlife.dap.lib.annotation.McpParameter; - import io.shinhanlife.dap.lib.annotation.McpValidation; - import lombok.Data; - - /** - * @package %s.dto - * @className %sRequest - * @description AX HUB 시스템 처리 클래스 - * @author %s - * @create %s - *
-             * ---------- 개정이력 ----------
-             * 수정일      수정자    수정내용
-             * ---------- -------- ---------------------------
-             * %s  %s    최초생성
-             * 
-             * 
- */ - @Data - @JsonInclude(JsonInclude.Include.NON_NULL) - public class %sRequest { - @McpParameter(description = "수신자 전화번호", required = true) - @McpValidation(pattern = "^01(?:0|1|[6-9])-(?:\\\\d{3}|\\\\d{4})-\\\\d{4}$", examples = {"010-1234-5678"}) - private String phoneNumber; - - @McpParameter(description = "전송할 메시지 내용", required = true) - @McpValidation(defaultValue = "안녕하세요.") - private String message; - } - """.formatted(bizPackage, bizPackage, baseName, author, createDate, createDate, author, baseName); - Files.writeString(dtoDir.resolve(baseName + "Request.java"), reqContent); - - // Generate Response DTO - String resContent = """ - package %s.dto; - - import com.fasterxml.jackson.annotation.JsonInclude; - import io.shinhanlife.dap.lib.annotation.McpOutputSchema; - import io.shinhanlife.dap.lib.annotation.McpValidation; - import lombok.Data; - - /** - * @package %s.dto - * @className %sResponse - * @description AX HUB 시스템 처리 클래스 - * @author %s - * @create %s - *
-             * ---------- 개정이력 ----------
-             * 수정일      수정자    수정내용
-             * ---------- -------- ---------------------------
-             * %s  %s    최초생성
-             * 
-             * 
- */ - @Data - @McpOutputSchema - @JsonInclude(JsonInclude.Include.NON_NULL) - public class %sResponse { - @McpValidation(required = true) - private String resultCode; - - @McpValidation(maxLength = 200, nullable = true) - private String resultMessage; - - // TODO: Add response fields here. Do not include PII in the Tool response. - } - """.formatted(bizPackage, bizPackage, baseName, author, createDate, createDate, author, baseName); - Files.writeString(dtoDir.resolve(baseName + "Response.java"), resContent); - - String toolName = toToolName(moduleName, group, baseName); - - String serviceInterfaceContent = """ - package %s.usecase; - - import io.shinhanlife.dap.lib.annotation.McpFunction; - import io.shinhanlife.dap.lib.annotation.McpTool; - import %s.dto.%sRequest; - - @McpTool( - routingType = "%s", - categoryKey = "%s" - ) - public interface %sUseCase { - @McpFunction( - displayName = "%s 툴", - name = "%s", - description = "%s", - prompt = "%s", - mappingId = "%s", - register = %s, - requiresApproval = false, - openWorldHint = true, - version = "1.0.0", - timeoutMillis = 300000L, - enabled = true - ) - Object execute(%sRequest req); - } - """.formatted( - bizPackage, - bizPackage, baseName, - routingType, group.toLowerCase(), - baseName, - baseName, toolName, description, description + " ?줘.", interfaceId, register, - baseName - ); - - Files.writeString(usecaseDir.resolve(baseName + "UseCase.java"), serviceInterfaceContent); - - String serviceImplContent; - - if (isMci) { - serviceImplContent = """ - package %s.usecase.impl; - - import %s.dto.%sRequest; - import %s.dto.%sResponse; - import %s.usecase.%sUseCase; - import io.shinhanlife.dap.lib.integration.mci.component.AxhubMciComponent; - import io.shinhanlife.glow.communication.dto.Transfer; - import org.springframework.stereotype.Service; - import lombok.RequiredArgsConstructor; - import lombok.extern.slf4j.Slf4j; - import java.util.Map; - import %s.converter.%sConverter; - import %s.%s.io.%s_I; - %s - - /** - * @package %s.usecase.impl - * @className %sUseCaseImpl - * @description AX HUB 시스템 처리 클래스 - * @author %s - * @create %s - *
-                 * ---------- 개정이력 ----------
-                 * 수정일      수정자    수정내용
-                 * ---------- -------- ---------------------------
-                 * %s  %s    최초생성
-                 * 
-                 * 
- */ - @Slf4j - @Service - @RequiredArgsConstructor - public class %sUseCaseImpl implements %sUseCase { - - %s - private final %sConverter converter; - - @Override - public Object execute(%sRequest req) { - log.info("[MCI Tool] {} 요청 수신.", "%s"); - try { - // MapStruct를 이용한 자동 매핑 (AI DTO -> MCI DTO) - %s_I mciReq = converter.toLegacyRequest(req); - - Transfer resTransfer = mci.callTo( - "%s", - null, - mciReq, - Object.class - ); - return resTransfer.getBody() != null ? resTransfer.getBody() : Map.of("status", "SUCCESS"); - } catch (Exception e) { - log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e); - return Map.of("status", "ERROR", "message", e.getMessage() != null ? e.getMessage() : "Unknown error"); - } - } - } - """.formatted( - bizPackage, - bizPackage, baseName, - bizPackage, baseName, - bizPackage, baseName, - bizPackage, baseName, - BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId, - (clientPrefixCap.isEmpty() ? "" : "import " + BASE_PACKAGE + "." + mciGroupPath.replace("/", ".") + ".Mci" + clientPrefixCap + "Client;\n"), - bizPackage, - baseName, - author, - createDate, - createDate, author, - baseName, - baseName, - (clientPrefixCap.isEmpty() ? "private final AxhubMciComponent mci;" : "private final Mci" + clientPrefixCap + "Client mci;"), - baseName, - baseName, - toolName, - interfaceId, - interfaceId - ); - } else { - serviceImplContent = """ - package %s.usecase.impl; - - import %s.dto.%sRequest; - import %s.dto.%sResponse; - import %s.usecase.%sUseCase; - import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase; - import %s.converter.%sConverter; - import org.springframework.stereotype.Service; - import lombok.RequiredArgsConstructor; - import lombok.extern.slf4j.Slf4j; - - /** - * @package %s.usecase.impl - * @className %sUseCaseImpl - * @description AX HUB 시스템 처리 클래스 - * @author %s - * @create %s - *
-                 * ---------- 개정이력 ----------
-                 * 수정일      수정자    수정내용
-                 * ---------- -------- ---------------------------
-                 * %s  %s    최초생성
-                 * 
-                 * 
- */ - @Slf4j - @Service - @RequiredArgsConstructor - public class %sUseCaseImpl extends AbstractMcpToolUseCase implements %sUseCase { - - private final %sConverter converter; - - @Override - public Object execute(%sRequest req) { - // %sLegacyRequest legacyRequest = converter.toLegacyRequest(req); - return executeLegacy("%s", "%s", req); // Or pass legacyRequest - } - } - """.formatted( - bizPackage, - bizPackage, baseName, - bizPackage, baseName, - bizPackage, baseName, - bizPackage, baseName, - bizPackage, baseName, - author, - createDate, - createDate, author, - baseName, baseName, - baseName, - baseName, - baseName, - routingType, interfaceId - ); - } - - Files.writeString(usecaseImplDir.resolve(baseName + "UseCaseImpl.java"), serviceImplContent); - - if (isMci) { - String mciReqContent = """ - package %s.%s.io; - - import lombok.Data; - - /** - * @package %s.%s.io - * @className %s_I - * @description AX HUB 시스템 처리 클래스 - * @author %s - * @create %s - *
-                 * ---------- 개정이력 ----------
-                 * 수정일      수정자    수정내용
-                 * ---------- -------- ---------------------------
-                 * %s  %s    최초생성
-                 * 
-                 * 
- */ - @Data - public class %s_I { - /** - * EAI 시스템이 요구하는 수신자 번호 파라미터명 - */ - private String phone; - - /** - * EAI 시스템이 요구하는 메시지 내용 파라미터명 - */ - private String content; - } - """.formatted(BASE_PACKAGE, mciGroupPath.replace("/", "."), BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId, author, createDate, createDate, author, interfaceId); - Files.writeString(mciIoDir.resolve(interfaceId + "_I.java"), mciReqContent); - - String mciResContent = """ - package %s.%s.io; - - import lombok.Data; - - /** - * @package %s.%s.io - * @className %s_O - * @description AX HUB 시스템 처리 클래스 - * @author %s - * @create %s - *
-                 * ---------- 개정이력 ----------
-                 * 수정일      수정자    수정내용
-                 * ---------- -------- ---------------------------
-                 * %s  %s    최초생성
-                 * 
-                 * 
- */ - @Data - public class %s_O { - // TODO: Add response fields here - } - """.formatted(BASE_PACKAGE, mciGroupPath.replace("/", "."), BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId, author, createDate, createDate, author, interfaceId); - Files.writeString(mciIoDir.resolve(interfaceId + "_O.java"), mciResContent); - - String converterContent = """ - package %s.converter; - - import %s.dto.%sRequest; - import %s.dto.%sResponse; - import %s.%s.io.%s_I; - import %s.%s.io.%s_O; - import org.mapstruct.Mapper; - import org.mapstruct.Mapping; - import org.mapstruct.factory.Mappers; - - /** - * @package %s.converter - * @className %sConverter - * @description AX HUB 시스템 처리 클래스 - * @author %s - * @create %s - *
-                 * ---------- 개정이력 ----------
-                 * 수정일      수정자    수정내용
-                 * ---------- -------- ---------------------------
-                 * %s  %s    최초생성
-                 * 
-                 * 
- */ - @Mapper(componentModel = "spring") - public interface %sConverter { - - @Mapping(source = "phoneNumber", target = "phone") - @Mapping(source = "message", target = "content") - %s_I toLegacyRequest(%sRequest req); - - @Mapping(source = "phone", target = "phoneNumber") - @Mapping(source = "content", target = "message") - %sRequest toRequest(%s_I mciReq); - - // %sResponse toResponse(%s_O mciRes); - } - """.formatted( - bizPackage, - bizPackage, baseName, - bizPackage, baseName, - BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId, - BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId, - bizPackage, baseName, author, createDate, createDate, author, - baseName, interfaceId, baseName, - baseName, interfaceId, - baseName, interfaceId - ); - Files.writeString(converterDir.resolve(baseName + "Converter.java"), converterContent); - - log.append("\n=========================================\n"); - log.append(" Scaffolding Complete! (Routing: " + routingType + ")\n"); - log.append("=========================================\n"); - log.append("[Usecase Interface] ").append(usecaseDir.resolve(baseName + "UseCase.java")).append("\n"); - log.append("[Usecase Impl] ").append(usecaseImplDir.resolve(baseName + "UseCaseImpl.java")).append("\n"); - log.append("[Request DTO] ").append(dtoDir.resolve(baseName + "Request.java")).append("\n"); - log.append("[Response DTO] ").append(dtoDir.resolve(baseName + "Response.java")).append("\n"); - log.append("[MCI Request IO] ").append(mciIoDir.resolve(interfaceId + "_I.java")).append("\n"); - log.append("[MCI Response IO] ").append(mciIoDir.resolve(interfaceId + "_O.java")).append("\n"); - log.append("[MCI Converter] ").append(converterDir.resolve(baseName + "Converter.java")).append("\n"); - - if (!clientPrefixCap.isEmpty()) { - String mciClientContent = """ - package %s.%s; - - import org.springframework.stereotype.Component; - import lombok.RequiredArgsConstructor; - import io.shinhanlife.dap.lib.integration.mci.component.AxhubMciComponent; - import io.shinhanlife.glow.communication.dto.Transfer; - - /** - * @package %s.%s - * @className Mci%sClient - * @description AX HUB 시스템 처리 클래스 - * @author %s - * @create %s - *
-                     * ---------- 개정이력 ----------
-                     * 수정일      수정자    수정내용
-                     * ---------- -------- ---------------------------
-                     * %s  %s    최초생성
-                     * 
-                     * 
- */ - @Component - @RequiredArgsConstructor - public class Mci%sClient { - private final AxhubMciComponent mci; - - public Transfer callTo(String interfaceId, String dummy, Object mciReq, Class resType) throws Exception { - return mci.callTo(interfaceId, dummy, mciReq, resType); - } - } - """.formatted( - BASE_PACKAGE, mciGroupPath.replace("/", "."), - BASE_PACKAGE, mciGroupPath.replace("/", "."), clientPrefixCap, author, createDate, createDate, author, clientPrefixCap - ); - Files.writeString(mciClientDir.resolve("Mci" + clientPrefixCap + "Client.java"), mciClientContent); - log.append("[MCI Client] ").append(mciClientDir.resolve("Mci" + clientPrefixCap + "Client.java")).append("\n"); - } - - } else { - String legacyReqContent = """ - package %s.legacy; - - import lombok.Data; - - /** - * @package %s.legacy - * @className %sLegacyRequest - * @description AX HUB 시스템 처리 클래스 - * @author %s - * @create %s - *
-                 * ---------- 개정이력 ----------
-                 * 수정일      수정자    수정내용
-                 * ---------- -------- ---------------------------
-                 * %s  %s    최초생성
-                 * 
-                 * 
- */ - @Data - public class %sLegacyRequest { - /** - * EAI 시스템이 요구하는 수신자 번호 파라미터명 - */ - private String phone; - - /** - * EAI 시스템이 요구하는 메시지 내용 파라미터명 - */ - private String content; - } - """.formatted(bizPackage, bizPackage, baseName, author, createDate, createDate, author, baseName); - Files.writeString(legacyDtoDir.resolve(baseName + "LegacyRequest.java"), legacyReqContent); - - String legacyResContent = """ - package %s.legacy; - - import lombok.Data; - - /** - * @package %s.legacy - * @className %sLegacyResponse - * @description AX HUB 시스템 처리 클래스 - * @author %s - * @create %s - *
-                 * ---------- 개정이력 ----------
-                 * 수정일      수정자    수정내용
-                 * ---------- -------- ---------------------------
-                 * %s  %s    최초생성
-                 * 
-                 * 
- */ - @Data - public class %sLegacyResponse { - // TODO: Add legacy response fields here - } - """.formatted(bizPackage, bizPackage, baseName, author, createDate, createDate, author, baseName); - Files.writeString(legacyDtoDir.resolve(baseName + "LegacyResponse.java"), legacyResContent); - - String converterContent = """ - package %s.converter; - - import %s.dto.%sRequest; - import %s.dto.%sResponse; - import %s.legacy.%sLegacyRequest; - import %s.legacy.%sLegacyResponse; - import org.mapstruct.Mapper; - import org.mapstruct.Mapping; - import org.mapstruct.factory.Mappers; - - /** - * @package %s.converter - * @className %sConverter - * @description AX HUB 시스템 처리 클래스 - * @author %s - * @create %s - *
-                 * ---------- 개정이력 ----------
-                 * 수정일      수정자    수정내용
-                 * ---------- -------- ---------------------------
-                 * %s  %s    최초생성
-                 * 
-                 * 
- */ - @Mapper(componentModel = "spring") - public interface %sConverter { - - @Mapping(source = "phoneNumber", target = "phone") - @Mapping(source = "message", target = "content") - %sLegacyRequest toLegacyRequest(%sRequest req); - - @Mapping(source = "phone", target = "phoneNumber") - @Mapping(source = "content", target = "message") - %sRequest toRequest(%sLegacyRequest legacyRequest); - - // %sResponse toResponse(%sLegacyResponse legacyResponse); - } - """.formatted( - bizPackage, - bizPackage, baseName, - bizPackage, baseName, - bizPackage, baseName, - bizPackage, baseName, - bizPackage, baseName, author, createDate, createDate, author, - baseName, baseName, baseName, baseName, baseName, baseName, baseName - ); - Files.writeString(converterDir.resolve(baseName + "Converter.java"), converterContent); - - log.append("\n=========================================\n"); - log.append(" Scaffolding Complete! (Routing: " + routingType + ")\n"); - log.append("=========================================\n"); - log.append("[Usecase Interface] ").append(usecaseDir.resolve(baseName + "UseCase.java")).append("\n"); - log.append("[Usecase Impl] ").append(usecaseImplDir.resolve(baseName + "UseCaseImpl.java")).append("\n"); - log.append("[Request DTO] ").append(dtoDir.resolve(baseName + "Request.java")).append("\n"); - log.append("[Response DTO] ").append(dtoDir.resolve(baseName + "Response.java")).append("\n"); - log.append("[Legacy Request DTO] ").append(legacyDtoDir.resolve(baseName + "LegacyRequest.java")).append("\n"); - log.append("[Legacy Response DTO] ").append(legacyDtoDir.resolve(baseName + "LegacyResponse.java")).append("\n"); - log.append("[Legacy Converter] ").append(converterDir.resolve(baseName + "Converter.java")).append("\n"); - } - log.append("\n Tip: ").append(interfaceId).append(" 목업 데이터를 mock-responses.json에 추가하세요.\n"); - - return log.toString(); - } - - private static String toToolName(String moduleName, String group, String baseName) { - String pod = moduleName.startsWith("dap-was-") - ? moduleName.substring("dap-was-".length()) - : "oth"; - String normalizedName = baseName.replaceAll("([a-z0-9])([A-Z])", "$1 $2") - .toLowerCase(Locale.ROOT) - .replaceAll("[^a-z0-9]+", " ") - .trim(); - String[] words = normalizedName.split("\\s+"); - String service = words[0]; - String action = words.length == 1 ? "execute" : words[words.length - 1]; - return "%s.%s.%s.%s".formatted( - pod.toLowerCase(Locale.ROOT), - group.toLowerCase(Locale.ROOT), - service, - action); - } - - private static String toPascalCase(String str) { - if (str == null || str.isEmpty()) { - return str; - } - StringBuilder result = new StringBuilder(); - boolean capitalizeNext = true; - for (char c : str.toCharArray()) { - if (c == '_' || c == '-' || c == ' ') { - capitalizeNext = true; - } else if (capitalizeNext) { - result.append(Character.toUpperCase(c)); - capitalizeNext = false; - } else { - result.append(c); - } - } - if (result.length() > 0) { - result.setCharAt(0, Character.toUpperCase(result.charAt(0))); - } - return result.toString(); - } -} \ No newline at end of file diff --git a/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/ToolScaffolderTest.java b/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/ToolScaffolderTest.java deleted file mode 100644 index f80f5011d..000000000 --- a/dap-was-lib/src/test/java/io/shinhanlife/dap/lib/util/ToolScaffolderTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.shinhanlife.dap.lib.util; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.nio.file.Files; -import java.nio.file.Path; -import org.junit.jupiter.api.Test; - -class ToolScaffolderTest { - - @Test - void generatesManifestReadyToolAndOutputSchemaDto() throws Exception { - String moduleName = "build/scaffold-manifest-test"; - - ToolScaffolder.scaffold("claim search", "CLM0001", "청구 조회", "cmm", "HTTP", moduleName, - "tester", "2026.08.04", true, null); - - Path root = Path.of(moduleName, "src/main/java/io/shinhanlife/dap/mcc/biz/cmm"); - String useCase = Files.readString(root.resolve("usecase/ClaimSearchUseCase.java")); - String response = Files.readString(root.resolve("dto/ClaimSearchResponse.java")); - - assertTrue(useCase.contains("name = \"oth.cmm.claim.search\"")); - assertTrue(useCase.contains("version = \"1.0.0\"")); - assertTrue(useCase.contains("timeoutMillis = 300000L")); - assertTrue(response.contains("@McpOutputSchema")); - assertTrue(response.contains("@McpValidation")); - } -}