diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java index a9d2282f..c937a25e 100644 --- a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java @@ -736,13 +736,35 @@ public class ToolScaffolder { String outputSchemaResource, List inputFields, List outputFields, String httpApiName, ToolDefinitionOptions definitionOptions) throws IOException { - baseName = toPascalCase(baseName); - title = title == null || title.isBlank() ? baseName : title.trim(); + return scaffoldWithAbbreviatedMciSources(baseName, interfaceId, title, description, group, routingType, + moduleName, author, createDate, register, clientSystemCode, inputSchemaResource, + outputSchemaResource, inputFields, outputFields, httpApiName, definitionOptions); + } + + /** + * Generates MCI source files from an abbreviation derived from the Base Name. The Base Name remains the MCP Tool name. + */ + private static String scaffoldWithAbbreviatedMciSources(String baseName, String interfaceId, String title, + String description, String group, String routingType, + String moduleName, String author, String createDate, + boolean register, String clientSystemCode, + String inputSchemaResource, String outputSchemaResource, + List inputFields, + List outputFields, String httpApiName, + ToolDefinitionOptions definitionOptions) throws IOException { + boolean isMci = "MCI".equalsIgnoreCase(routingType); + boolean isHttp = "HTTP".equalsIgnoreCase(routingType); + if (!isMci && !isHttp) { + throw new IllegalArgumentException("Unsupported routing type: " + routingType + ". Only MCI and HTTP are supported."); + } + String toolBaseName = toPascalCase(baseName); + baseName = isMci ? abbreviatedMciSourceBaseName(toolBaseName) : toolBaseName; + title = title == null || title.isBlank() ? toolBaseName : title.trim(); description = description == null ? "" : description.trim(); definitionOptions = definitionOptions == null ? new ToolDefinitionOptions(null, null, null, null, null, List.of(), List.of(), null) : definitionOptions; - httpApiName = httpApiName == null || httpApiName.isBlank() ? toKebabCase(baseName) : httpApiName.trim(); + httpApiName = httpApiName == null || httpApiName.isBlank() ? toKebabCase(toolBaseName) : httpApiName.trim(); String envSourceDir = System.getProperty("AXHUB_SOURCE_DIR"); if (envSourceDir == null) { envSourceDir = System.getenv("AXHUB_SOURCE_DIR"); @@ -754,11 +776,10 @@ public class ToolScaffolder { 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")); // Schema Resource 파일 경로(useSchemaResource=true일 때만 생성) boolean useSchemaResource = (inputSchemaResource != null && !inputSchemaResource.trim().isEmpty()) || (outputSchemaResource != null && !outputSchemaResource.trim().isEmpty()); - String schemaBaseName = toKebabCase(baseName); + String schemaBaseName = toKebabCase(toolBaseName); String inputSchemaFileName = schemaBaseName + "-resource-input-schema.json"; String outputSchemaFileName = schemaBaseName + "-resource-output-schema.json"; Path schemaDir = rootDir.resolve(Paths.get(moduleName, "src/main/resources/tool-schemas", group.toLowerCase())); @@ -767,11 +788,6 @@ public class ToolScaffolder { String outputSchemaClasspath = "classpath:tool-schemas/" + group.toLowerCase() + "/" + outputSchemaFileName; String bizPackage = BASE_PACKAGE + ".biz." + group.toLowerCase(); - boolean isMci = "MCI".equalsIgnoreCase(routingType); - boolean isHttp = "HTTP".equalsIgnoreCase(routingType); - if (!isMci && !isHttp) { - throw new IllegalArgumentException("Unsupported routing type: " + routingType + ". Only MCI and HTTP are supported."); - } String ioPrefix = (clientSystemCode != null && !clientSystemCode.isBlank()) ? clientSystemCode.toUpperCase() : interfaceId; String mciGroupPath = "infra/itrf/mci/" + group.toLowerCase(); String clientPrefixCap = ""; @@ -784,6 +800,18 @@ public class ToolScaffolder { mciClientDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, mciGroupPath)); } + String converterPackage = bizPackage + ".converter"; + String targetSystemPackage = isMci ? mciTargetSystemPackage(clientSystemCode) : null; + if (targetSystemPackage != null) { + converterPackage += "." + targetSystemPackage; + } + Path converterDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, "biz", group.toLowerCase(), "converter")); + if (targetSystemPackage != null) { + for (String segment : targetSystemPackage.split("\\.")) { + converterDir = converterDir.resolve(segment); + } + } + Path mciIoDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, mciGroupPath, "io")); String httpApiPackage = toPackageSegment(httpApiName); String httpApiClass = toPascalCase(httpApiName); @@ -886,9 +914,9 @@ public class ToolScaffolder { writeUtf8(dtoDir.resolve(baseName + "Response.java"), resContent); writeStructuredFieldTypes(dtoDir, bizPackage + ".dto", baseName + "Response", outputFields); - String toolName = toToolName(moduleName, group, baseName); + String toolName = toToolName(moduleName, group, toolBaseName); - boolean isMutation = isMutationTool(baseName); + boolean isMutation = isMutationTool(toolBaseName); StringBuilder sb = new StringBuilder(" @GrowToolHint(\n"); if (useSchemaResource) { sb.append(" inputSchemaResource = \"").append(inputSchemaClasspath).append("\",\n"); @@ -988,7 +1016,7 @@ public class ToolScaffolder { import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; - import %s.converter.%sConverter; + import %s.%sConverter; import %s.%s.io.%s_I; import %s.%s.io.%s_O; %s @@ -1062,7 +1090,7 @@ public class ToolScaffolder { bizPackage, baseName, bizPackage, baseName, bizPackage, baseName, - bizPackage, baseName, + converterPackage, baseName, BASE_PACKAGE, mciGroupPath.replace("/", "."), ioPrefix, BASE_PACKAGE, mciGroupPath.replace("/", "."), ioPrefix, (clientPrefixCap.isEmpty() ? "" : "import " + BASE_PACKAGE + "." + mciGroupPath.replace("/", ".") + ".Mci" + clientPrefixCap + "Client;\n"), @@ -1279,7 +1307,7 @@ public class ToolScaffolder { baseName, ioPrefix, baseName, ioPrefix ); - converterContent = mciConverterContent(bizPackage, baseName, mciGroupPath.replace("/", "."), ioPrefix); + converterContent = mciConverterContent(converterPackage, bizPackage, baseName, mciGroupPath.replace("/", "."), ioPrefix); writeUtf8(converterDir.resolve(baseName + "Converter.java"), converterContent); log.append("\n=========================================\n"); @@ -2140,9 +2168,10 @@ public class ToolScaffolder { .replaceAll("^_+|_+$", ""); return normalized.isBlank() ? "http_api" : normalized; } - private static String mciConverterContent(String bizPackage, String baseName, String mciPackage, String interfaceId) { + private static String mciConverterContent(String converterPackage, String bizPackage, String baseName, + String mciPackage, String interfaceId) { return """ - package %s.converter; + package %s; import %s.dto.%sRequest; import %s.dto.%sResponse; @@ -2160,11 +2189,19 @@ public class ToolScaffolder { %sRequest toRequest(%s_I mciRequest); %sResponse toResponse(%s_O mciRes); } - """.formatted(bizPackage, bizPackage, baseName, bizPackage, baseName, + """.formatted(converterPackage, bizPackage, baseName, bizPackage, baseName, BASE_PACKAGE, mciPackage, interfaceId, BASE_PACKAGE, mciPackage, interfaceId, baseName, interfaceId, baseName, baseName, interfaceId, baseName, interfaceId); } + private static String mciTargetSystemPackage(String clientSystemCode) { + if (clientSystemCode == null || clientSystemCode.length() != 9) { + return null; + } + String prefix = clientSystemCode.substring(1, 5).toLowerCase(Locale.ROOT); + return prefix.substring(0, 3) + "." + prefix.substring(3); + } + private static String legacyConverterContent(String bizPackage, String baseName) { return """ package %s.converter; @@ -2364,6 +2401,19 @@ public class ToolScaffolder { action); } + private static String abbreviatedMciSourceBaseName(String baseName) { + String[] words = baseName.split("(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])"); + if (words.length < 3) { + return baseName; + } + return abbreviatedWord(words[0], 4) + abbreviatedWord(words[1], 6); + } + + private static String abbreviatedWord(String word, int maximumLength) { + int length = Math.min(word.length(), maximumLength); + return toPascalCase(word.substring(0, length).toLowerCase(Locale.ROOT)); + } + private static String toPascalCase(String str) { if (str == null || str.isEmpty()) { return str; diff --git a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/ToolScaffolderTest.java b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/ToolScaffolderTest.java index 5a636105..872f8f5b 100644 --- a/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/ToolScaffolderTest.java +++ b/dat-was-lib/src/test/java/io/shinhanlife/dat/lib/util/ToolScaffolderTest.java @@ -539,4 +539,29 @@ class ToolScaffolderTest { assertTrue(implementation.contains("setResultCode(\"ERROR\")"), implementation); assertFalse(implementation.contains("LCHITP00001\", null, request, ONCSG1341_O.class).getBody()"), implementation); } + + @Test + void generatesAbbreviatedMciSourcesAndTargetSystemConverterPackage() throws Exception { + String moduleName = root.resolve("dat-was-pro").toString(); + + ToolScaffolder.scaffold("individual customer detail inquiry", "LCHITP00001", + "개인 고객 상세 조회", "개인 고객 상세 정보를 조회합니다.", + "pro", "MCI", moduleName, "tester", "2026.09.10", false, + "ONBTA2380", null, null, List.of(), List.of(), null, null); + + Path sourceRoot = root.resolve("dat-was-pro/src/main/java/io/shinhanlife/dat/mcc/biz/pro"); + Path converter = sourceRoot.resolve("converter/nbt/a/IndiCustomConverter.java"); + assertTrue(Files.exists(converter)); + assertTrue(Files.exists(sourceRoot.resolve("dto/IndiCustomRequest.java"))); + assertTrue(Files.exists(sourceRoot.resolve("dto/IndiCustomResponse.java"))); + assertTrue(Files.exists(sourceRoot.resolve("usecase/IndiCustomUseCase.java"))); + assertTrue(Files.exists(sourceRoot.resolve("usecase/impl/IndiCustomUseCaseImpl.java"))); + + String converterSource = Files.readString(converter); + String useCaseSource = Files.readString(sourceRoot.resolve("usecase/IndiCustomUseCase.java")); + String implementationSource = Files.readString(sourceRoot.resolve("usecase/impl/IndiCustomUseCaseImpl.java")); + assertTrue(converterSource.contains("package io.shinhanlife.dat.mcc.biz.pro.converter.nbt.a;"), converterSource); + assertTrue(implementationSource.contains("import io.shinhanlife.dat.mcc.biz.pro.converter.nbt.a.IndiCustomConverter;"), implementationSource); + assertTrue(useCaseSource.contains("name = \"pro_individual_inquiry\""), useCaseSource); + } }