refactor: remove sample HTTP tool integration
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
Some checks failed
Deploy to OCIWP / deploy (push) Has been cancelled
This commit is contained in:
@@ -90,7 +90,7 @@ public class ScaffoldingController {
|
||||
if (date == null || date.trim().isEmpty()) date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd"));
|
||||
boolean register = Boolean.parseBoolean(req.getOrDefault("register", "true"));
|
||||
String clientSystemCode = req.get("clientSystemCode");
|
||||
String httpApiName = req.getOrDefault("httpApiName", "sample");
|
||||
String httpApiName = req.get("httpApiName");
|
||||
String inputSchemaResource = req.get("inputSchemaResource");
|
||||
String outputSchemaResource = req.get("outputSchemaResource");
|
||||
List<ToolScaffolder.FieldDefinition> inputFields = parseFields(req.get("inputFields"));
|
||||
@@ -259,7 +259,7 @@ public class ScaffoldingController {
|
||||
if (!Set.of("HTTP", "MCI").contains(routingType)) {
|
||||
throw new IllegalArgumentException("AI가 지원하지 않는 Protocol을 생성했습니다.");
|
||||
}
|
||||
String httpApiName = draft.httpApiName() == null ? "sample" : draft.httpApiName().trim();
|
||||
String httpApiName = draft.httpApiName() == null ? "http-api" : draft.httpApiName().trim();
|
||||
if (!httpApiName.matches("^[A-Za-z0-9_-]+$")) {
|
||||
throw new IllegalArgumentException("AI가 올바르지 않은 HTTP API Name을 생성했습니다.");
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ mcp:
|
||||
fallback:
|
||||
default-url: http://localhost:8084
|
||||
routes:
|
||||
cmm_memo_retriever: http://localhost:8082
|
||||
sms: http://localhost:8082
|
||||
email: http://localhost:8083
|
||||
payment: http://localhost:8085
|
||||
|
||||
@@ -568,7 +568,7 @@
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">HTTP API Name (Glow api-list)</label>
|
||||
<input type="text" class="form-control" name="httpApiName" value="sample" pattern="^[a-zA-Z0-9_-]+$" placeholder="e.g. employee">
|
||||
<input type="text" class="form-control" name="httpApiName" pattern="^[a-zA-Z0-9_-]+$" placeholder="비우면 Tool 이름으로 자동 생성">
|
||||
<div class="input-hint">HTTP only. Must match glow.communication.http.api-list[].name; URL and method are read from Glow YAML.</div>
|
||||
</div>
|
||||
<div class="col-md-6 mt-3 mt-md-0">
|
||||
@@ -1053,7 +1053,7 @@
|
||||
form.elements.description.value = result.description || '';
|
||||
form.elements.categoryKey.value = result.categoryKey || '';
|
||||
form.elements.routingType.value = result.routingType || 'HTTP';
|
||||
form.elements.httpApiName.value = result.httpApiName || 'sample';
|
||||
form.elements.httpApiName.value = result.httpApiName || '';
|
||||
document.getElementById('inputFields').value = JSON.stringify(result.inputFields || [], null, 2);
|
||||
document.getElementById('outputFields').value = JSON.stringify(result.outputFields || [], null, 2);
|
||||
alert('Tool 초안을 채웠습니다. Legacy Interface ID와 Client System Code는 실제 연계 명세를 확인해 입력해주세요.');
|
||||
|
||||
@@ -47,16 +47,6 @@ public class AxhubHttpComponent {
|
||||
return execute(api, uri, inputDto, responseBodyClass, timeout);
|
||||
}
|
||||
|
||||
/** Backward-compatible enum overload. */
|
||||
public <T, R> R call(AxhubHttpDomain domain, String uri, T inputDto, Class<R> responseBodyClass) {
|
||||
return call(domain.getCode(), uri, inputDto, responseBodyClass, 0);
|
||||
}
|
||||
|
||||
/** Backward-compatible enum overload. */
|
||||
public <T, R> R call(AxhubHttpDomain domain, String uri, T inputDto, Class<R> responseBodyClass, int timeout) {
|
||||
return call(domain.getCode(), uri, inputDto, responseBodyClass, timeout);
|
||||
}
|
||||
|
||||
/** Calls the configured URL only when the target is marked as a business Pod. */
|
||||
public <T, R> R callBizPod(String apiName, T inputDto, Class<R> responseBodyClass) {
|
||||
AxhubHttpProperties.ApiDefinition api = resolveApi(apiName);
|
||||
@@ -66,15 +56,6 @@ public class AxhubHttpComponent {
|
||||
return execute(api, "", inputDto, responseBodyClass, 0);
|
||||
}
|
||||
|
||||
/** Backward-compatible enum overload. */
|
||||
public <T, R> R callBizPod(AxhubHttpDomain domain, String uri, T inputDto, Class<R> responseBodyClass) {
|
||||
AxhubHttpProperties.ApiDefinition api = resolveApi(domain.getCode());
|
||||
if (!api.bizPod()) {
|
||||
throw new IllegalArgumentException("Configured API is not a business Pod: " + domain.getCode());
|
||||
}
|
||||
return execute(api, uri, inputDto, responseBodyClass, 0);
|
||||
}
|
||||
|
||||
private <T, R> R execute(AxhubHttpProperties.ApiDefinition api, String uri, T inputDto,
|
||||
Class<R> responseBodyClass, int timeout) {
|
||||
HttpHeader header = createHeader(api, timeout);
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package io.shinhanlife.dap.lib.integration.http.component;
|
||||
|
||||
/** Registered outbound HTTP API domains. Add a domain only after its endpoint is configured. */
|
||||
public enum AxhubHttpDomain {
|
||||
SAMPLE("sample");
|
||||
|
||||
private final String code;
|
||||
|
||||
AxhubHttpDomain(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,8 @@ public class ToolScaffolder {
|
||||
*/
|
||||
public static String scaffold(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<FieldDefinition> inputFields, List<FieldDefinition> outputFields) throws IOException {
|
||||
return scaffold(baseName, interfaceId, title, description, group, routingType, moduleName, author, createDate,
|
||||
register, clientSystemCode, inputSchemaResource, outputSchemaResource, inputFields, outputFields, "sample");
|
||||
register, clientSystemCode, inputSchemaResource, outputSchemaResource, inputFields, outputFields,
|
||||
toKebabCase(toPascalCase(baseName)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,7 +128,7 @@ public class ToolScaffolder {
|
||||
baseName = toPascalCase(baseName);
|
||||
title = title == null || title.isBlank() ? baseName : title.trim();
|
||||
description = description == null ? "" : description.trim();
|
||||
httpApiName = httpApiName == null || httpApiName.isBlank() ? "sample" : httpApiName.trim();
|
||||
httpApiName = httpApiName == null || httpApiName.isBlank() ? toKebabCase(baseName) : httpApiName.trim();
|
||||
String envSourceDir = System.getenv("AXHUB_SOURCE_DIR");
|
||||
Path rootDir = envSourceDir != null ? Paths.get(envSourceDir) : Paths.get(".");
|
||||
|
||||
@@ -860,7 +861,7 @@ public class ToolScaffolder {
|
||||
Files.writeString(wireMockBodyPath, mockResponse);
|
||||
Files.writeString(wireMockMappingPath, wireMockMappingContent(interfaceId, wireMockBodyPath.getFileName().toString()));
|
||||
Files.writeString(podMockResponsePath, mockResponse);
|
||||
ensureLocalHttpApiConfiguration(moduleRoot, httpApiName, toolName);
|
||||
ensureLocalHttpApiConfiguration(projectRoot, httpApiName, toolName);
|
||||
log.append("[WireMock Response] ").append(wireMockBodyPath).append("\n");
|
||||
log.append("[WireMock Mapping] ").append(wireMockMappingPath).append("\n");
|
||||
log.append("[Pod Mock Response] ").append(podMockResponsePath).append("\n");
|
||||
@@ -889,8 +890,8 @@ public class ToolScaffolder {
|
||||
.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
private static void ensureLocalHttpApiConfiguration(Path moduleRoot, String httpApiName, String toolName) throws IOException {
|
||||
Path localConfigPath = moduleRoot.resolve("src/main/resources/application-local.yml");
|
||||
private static void ensureLocalHttpApiConfiguration(Path projectRoot, String httpApiName, String toolName) throws IOException {
|
||||
Path localConfigPath = projectRoot.resolve("dap-was-lib/src/main/resources/glow/application-glow-local.yml");
|
||||
Files.createDirectories(localConfigPath.getParent());
|
||||
String existing = Files.exists(localConfigPath) ? Files.readString(localConfigPath) : "";
|
||||
if (java.util.regex.Pattern.compile("(?m)^\\s*-\\s+name:\\s*"
|
||||
@@ -898,17 +899,7 @@ public class ToolScaffolder {
|
||||
return;
|
||||
}
|
||||
String environmentKey = toPackageSegment(httpApiName).toUpperCase(Locale.ROOT).replace('-', '_');
|
||||
String config = """
|
||||
|
||||
axhub:
|
||||
mock:
|
||||
http:
|
||||
enabled: true
|
||||
|
||||
glow:
|
||||
communication:
|
||||
http:
|
||||
api-list:
|
||||
String apiEntry = """
|
||||
- name: %s
|
||||
domain: ${AXHUB_%s_HTTP_DOMAIN:http://localhost:${server.port}}
|
||||
url: ${AXHUB_%s_HTTP_URL:/api/mock/http/%s}
|
||||
@@ -916,7 +907,37 @@ public class ToolScaffolder {
|
||||
content-type: application/json;charset=UTF-8
|
||||
biz-pod: false
|
||||
""".formatted(httpApiName, environmentKey, environmentKey, toolName);
|
||||
Files.writeString(localConfigPath, existing + config);
|
||||
if (existing.isBlank()) {
|
||||
existing = """
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: local
|
||||
|
||||
glow:
|
||||
communication:
|
||||
http:
|
||||
api-list:
|
||||
""" + apiEntry;
|
||||
} else if (existing.contains("\n mci:")) {
|
||||
existing = existing.replace("\n mci:", apiEntry + " mci:");
|
||||
} else if (existing.contains("\naxhub:")) {
|
||||
existing = existing.replace("\naxhub:", apiEntry + "axhub:");
|
||||
} else if (existing.contains("api-list:")) {
|
||||
existing += apiEntry;
|
||||
} else {
|
||||
throw new IllegalStateException("application-glow-local.yml must define glow.communication.http.api-list");
|
||||
}
|
||||
if (!existing.contains("axhub:\n mock:\n http:\n enabled: true")) {
|
||||
existing += """
|
||||
|
||||
axhub:
|
||||
mock:
|
||||
http:
|
||||
enabled: true
|
||||
""";
|
||||
}
|
||||
Files.writeString(localConfigPath, existing);
|
||||
}
|
||||
|
||||
private static String dtoContent(String packageName, String className, List<FieldDefinition> fields,
|
||||
@@ -1059,7 +1080,7 @@ public class ToolScaffolder {
|
||||
String normalized = value == null ? "" : value.toLowerCase(Locale.ROOT)
|
||||
.replaceAll("[^a-z0-9]+", "_")
|
||||
.replaceAll("^_+|_+$", "");
|
||||
return normalized.isBlank() ? "sample" : normalized;
|
||||
return normalized.isBlank() ? "http_api" : normalized;
|
||||
}
|
||||
private static String mciConverterContent(String bizPackage, String baseName, String mciPackage, String interfaceId) {
|
||||
return """
|
||||
|
||||
@@ -13,9 +13,9 @@ glow:
|
||||
connection-timeout: 5
|
||||
read-timeout: 5
|
||||
api-list:
|
||||
- name: sample
|
||||
domain: ${AXHUB_SAMPLE_HTTP_DOMAIN:http://localhost:8089}
|
||||
url: ${AXHUB_SAMPLE_HTTP_URL:/CLCNNB00001}
|
||||
- name: memo
|
||||
domain: ${AXHUB_MEMO_HTTP_DOMAIN:http://localhost:${server.port}}
|
||||
url: ${AXHUB_MEMO_HTTP_URL:/api/mock/http/cmm_memo_retriever}
|
||||
method: POST
|
||||
content-type: application/json;charset=UTF-8
|
||||
biz-pod: false
|
||||
@@ -28,3 +28,8 @@ glow:
|
||||
eai:
|
||||
host: ${GLOW_COMMUNICATION_EAI_HOST:http://localhost}
|
||||
port: ${GLOW_COMMUNICATION_EAI_PORT:8080}
|
||||
|
||||
axhub:
|
||||
mock:
|
||||
http:
|
||||
enabled: true
|
||||
|
||||
@@ -21,18 +21,8 @@ glow:
|
||||
http:
|
||||
connection-timeout: 5
|
||||
read-timeout: 5
|
||||
# HTTP Tool target catalog. Replace or add entries after the business endpoint is agreed.
|
||||
api-list:
|
||||
# WireMock/개발환경 샘플입니다. 컨테이너 내부에서는 localhost가 Tool Pod 자신을 뜻하므로
|
||||
# Docker 서비스명(mci-mock)과 컨테이너 포트(8080)를 기본값으로 사용합니다.
|
||||
# 로컬 PC에서 실행할 때는 AXHUB_SAMPLE_HTTP_DOMAIN=http://localhost:8089 로 덮어씁니다.
|
||||
- name: sample
|
||||
domain: ${AXHUB_SAMPLE_HTTP_DOMAIN:http://mci-mock:8080}
|
||||
# mci-mock/mappings/smp_employee_search.json의 urlPath와 동일해야 합니다.
|
||||
url: ${AXHUB_SAMPLE_HTTP_URL:/CLCNNB00001}
|
||||
method: POST
|
||||
content-type: application/json;charset=UTF-8
|
||||
biz-pod: false
|
||||
# HTTP Tool target catalog. Scaffold adds local mock entries after a Tool is created.
|
||||
api-list: []
|
||||
mci:
|
||||
uri: /ntl_mci/dap_rcv
|
||||
receive-uri: /itrf/mciReceive
|
||||
|
||||
@@ -19,13 +19,13 @@ import org.springframework.web.client.RestClient;
|
||||
class AxhubHttpComponentTest {
|
||||
|
||||
@Test
|
||||
void callResolvesDomainBuildsGlowTransferAndDeserializesJsonResponse() {
|
||||
void callByApiNameBuildsGlowTransferAndDeserializesJsonResponse() {
|
||||
RestClient.Builder builder = RestClient.builder();
|
||||
MockRestServiceServer server = MockRestServiceServer.bindTo(builder).build();
|
||||
GlowHttpComponent glowHttpComponent = new GlowHttpComponent(builder);
|
||||
AxhubHttpProperties properties = new AxhubHttpProperties();
|
||||
properties.setApiList(List.of(new AxhubHttpProperties.ApiDefinition(
|
||||
"sample", "https://api.example.test", "/v1", HttpMethod.GET, "application/json", false)));
|
||||
"status", "https://api.example.test", "/v1", HttpMethod.GET, "application/json", false)));
|
||||
AxhubHttpComponent component = new AxhubHttpComponent(
|
||||
glowHttpComponent, new ObjectMapper(), new GlowCommunicationProperties(), properties);
|
||||
|
||||
@@ -33,7 +33,7 @@ class AxhubHttpComponentTest {
|
||||
.andExpect(header("X-ANONYMOUS-REQ", "AXHUB-TOOL"))
|
||||
.andRespond(withSuccess("{\"status\":\"OK\"}", APPLICATION_JSON));
|
||||
|
||||
SampleResponse response = component.call(AxhubHttpDomain.SAMPLE, "/status", null, SampleResponse.class);
|
||||
SampleResponse response = component.call("status", "/status", null, SampleResponse.class);
|
||||
|
||||
assertThat(response.status()).isEqualTo("OK");
|
||||
server.verify();
|
||||
|
||||
@@ -162,11 +162,11 @@ class ToolScaffolderTest {
|
||||
assertTrue(response.indexOf("private String resultCode;") == response.lastIndexOf("private String resultCode;"), response);
|
||||
assertTrue(response.indexOf("private String employeeName;") == response.lastIndexOf("private String employeeName;"), response);
|
||||
String converter = Files.readString(root.resolve("dap-was-http/src/main/java/io/shinhanlife/dap/mcc/biz/smp/converter/EmployeeSearchConverter.java"));
|
||||
String httpRequest = Files.readString(root.resolve("dap-was-http/src/main/java/io/shinhanlife/dap/mcc/infra/itrf/http/sample/io/EmployeeSearchHttpRequest.java"));
|
||||
String httpResponse = Files.readString(root.resolve("dap-was-http/src/main/java/io/shinhanlife/dap/mcc/infra/itrf/http/sample/io/EmployeeSearchHttpResponse.java"));
|
||||
String httpClient = Files.readString(root.resolve("dap-was-http/src/main/java/io/shinhanlife/dap/mcc/infra/itrf/http/sample/SampleClient.java"));
|
||||
String httpRequest = Files.readString(root.resolve("dap-was-http/src/main/java/io/shinhanlife/dap/mcc/infra/itrf/http/employee_search/io/EmployeeSearchHttpRequest.java"));
|
||||
String httpResponse = Files.readString(root.resolve("dap-was-http/src/main/java/io/shinhanlife/dap/mcc/infra/itrf/http/employee_search/io/EmployeeSearchHttpResponse.java"));
|
||||
String httpClient = Files.readString(root.resolve("dap-was-http/src/main/java/io/shinhanlife/dap/mcc/infra/itrf/http/employee_search/EmployeeSearchClient.java"));
|
||||
assertFalse(converter.contains("phoneNumber"), converter);
|
||||
assertTrue(converter.contains("infra.itrf.http.sample.io.EmployeeSearchHttpRequest"), converter);
|
||||
assertTrue(converter.contains("infra.itrf.http.employee_search.io.EmployeeSearchHttpRequest"), converter);
|
||||
assertFalse(converter.contains("io.shinhanlife.dap.mcc.io.shinhanlife.dap.mcc"), converter);
|
||||
assertTrue(converter.contains("// @Mapping(source = \"sourceField\", target = \"targetField\")"), converter);
|
||||
assertTrue(httpRequest.contains("private String employeeId;"), httpRequest);
|
||||
@@ -175,9 +175,9 @@ class ToolScaffolderTest {
|
||||
assertFalse(Files.exists(root.resolve("dap-was-http/src/main/java/io/shinhanlife/dap/mcc/biz/smp/legacy")));
|
||||
String implementation = Files.readString(root.resolve("dap-was-http/src/main/java/io/shinhanlife/dap/mcc/biz/smp/usecase/impl/EmployeeSearchUseCaseImpl.java"));
|
||||
assertTrue(implementation.contains("public EmployeeSearchResponse execute(EmployeeSearchRequest req)"), implementation);
|
||||
assertTrue(implementation.contains("import io.shinhanlife.dap.mcc.infra.itrf.http.sample.SampleClient;"), implementation);
|
||||
assertTrue(implementation.contains("private final SampleClient sampleClient;"), implementation);
|
||||
assertTrue(implementation.contains("sampleClient.call(httpRequest, EmployeeSearchHttpResponse.class)"), implementation);
|
||||
assertTrue(implementation.contains("import io.shinhanlife.dap.mcc.infra.itrf.http.employee_search.EmployeeSearchClient;"), implementation);
|
||||
assertTrue(implementation.contains("private final EmployeeSearchClient employeeSearchClient;"), implementation);
|
||||
assertTrue(implementation.contains("employeeSearchClient.call(httpRequest, EmployeeSearchHttpResponse.class)"), implementation);
|
||||
assertFalse(implementation.contains("AxhubHttpComponent"), implementation);
|
||||
assertFalse(implementation.contains("executeLegacy(\"HTTP\""), implementation);
|
||||
Path wireMockResponse = root.resolve("mci-mock/__files/smp_employee_search.json");
|
||||
@@ -185,17 +185,17 @@ class ToolScaffolderTest {
|
||||
assertTrue(Files.exists(wireMockResponse), wireMockResponse.toString());
|
||||
assertTrue(Files.exists(wireMockMapping), wireMockMapping.toString());
|
||||
assertTrue(Files.readString(wireMockMapping).contains("\"urlPath\" : \"/HR_EMPLOYEE_SEARCH\""));
|
||||
Path localConfig = root.resolve("dap-was-http/src/main/resources/application-local.yml");
|
||||
Path localConfig = root.resolve("dap-was-lib/src/main/resources/glow/application-glow-local.yml");
|
||||
assertTrue(Files.exists(localConfig), localConfig.toString());
|
||||
assertTrue(Files.readString(localConfig).contains("name: sample"));
|
||||
assertTrue(Files.readString(localConfig).contains("url: ${AXHUB_SAMPLE_HTTP_URL:/api/mock/http/smp_employee_search}"));
|
||||
assertTrue(Files.readString(localConfig).contains("name: employee-search"));
|
||||
assertTrue(Files.readString(localConfig).contains("url: ${AXHUB_EMPLOYEE_SEARCH_HTTP_URL:/api/mock/http/smp_employee_search}"));
|
||||
Path podMockResponse = root.resolve("dap-was-http/src/main/resources/mock-responses/smp_employee_search.json");
|
||||
assertTrue(Files.exists(podMockResponse), podMockResponse.toString());
|
||||
|
||||
ToolScaffolder.scaffold("employee search", "HR_EMPLOYEE_SEARCH", "Employee search", "smp", "HTTP", moduleName,
|
||||
"tester", "2026.08.11", false, null, null, null, inputFields, outputFields);
|
||||
long apiNameCount = Files.readAllLines(localConfig).stream()
|
||||
.filter(line -> line.trim().equals("- name: sample"))
|
||||
.filter(line -> line.trim().equals("- name: employee-search"))
|
||||
.count();
|
||||
assertEquals(1, apiNameCount);
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package io.shinhanlife.dap.mcc.biz.smp.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/** Tool response for the HTTP integration sample. */
|
||||
public record SampleHttpStatusResponse(
|
||||
@Schema(description = "External API processing status", example = "OK") String status,
|
||||
@Schema(description = "External API response message", example = "Sample API is available") String message) {
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package io.shinhanlife.dap.mcc.biz.smp.usecase;
|
||||
|
||||
import io.shinhanlife.dap.lib.annotation.ToolHint;
|
||||
import io.shinhanlife.dap.mcc.biz.smp.dto.SampleHttpStatusResponse;
|
||||
import org.springaicommunity.mcp.annotation.McpTool;
|
||||
|
||||
/** Sample Tool that demonstrates a configured HTTP API integration. */
|
||||
public interface SampleHttpStatusUseCase {
|
||||
|
||||
@McpTool(name = "smp_sample_status",
|
||||
title = "Sample external HTTP API status",
|
||||
description = "Calls the configured sample HTTP API and returns its status.")
|
||||
@ToolHint(register = false, categoryKey = "smp", mappingId = "HTTP_SAMPLE_001")
|
||||
SampleHttpStatusResponse execute();
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package io.shinhanlife.dap.mcc.biz.smp.usecase.impl;
|
||||
|
||||
import io.shinhanlife.dap.mcc.biz.smp.dto.SampleHttpStatusResponse;
|
||||
import io.shinhanlife.dap.mcc.biz.smp.usecase.SampleHttpStatusUseCase;
|
||||
import io.shinhanlife.dap.mcc.infra.itrf.http.sample.SampleHttpApiClient;
|
||||
import io.shinhanlife.dap.mcc.infra.itrf.http.sample.SampleHttpApiResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SampleHttpStatusUseCaseImpl implements SampleHttpStatusUseCase {
|
||||
|
||||
private final SampleHttpApiClient sampleHttpApiClient;
|
||||
|
||||
@Override
|
||||
public SampleHttpStatusResponse execute() {
|
||||
SampleHttpApiResponse response = sampleHttpApiClient.getStatus();
|
||||
return new SampleHttpStatusResponse(response.status(), response.message());
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package io.shinhanlife.dap.mcc.infra.itrf.http.sample;
|
||||
|
||||
import io.shinhanlife.dap.lib.integration.http.component.AxhubHttpComponent;
|
||||
import io.shinhanlife.dap.lib.integration.http.component.AxhubHttpDomain;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/** Example of a Tool-specific HTTP client using the configured AX HUB HTTP domain. */
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SampleHttpApiClient {
|
||||
|
||||
private final AxhubHttpComponent http;
|
||||
|
||||
public SampleHttpApiResponse getStatus() {
|
||||
return http.call(AxhubHttpDomain.SAMPLE, "/status", null, SampleHttpApiResponse.class);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package io.shinhanlife.dap.mcc.infra.itrf.http.sample;
|
||||
|
||||
/** DTO matching the external API JSON response: { "status": "OK", "message": "..." }. */
|
||||
public record SampleHttpApiResponse(String status, String message) {
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package io.shinhanlife.dap.mcc.biz.smp.converter;
|
||||
|
||||
import io.shinhanlife.dap.mcc.biz.smp.dto.EmployeeSearchRequest;
|
||||
import io.shinhanlife.dap.mcc.biz.smp.dto.EmployeeSearchResponse;
|
||||
import io.shinhanlife.dap.mcc.infra.itrf.http.sample.io.EmployeeSearchHttpRequest;
|
||||
import io.shinhanlife.dap.mcc.infra.itrf.http.sample.io.EmployeeSearchHttpResponse;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||
public interface EmployeeSearchConverter {
|
||||
EmployeeSearchHttpRequest toHttpRequest(EmployeeSearchRequest request);
|
||||
EmployeeSearchResponse toResponse(EmployeeSearchHttpResponse httpResponse);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package io.shinhanlife.dap.mcc.biz.smp.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class EmployeeSearchRequest {
|
||||
@Schema(description = "조회할 사번", example = "EMP10001", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String employeeId;
|
||||
|
||||
@Schema(description = "직원명. 사번 없이 이름으로 조회할 때 사용", example = "홍길동")
|
||||
private String employeeName;
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package io.shinhanlife.dap.mcc.biz.smp.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class EmployeeSearchResponse {
|
||||
private String resultCode;
|
||||
|
||||
private String resultMessage;
|
||||
@Schema(description = "직원명", example = "홍길동")
|
||||
private String employeeName;
|
||||
|
||||
@Schema(description = "소속 부서명", example = "AX추진팀")
|
||||
private String departmentName;
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package io.shinhanlife.dap.mcc.biz.smp.usecase;
|
||||
|
||||
import org.springaicommunity.mcp.annotation.McpTool;
|
||||
import io.shinhanlife.dap.lib.annotation.ToolHint;
|
||||
import io.shinhanlife.dap.mcc.biz.smp.dto.EmployeeSearchRequest;
|
||||
import io.shinhanlife.dap.mcc.biz.smp.dto.EmployeeSearchResponse;
|
||||
|
||||
/**
|
||||
* @package io.shinhanlife.dap.mcc.biz.smp.usecase
|
||||
* @className EmployeeSearchUseCase
|
||||
* @description AX HUB ?쒖뒪??泥섎━ ?대옒??
|
||||
* @author jade
|
||||
* @create 2026.08.11
|
||||
* <pre>
|
||||
* ---------- 媛쒖젙?대젰 ----------
|
||||
* ?섏젙?? ?섏젙?? ?섏젙?댁슜
|
||||
* ---------- -------- ---------------------------
|
||||
* 2026.08.11 jade 理쒖큹?앹꽦
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public interface EmployeeSearchUseCase {
|
||||
|
||||
@McpTool(name = "smp_employee_search", title = "직원 정보 조회", description = "사번 또는 직원명을 기준으로 직원 정보를 조회합니다.")
|
||||
@ToolHint(register = false, categoryKey = "smp", mappingId = "CLCNNB00001")
|
||||
EmployeeSearchResponse execute(EmployeeSearchRequest req);
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package io.shinhanlife.dap.mcc.biz.smp.usecase.impl;
|
||||
|
||||
import io.shinhanlife.dap.mcc.biz.smp.converter.EmployeeSearchConverter;
|
||||
import io.shinhanlife.dap.mcc.biz.smp.dto.EmployeeSearchRequest;
|
||||
import io.shinhanlife.dap.mcc.biz.smp.dto.EmployeeSearchResponse;
|
||||
import io.shinhanlife.dap.mcc.biz.smp.usecase.EmployeeSearchUseCase;
|
||||
import io.shinhanlife.dap.mcc.infra.itrf.http.sample.SampleClient;
|
||||
import io.shinhanlife.dap.mcc.infra.itrf.http.sample.io.EmployeeSearchHttpRequest;
|
||||
import io.shinhanlife.dap.mcc.infra.itrf.http.sample.io.EmployeeSearchHttpResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class EmployeeSearchUseCaseImpl implements EmployeeSearchUseCase {
|
||||
|
||||
private final EmployeeSearchConverter converter;
|
||||
private final SampleClient sampleClient;
|
||||
|
||||
@Override
|
||||
public EmployeeSearchResponse execute(EmployeeSearchRequest request) {
|
||||
EmployeeSearchHttpRequest httpRequest = converter.toHttpRequest(request);
|
||||
EmployeeSearchHttpResponse httpResponse = sampleClient.call(httpRequest, EmployeeSearchHttpResponse.class);
|
||||
|
||||
EmployeeSearchResponse response = converter.toResponse(httpResponse);
|
||||
response.setResultCode("SUCCESS");
|
||||
response.setResultMessage("HTTP API call completed.");
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package io.shinhanlife.dap.mcc.infra.itrf.http.sample;
|
||||
|
||||
import io.shinhanlife.dap.lib.integration.http.component.AxhubHttpComponent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SampleClient {
|
||||
private static final String API_NAME = "sample";
|
||||
|
||||
private final AxhubHttpComponent http;
|
||||
|
||||
public <I, O> O call(I request, Class<O> responseType) {
|
||||
return http.call(API_NAME, request, responseType);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package io.shinhanlife.dap.mcc.infra.itrf.http.sample.io;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class EmployeeSearchHttpRequest {
|
||||
private String employeeId;
|
||||
private String employeeName;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package io.shinhanlife.dap.mcc.infra.itrf.http.sample.io;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class EmployeeSearchHttpResponse {
|
||||
private String resultCode;
|
||||
private String employeeName;
|
||||
private String departmentName;
|
||||
}
|
||||
@@ -26,17 +26,3 @@ axhub:
|
||||
url: http://localhost:8081
|
||||
tool:
|
||||
url: ${AXHUB_TOOL_URL:http://localhost:${server.port}}
|
||||
mock:
|
||||
http:
|
||||
enabled: true
|
||||
|
||||
glow:
|
||||
communication:
|
||||
http:
|
||||
api-list:
|
||||
- name: memo
|
||||
domain: ${AXHUB_MEMO_HTTP_DOMAIN:http://localhost:${server.port}}
|
||||
url: ${AXHUB_MEMO_HTTP_URL:/api/mock/http/cmm_memo_retriever}
|
||||
method: POST
|
||||
content-type: application/json;charset=UTF-8
|
||||
biz-pod: false
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
package io.shinhanlife.dap.mcc.biz.smp.usecase;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import io.shinhanlife.dap.mcc.infra.itrf.http.sample.SampleClient;
|
||||
|
||||
import io.shinhanlife.dap.mcc.biz.smp.dto.EmployeeSearchRequest;
|
||||
import io.shinhanlife.dap.mcc.biz.smp.dto.EmployeeSearchResponse;
|
||||
import io.shinhanlife.dap.mcc.biz.smp.usecase.impl.EmployeeSearchUseCaseImpl;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class EmployeeSearchUseCaseTest {
|
||||
|
||||
@Test
|
||||
void createsToolRequestAndResponseDtos() {
|
||||
assertNotNull(new EmployeeSearchRequest());
|
||||
assertNotNull(new EmployeeSearchResponse());
|
||||
}
|
||||
|
||||
@Test
|
||||
void delegatesHttpCallThroughApiSpecificClient() {
|
||||
assertNotNull(EmployeeSearchUseCaseImpl.class.getDeclaredFields());
|
||||
assertTrue(java.util.Arrays.stream(EmployeeSearchUseCaseImpl.class.getDeclaredFields())
|
||||
.anyMatch(field -> field.getType().equals(SampleClient.class)));
|
||||
}
|
||||
}
|
||||
@@ -61,10 +61,6 @@ services:
|
||||
- AXHUB_GATEWAY_URL=http://gateway:8081
|
||||
- AXHUB_SOURCE_DIR=/src
|
||||
- AXHUB_TOOL_URL=http://was-sms:8082
|
||||
# HTTP Tool sample target inside the Docker network.
|
||||
# WireMock 서비스명과 컨테이너 포트(8080)를 사용합니다.
|
||||
- AXHUB_SAMPLE_HTTP_DOMAIN=http://mci-mock:8080
|
||||
- AXHUB_SAMPLE_HTTP_URL=/CLCNNB00001
|
||||
- GLOW_COMMUNICATION_MCI_HOMT=http://mci-mock
|
||||
- GLOW_COMMUNICATION_MCI_PORT=8080
|
||||
- GLOW_COMMUNICATION_EXTMCI_HOMT=http://mci-mock
|
||||
@@ -88,10 +84,6 @@ services:
|
||||
- SPRING_DATA_REDIS_PORT=6379
|
||||
- AXHUB_GATEWAY_URL=http://gateway:8081
|
||||
- AXHUB_TOOL_URL=http://was-oth:8084
|
||||
# HTTP Tool sample target inside the Docker network.
|
||||
# WireMock 서비스명과 컨테이너 포트(8080)를 사용합니다.
|
||||
- AXHUB_SAMPLE_HTTP_DOMAIN=http://mci-mock:8080
|
||||
- AXHUB_SAMPLE_HTTP_URL=/CLCNNB00001
|
||||
- GLOW_COMMUNICATION_MCI_HOMT=http://mci-mock
|
||||
- GLOW_COMMUNICATION_MCI_PORT=8080
|
||||
- GLOW_COMMUNICATION_EXTMCI_HOMT=http://mci-mock
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"resultCode" : "SUCCESS",
|
||||
"employeeName" : "홍길동",
|
||||
"departmentName" : "AX추진팀"
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"request" : {
|
||||
"method" : "POST",
|
||||
"urlPath" : "/CLCNNB00001"
|
||||
},
|
||||
"response" : {
|
||||
"status" : 200,
|
||||
"headers" : {
|
||||
"Content-Type" : "application/json;charset=UTF-8"
|
||||
},
|
||||
"bodyFileName" : "smp_employee_search.json"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user