# API 거래 플로우 정리 ## 전체 플로우 다이어그램 ``` [Client Request] ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 1. ApiAdapterController (/api/**, /mapi/**) │ │ - HTTP 요청 수신, 어댑터 정보 조회 │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 2. ApiAdapterService │ │ - 요청 파싱 (GET/POST/PUT/DELETE) │ │ - 암/복호화 처리 (AES128, AES256 등) │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 3. HttpAdapterServiceSupport.service() │ │ - Pre/Post Filter 실행 │ │ - RequestDispatcher 호출 │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 4. RequestDispatcher.handle() │ │ - Processor 인스턴스 생성/획득 │ │ - Adapter 상태 관리 │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 5. RequestProcessor.hookup() │ │ - EAIMessage 생성 (StandardMessage → EAIMessage) │ │ - 유량제어, 라우팅 판단 │ │ - FlowRouter.process() 호출 │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 6. IFRouter.process() │ │ - Outbound 라우팅 │ │ - FailOver 처리 │ │ - ElinkESBProcessProxy 호출 │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 7. RESTProcess (extends DefaultProcess) │ │ - flow() 메소드 실행 │ │ - 송신 변환, 로그, 응답 처리 │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 8. HttpSender.callService() │ │ - ElinkAdapter 획득 │ │ - Adapter 호출 │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 9. HttpClient5AdapterServiceRest.execute() │ │ - 실제 HTTP 통신 (Apache HttpClient 5) │ │ - OAuth 토큰 관리 │ │ - 암/복호화 처리 │ └─────────────────────────────────────────────────────────────────┘ ↓ [Target System] ``` --- ## 각 클래스 설명 ### 1. ApiAdapterController | 항목 | 내용 | |------|------| | 위치 | `eapim-online/src/main/java/com/eactive/eai/adapter/controller/` | | 역할 | REST API 진입점 (Spring Controller) | | 주요 기능 | - `/api/**`, `/mapi/**` 엔드포인트 매핑
- TSEAIHS04 테이블에서 어댑터 정보 조회
- HttpDynamicInAdapterManager로 어댑터 찾기
- ApiAdapterService.callApi() 호출 | ### 2. ApiAdapterService | 항목 | 내용 | |------|------| | 위치 | `eapim-online/src/main/java/com/eactive/eai/adapter/service/` | | 역할 | Inbound 서비스 레이어 | | 상속 | `HttpAdapterServiceSupport` | | 주요 기능 | - HTTP Method별 요청 파싱
- Inbound 암/복호화 (AES128, AES256 등)
- 부모 클래스 `service()` 호출 | ### 3. HttpAdapterServiceSupport | 항목 | 내용 | |------|------| | 위치 | `elink-online-common/src/main/java/com/eactive/eai/adapter/http/dynamic/` | | 역할 | Inbound 어댑터 추상 클래스 | | 주요 기능 | - `service()` 메소드: 핵심 디스패처
- Pre-Filter / Post-Filter 실행
- StandardMessage 생성
- RequestDispatcher.handle() 호출 | ### 4. RequestDispatcher | 항목 | 내용 | |------|------| | 위치 | `elink-online-common/src/main/java/com/eactive/eai/adapter/` | | 역할 | 요청 분배자 | | 주요 기능 | - Processor 인스턴스 생성/획득
- `processor.execute()` 호출
- AdapterGroup 상태 관리 (동시 처리 수 증감) | ### 5. RequestProcessorSupport / RequestProcessor | 항목 | 내용 | |------|------| | 위치 | `elink-online-common/src/main/java/com/eactive/eai/inbound/processor/` | | 역할 | 요청 처리 프로세서 | | 관계 | `RequestProcessor extends RequestProcessorSupport` | | 주요 기능 | - `execute()` → `hookup()` 호출
- StandardMessage → EAIMessage 변환
- 유량제어 (RateLimiter)
- SYNC/ASYNC 분기 처리
- FlowRouter.process() 호출 | ### 6. IFRouter | 항목 | 내용 | |------|------| | 위치 | `elink-online-common/src/main/java/com/eactive/eai/common/routing/` | | 역할 | FlowControl → Outbound 라우터 | | 주요 기능 | - Outbound Process로 라우팅
- Local/Remote 호출 판단
- FailOver 처리
- TAS(시뮬레이터) 거래 처리
- ElinkESBProcessProxy 호출 | ### 7. DefaultProcess / RESTProcess | 항목 | 내용 | |------|------| | 위치 | `elink-online-common/src/main/java/com/eactive/eai/outbound/` | | 역할 | Outbound 처리 프로세스 | | 관계 | `RESTProcess extends HTTPProcess extends DefaultProcess` | | 주요 기능 (DefaultProcess) | - `flow()`: 핵심 처리 흐름
- 송신 전/후 처리
- 메시지 변환 (Transform)
- 로그 처리 | | 주요 기능 (RESTProcess) | - `outboundCtrlCallService()`: HttpSender 호출
- REST 특화 처리
- 표준/비표준 메시지 처리 | ### 8. HttpSender | 항목 | 내용 | |------|------| | 위치 | `elink-online-common/src/main/java/com/eactive/eai/control/` | | 역할 | HTTP 송신 제어 | | 주요 기능 | - ElinkAdapterFactory에서 HTTP Adapter 획득
- `adapter.callService()` 호출
- SocketTimeout, HttpStatusException 처리 | ### 9. HttpClient5AdapterServiceRest | 항목 | 내용 | |------|------| | 위치 | `elink-online-common/src/main/java/com/eactive/eai/adapter/http/client/impl/` | | 역할 | 실제 HTTP 클라이언트 구현체 | | 주요 기능 | - Apache HttpClient 5 사용
- GET/POST/PUT/DELETE 메소드 처리
- OAuth2 토큰 관리 (발급/갱신)
- Outbound 암/복호화 (AES128, AES256, AES256GCM 등)
- Forward Proxy 지원
- 응답 헤더 릴레이 | --- ## 클래스 관계도 ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ eapim-online (프로젝트) │ ├─────────────────────────────────────────────────────────────────────────┤ │ ApiAdapterController ──uses──▶ ApiAdapterService │ │ │ │ │ │ extends │ │ ▼ │ └──────────────────────────────────────┼──────────────────────────────────┘ │ ┌──────────────────────────────────────┼──────────────────────────────────┐ │ elink-online-common (서브모듈) │ ├──────────────────────────────────────┼──────────────────────────────────┤ │ ▼ │ │ HttpAdapterServiceSupport │ │ │ │ │ │ calls │ │ ▼ │ │ RequestDispatcher ──creates──▶ RequestProcessor │ │ │ │ │ │ extends │ │ ▼ │ │ RequestProcessorSupport │ │ │ │ │ │ calls │ │ ▼ │ │ FlowRouter ────────────────▶ IFRouter │ │ │ │ │ │ calls │ │ ▼ │ │ RESTProcess ◀──extends── HTTPProcess │ │ │ │ │ │ │ extends │ extends │ │ ▼ ▼ │ │ DefaultProcess ◀────────────┘ │ │ │ │ │ │ calls │ │ ▼ │ │ HttpSender │ │ │ │ │ │ uses │ │ ▼ │ │ ElinkAdapterFactory │ │ │ │ │ │ creates │ │ ▼ │ │ HttpClient5AdapterServiceRest │ │ │ │ │ │ uses │ │ ▼ │ │ Apache HttpClient 5 │ └─────────────────────────────────────────────────────────────────────────┘ ``` --- ## 메시지 변환 흐름 ``` [HTTP Request Body] ↓ StandardMessage (표준전문) ↓ EAIMessage (내부 전문) ↓ Transform (변환) ↓ [Target System Request] ↓ [Target System Response] ↓ Transform (역변환) ↓ EAIMessage ↓ StandardMessage ↓ [HTTP Response Body] ``` --- ## 주요 처리 패턴 | 패턴 | 설명 | 처리 위치 | |------|------|-----------| | **SS (Sync-Sync)** | 동기 요청 → 동기 응답 | RequestProcessor, RESTProcess | | **SA (Sync-Async)** | 동기 요청 → 비동기 응답 (Topic 대기) | RESTProcess.getTopicProperty() | | **AS (Async-Sync)** | 비동기 요청 → 동기 응답 | DefaultProcess.isAsyncSyncPattern() | | **AA (Async-Async)** | 비동기 요청 → 비동기 응답 | RequestProcessor | --- ## 비동기(Async) 처리 플로우 ### 비동기 전체 흐름 ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ [송신 스레드 - 요청 수신] │ │ │ │ RequestProcessor.hookup() │ │ ├─ ROUTING_TYPE = "QUEUE" 판단 │ │ │ │ │ └─ FlowRouter.process() │ │ └─ JMSSender.sendToQueue(eaiMessage, ...) │ │ └─ EAIMessage 직렬화 → JMS Queue 전송 │ │ │ │ │ ← 즉시 응답 반환 (202 Accepted 등) │ └─────────────────────────┼───────────────────────────────────────────────┘ │ [JMS Queue] (ActiveMQ / WebLogic JMS / WebSphere MQ) │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ [수신 스레드 - QueueConsumer] │ │ │ │ DefaultQueueConsumer.run() │ │ ├─ consumer.receive() - 메시지 수신 대기 │ │ │ │ │ ├─ EAIMessage 역직렬화 │ │ │ └─ transactionContext Map 복원 │ │ │ │ │ ├─ ElinkTransactionContext.initialize(...) │ │ │ │ │ └─ ElinkESBProcessProxy.callElinkESBProcess() │ │ └─ DefaultProcess / RESTProcess 호출 │ │ └─ 실제 대외기관 호출 │ │ │ │ (finally) ElinkTransactionContext.clear() │ └─────────────────────────────────────────────────────────────────────────┘ ``` ### Queue 송신 (FlowRouter → JMSSender) ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ FlowRouter.process() │ │ │ │ │ ├─ route_type == "QUEUE" 확인 │ │ │ │ │ ├─ RoutingVO에서 asyncRoutingPath(Queue 이름) 조회 │ │ │ │ │ ├─ Properties에 추가 정보 설정 │ │ │ ├─ EAIBWKCLS (업무그룹코드) │ │ │ ├─ EAISVCCD (서비스코드) │ │ │ └─ OSIDINSTCD (대외기관코드) │ │ │ │ │ └─ JMSSender.sendToQueue(eaiMessage, factory, queue, prop) │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ JMSSender.sendToQueue() │ │ │ │ │ ├─ ElinkConfig.isUseInternalQueue() 확인 │ │ │ │ │ ├─ [내부 Queue] AmqQueueProducer.sendMessage() │ │ │ └─ ActiveMQ 내장 브로커 사용 (vm://localhost) │ │ │ │ │ └─ [외부 Queue] sendToJmsQueue() │ │ ├─ JmsServiceLocator에서 QueueConnectionFactory 획득 │ │ ├─ QueueConnection → QueueSession → QueueSender 생성 │ │ ├─ ObjectMessage 생성 │ │ │ ├─ msg.setObject(eaiMessage) ← Serializable │ │ │ └─ msg.setStringProperty(...) ← Properties 복사 │ │ └─ qsender.send(msg) │ └─────────────────────────────────────────────────────────────────────────┘ ``` ### Queue Consumer 수신 및 처리 ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ QueueConsumerService (Spring Bean) │ │ │ │ │ ├─ afterPropertiesSet() → startConsumer() │ │ │ │ │ ├─ ActiveMQConnectionFactory 생성 │ │ │ └─ setTrustAllPackages(true) ← 역직렬화 허용 │ │ │ │ │ ├─ ExecutorService (FixedThreadPool) 생성 │ │ │ │ │ └─ DefaultQueueConsumer[maxThread] 생성 및 submit │ │ └─ 각 Consumer가 별도 스레드에서 실행 │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ Consumer.run() [Loop] (DefaultQueueConsumer / FCQueueReceiver) │ │ │ │ │ ├─ while(run) { │ │ │ message = consumer.receive(2000) ← 2초 타임아웃 │ │ │ │ │ │ if(message == null) continue; │ │ │ │ │ │ // ObjectMessage 검증 및 EAIMessage 역직렬화 │ │ │ omsg = (ObjectMessage) message; │ │ │ eaiMessage = (EAIMessage) omsg.getObject(); │ │ │ │ │ │ // RoutingVO에서 Process 경로 조회 │ │ │ routingVO = RoutingManager.getRoutingVO(flwCntlRtnNm); │ │ │ serviceURI = routingVO.getSyncRoutingPath(); // BaseFCProcess │ │ │ │ │ │ // Process 호출 (ElinkESBProcessProxy 내부에서 컨텍스트 관리) │ │ │ ElinkESBProcessProxy.callElinkESBProcess(serviceURI, ...) │ │ │ } │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ ElinkESBProcessProxy.callElinkESBProcess() │ │ │ │ │ ├─ [조건 충족: ASYNC && !outbound] → 컨텍스트 초기화 │ │ │ ElinkTransactionContext.initialize(eaiMessage.getTransactionContext()) │ │ │ │ ├─ BaseFCProcess.callService() │ │ │ └─ ElinkESBProcessProxy (RESTProcess) ← 조건 미충족, 초기화 안함 │ │ │ └─ RESTProcess 실행 │ │ │ │ │ └─ finally { ElinkTransactionContext.clear() } ← 조건부 해제 │ └─────────────────────────────────────────────────────────────────────────┘ ``` ### 비동기 관련 클래스 | 클래스 | 위치 | 역할 | |--------|------|------| | `FlowRouter` | `elink-online-common/.../routing/` | ROUTING_TYPE에 따라 CALL/QUEUE/TOPIC 분기 | | `JMSSender` | `elink-online-common/.../util/` | JMS Queue/Topic 메시지 송신 | | `AmqQueueProducer` | `elink-online-common/.../activemq/` | ActiveMQ 내장 브로커용 Producer | #### JMS Provider별 Consumer 구현체 | Provider | Consumer | 비고 | |----------|----------|------| | **ActiveMQ** | `flowcontrol/activemq/DefaultQueueConsumer.java` | 내장 브로커 (vm://localhost) | | **JEUS** | `flowcontrol/jeus/DefaultQueueConsumer.java` | JNDI Lookup | | **WebSphere** | `flowcontrol/websphere/DefaultQueueConsumer.java` | JNDI Lookup | | **WebLogic** | `flowcontrol/jms/FCQueueReceiver.java` | JNDI Lookup (weblogic.jndi.WLInitialContextFactory) | > `ElinkTransactionContext` 초기화/해제는 Consumer가 아닌 `ElinkESBProcessProxy`에서 조건부로 처리됩니다. ### Queue 연결 방식 | 방식 | 설정 | 사용 환경 | |------|------|-----------| | **내장 브로커** | `vm://localhost` | 단일 인스턴스, 테스트 환경 | | **TCP 연결** | `tcp://host:61617` | 분산 환경, 다중 인스턴스 | | **외부 JMS** | JNDI Lookup | WebLogic, WebSphere MQ 등 | ### 환경별 Consumer 설정 (Spring XML) ``` WebContent/WEB-INF/ ├─ applicationContext.xml ← 메인 설정 │ ├─ import: mq/applicationContext-activemq.xml │ └─ import: mq/applicationContext-websphere.xml │ └─ mq/ ├─ applicationContext-activemq.xml ← ActiveMQ (현재 활성화) │ └─ flowcontrol.activemq.QueueConsumerService │ └─ uri: vm://localhost (내장 브로커) │ └─ applicationContext-websphere.xml ← WebSphere MQ (주석처리 = 비활성화) └─ flowcontrol.websphere.QueueConsumerService └─ 외부 WebSphere MQ 연결 ``` > **Note**: WebLogic/JEUS 환경에서 외부 JMS 사용 시 해당 XML 파일 추가 또는 수정 필요. > 현재 프로젝트는 **ActiveMQ 내장 브로커**를 기본으로 사용. ### TransactionContext 비동기 전달 ``` [송신 스레드] [수신 스레드] │ │ ├─ eaiMsg.transactionContext │ │ └─ {"SEED_SALT": "abc123", ...} │ │ │ ▼ │ ┌──────────────┐ │ │ Serialize │ ──── JMS Queue ────▶ │ │ (EAIMessage) │ │ └──────────────┘ │ ▼ ┌──────────────────┐ │ Deserialize │ │ (EAIMessage) │ │ └─ context 복원 │ └──────────────────┘ │ ▼ ElinkESBProcessProxy └─ 조건부 initialize() │ ElinkTransactionContext .getSeedSalt() → "abc123" ``` > **Note**: `EAIMessage.transactionContext`는 `Serializable`이므로 JMS Queue를 통해 전달되어도 데이터가 유지됩니다. > `ElinkTransactionContext.initialize()`는 `ElinkESBProcessProxy`에서 ASYNC 거래 && !outbound 조건일 때만 호출됩니다. --- ## 암호화 지원 (HttpClient5AdapterServiceRest) | 알고리즘 | 용도 | Key 추출 방식 | |----------|------|---------------| | AES128-TOSS | 토스 연동 | clientSecret[22:38] | | AES128-TOGETHER | 투게더 연동 | clientSecret[44:60] | | AES256 | 일반 | clientSecret[10:42] | | AES256-KAKAO | 카카오 연동 | IV/Key 별도 설정 | | AES256-NICEON | 나이스지키미 연동 | Adapter Token 기반 | | AES256GCM | GCM 모드 | 동적 Key 생성 | --- ## 관련 파일 경로 ### eapim-online (메인 프로젝트) - `src/main/java/com/eactive/eai/adapter/controller/ApiAdapterController.java` - `src/main/java/com/eactive/eai/adapter/service/ApiAdapterService.java` ### elink-online-common (서브모듈) #### 동기 처리 - `src/main/java/com/eactive/eai/adapter/http/dynamic/HttpAdapterServiceSupport.java` - `src/main/java/com/eactive/eai/adapter/RequestDispatcher.java` - `src/main/java/com/eactive/eai/inbound/processor/RequestProcessorSupport.java` - `src/main/java/com/eactive/eai/inbound/processor/RequestProcessor.java` - `src/main/java/com/eactive/eai/common/routing/IFRouter.java` - `src/main/java/com/eactive/eai/outbound/DefaultProcess.java` - `src/main/java/com/eactive/eai/outbound/RESTProcess.java` - `src/main/java/com/eactive/eai/control/HttpSender.java` - `src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClient5AdapterServiceRest.java` #### 비동기 처리 (Queue) - `src/main/java/com/eactive/eai/common/routing/FlowRouter.java` - 라우팅 분기 (CALL/QUEUE/TOPIC) - `src/main/java/com/eactive/eai/common/routing/ElinkESBProcessProxy.java` - Process 호출 (비동기 컨텍스트 관리) - `src/main/java/com/eactive/eai/common/util/JMSSender.java` - Queue/Topic 송신 - `src/main/java/com/eactive/eai/common/activemq/AmqQueueProducer.java` - ActiveMQ Producer - `src/main/java/com/eactive/eai/flowcontrol/activemq/QueueConsumerService.java` - ActiveMQ Consumer 서비스 - `src/main/java/com/eactive/eai/flowcontrol/activemq/DefaultQueueConsumer.java` - ActiveMQ Consumer - `src/main/java/com/eactive/eai/flowcontrol/jeus/QueueConsumerService.java` - JEUS Consumer 서비스 - `src/main/java/com/eactive/eai/flowcontrol/jeus/DefaultQueueConsumer.java` - JEUS Consumer - `src/main/java/com/eactive/eai/flowcontrol/websphere/QueueConsumerService.java` - WebSphere Consumer 서비스 - `src/main/java/com/eactive/eai/flowcontrol/websphere/DefaultQueueConsumer.java` - WebSphere Consumer - `src/main/java/com/eactive/eai/flowcontrol/jms/FCQueueReceiver.java` - WebLogic JMS Consumer