42 Commits

Author SHA1 Message Date
curry772 1240b24c90 BIZ_DATA 항목 추가 2026-06-12 09:08:02 +09:00
curry772 7346c3070d eaiSvcCd 추출 로직 변경
- StandarMessage에 이미 eaiSvcCd가 설정되어 있으면 그것을 이용(비표준)
- 표준전문에서 조합하도록 수정(표준)
2026-06-12 09:07:40 +09:00
curry772 9a597a52ac afterFoundEaiMessage 함수에 프러퍼티 이용 헤더매핑 로직 추가
- DJB_IN_HTTHEAD_STDHEAD_MAPPING 프러퍼티 그룹 이용
2026-06-12 09:05:50 +09:00
curry772 5653a183eb GUID 생성 시 시스템코드 OPA 사용으로 변경 2026-06-12 09:01:27 +09:00
curry772 0e3a612bc0 TemplateAdapterErrorMsgHandler 를 이용하여 오류메시지 생성할 수 있도록 변경 2026-06-09 13:49:32 +09:00
curry772 68c29b962e feat: StandardMessageCoordinatorDJB에 callProp refValue 값 주입 기능 추가
- coordinateAfterCreateMessageByRule에서 StandardItem의 refValue가
   \${callProp.키} 패턴이면 Properties에서 값을 꺼내 setValue로 설정한다.
- \${callProp.키:기본값} 구문으로 기본값 지정 가능
- 점(.) 구분으로 Properties/Map 중첩 구조 탐색 지원
- GROUP 타입 재귀 순회, GRID/FARRAY는 건너뜀
2026-06-05 17:20:09 +09:00
curry772 dafe80f8bc fix: SiftingAppender 파일 락 해결 및 거래 로그 on/off 제어 추가
- DJErpApiAdapterController: MDC 제어를 TxSiftContext.begin/end로 교체
- TxSiftContext.end()를 별도 finally로 분리하여 항상 실행 보장
- elink-online-core: Logger SiftingAppender 개선 (submodule)
- elink-online-common: TxSiftContext 추가 (submodule)
2026-06-05 14:06:40 +09:00
curry772 9e78a0e199 ApiRequestBodyFilter 테스트를 위한 url pattern /dj/* 추가 2026-06-02 18:08:11 +09:00
curry772 3ec18b17e8 테스크 코드 이동 2026-06-02 18:06:55 +09:00
curry772 90464ee33f 성능 튜닝 2026-06-02 18:06:29 +09:00
curry772 60e6b30c9b api id, eai svc cd 추출 부분 ApiKeyExtractFilter로 이동 2026-06-02 18:06:19 +09:00
curry772 7d89d6d43e XML 메시지 지원 2026-06-02 08:30:51 +09:00
curry772 7109c56623 DJBank에 필요없는 클래스 정리
- 타 사이트 설정파일 및 표준전문 클래스
2026-06-01 09:57:06 +09:00
curry772 6a53e29710 eai.tableowner AGWADM -> AGWAPP 변경 2026-06-01 09:41:10 +09:00
curry772 eff7b31490 암복호화 함수 이름 변경 및 단위테스트 추가
- 클래스이름 오타 수정
- Parser 단위 테스트 추가
2026-06-01 08:58:08 +09:00
curry772 e2950a339f API 수신 RequestMapping 추가 2026-05-28 13:31:35 +09:00
curry772 01e4e36345 HsmContextSha256KeyDerivationStrategy 추가
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 13:30:37 +09:00
curry772 698b3ca7b6 JWT 서명 알고리즘 RS256 → PS256 교체 — AuthorizationServerConfig
PssJwtAccessTokenConverter 적용

- jwtAccessTokenConverter()에서 PssJwtAccessTokenConverter 사용으로 변경
- 기존 JwtAccessTokenConverter + setKeyPair() → new
PssJwtAccessTokenConverter(privateKey, publicKey)
- PEM 도출·setVerifierKey() 호출은 생성자 내부로 이전
- elink-online-common 서브모듈 업데이트 (RsaPssSigner, RsaPssVerifier,
PssJwtAccessTokenConverter 추가)
2026-05-28 13:28:41 +09:00
curry772 c74d1777df Dynamic IV 도출 지원 — DerivedKey iv 필드 추가, HsmKeyAndIvDerivationStrategy 구현 2026-05-27 13:48:23 +09:00
curry772 c95307901e DJBErp -> DJB 클래스 이름 첨자 변경 2026-05-27 10:49:22 +09:00
curry772 c12ff0a64a chore: 서브모듈들 master HEAD로 업데이트 2026-05-27 10:34:25 +09:00
curry772 1c82f0121c 설계서 ignore 추가 2026-05-27 10:33:23 +09:00
curry772 82998b475c DJBRequestProcessor Override 메소드 시그니쳐 변경 2026-05-27 10:32:08 +09:00
curry772 7336267b32 Reload/RemoveInflowClientControlCommand 패키지 이동 2026-05-27 10:30:54 +09:00
curry772 8d69c459d9 클라이언트 유량제어 관련 단위테스트 eapim-online 이동 2026-05-26 16:36:16 +09:00
curry772 4f54ee5259 클라이언트 유량제어 eapim-online 이동 2026-05-26 16:33:15 +09:00
curry772 912a282b54 body 전체 암복호화 대상 필터 (설계서 작성 코딩) 2026-05-26 15:16:54 +09:00
curry772 e8c379f3c7 대상 없는 암복호화 필터 제거 2026-05-26 13:43:10 +09:00
curry772 6ab138b63a 전체 body 암호화를 사용하지 않는 기관의 필터 제거
- 카카오페이, 네이버페이
2026-05-26 13:41:29 +09:00
curry772 c2ad7be7e4 전체암호화를 상용하지 않는 기관의 필터 제거
- 카카오페이, 네이버페이
2026-05-26 13:40:52 +09:00
curry772 aea4134437 Erp 응답용 외부 암호화 없음 2026-05-26 13:28:32 +09:00
curry772 bf91d02be7 암복호화 function 개발
- 암호화모듈서비스(CryptoModuleService)를 호출하여 암복호화 수행하는 function
2026-05-26 10:15:22 +09:00
curry772 9fcce55966 coordinateAfterParsing 수정 2026-05-26 09:54:53 +09:00
curry772 1f285c3bfd DJBank 암복호화필터 설계
- 기관별 InCryptoFilter를 상속한 필터 설계
- 기관별 OutCryptoFilter를 상송한 필터 설계
- 대상 기관 : 카카오뱅크, 카카오페이, 네이버Fn, 토스뱅크, 제주은행, DJErp
2026-05-26 09:51:53 +09:00
curry772 13608ebc8e chore: elink-online-common/core 서브모듈을 master HEAD로 업데이트 2026-05-19 11:22:18 +09:00
curry772 202538c50c 거래파일로그(SIFT_LOGGER) 출력기능 개발
- UUID별로 거래파일로그 생성
2026-05-19 11:19:39 +09:00
curry772 ade012a1f7 JSON 메시지 validation 기능 수정
- 기본 동작 변경 : transformer.validation=true
2026-05-18 14:01:42 +09:00
curry772 abe3756f69 chore: elink-online-common 서브모듈을 master HEAD로 업데이트 2026-05-18 10:58:50 +09:00
curry772 65fc0d0df4 context.xml rename 2026-05-18 10:49:49 +09:00
curry772 c34a2c019b 분별 통계 메트릭 로직 변경
- totoalCnt는 400시점으로 변경
- 시간 메트릭 생성 동작 기본값 false로 기본 처리하지 않도록 변경
2026-05-18 10:46:43 +09:00
curry772 6dbe557584 chore: elink-online-common 서브모듈을 master HEAD로 업데이트
feature/cryptofilter 머지 후 생성된 머지 커밋 반영

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 15:24:54 +09:00
curry772 1185329b78 Merge branch 'feature/cryptofilter' 2026-05-14 15:24:20 +09:00
92 changed files with 2569 additions and 3786 deletions
+2
View File
@@ -239,3 +239,5 @@ gradle-app.setting
# Claude Code
.claude/
/작업내역*.md
/설계서*.md
/분석서*.md
@@ -18,5 +18,5 @@ eai.rmiserviceport=30112
eai.systemmode=D
# EAI FEP MCI GW ...
eai.systemtype=API
eai.tableowner=AGWADM
eai.tableowner=AGWAPP
eai.server.extractor=[0,2],[0,2],[-2]
@@ -1,2 +1,2 @@
#\uae30\uc874 ENV \ud56d\ubaa9 \uc678 \uae30\ud0c0 \uc2dc\uc2a4\ud15c \ud504\ub85c\ud37c\ud2f0\ub85c \uc815\uc758\uac00 \ud544\uc694\ud55c \ud544\ub4dc\ub97c \uc815\uc758
transformer.validation=false
transformer.validation=true
+1 -1
View File
@@ -30,7 +30,7 @@
<filter-mapping>
<filter-name>ApiRequestBodyFilter</filter-name>
<url-pattern>/api/*</url-pattern> <!-- 필요한 URL 패턴 -->
<url-pattern>/mapi/*</url-pattern> <!-- 필요한 URL 패턴 -->
<url-pattern>/dj/*</url-pattern> <!-- 필요한 URL 패턴 -->
</filter-mapping>
-26
View File
@@ -1,26 +0,0 @@
# comment start with #
# level; // 0 : root ~ n
# type; // 0: Message, 1: Field, 2:Group 3, Array, 4 : BIZ DATA
# size // 0 : variable, > 0 fixed
# fieldType; // 0: ELEMENT, 1: ATTRIBUTE,
# length;
# dataType; // 0: String, 1: Number
#name,level,type,size,fieldType,length,dataType,refPath,refValue,value
ElinkHeader ,0,0,1,0, 0,0,,,
Header ,1,2,1,1, 0,0,,,
StndCicsTrncd ,2,1,1,1,10,0,,,
StndIntnlStndTelgmLen,2,1,1,1,10,11,,,0
StndTranBaseYmd ,2,1,1,1,10,0,,,
Common ,1,2,0,0, 0,0,Header.StndCicsTrncd,JI6H,null
TranInfo ,2,2,1,0, 0,0,,,
StndCicsTrncd ,3,1,1,0, 3,0,,,
StndTelgmRecvTranCd ,3,1,1,0,10,0,,,
StndPrcssRtdTranCd ,3,1,1,0,10,0,,,
Array ,1,3,0,0, 3,0,,,
Item1 ,2,1,1,0,10,0,,,JI6H
Group ,2,3,1,0, 1,0,,,
gitem1 ,3,1,1,0,10,1,,,726
gitem2 ,3,1,1,0,10,0,,,20220905
FArray ,1,4,0,0,10,0,,,
bizData ,1,9,1,0, 0,0,,,
zzData ,1,1,1,0, 2,10,,,ZZ
1 # comment start with #
2 # level; // 0 : root ~ n
3 # type; // 0: Message, 1: Field, 2:Group 3, Array, 4 : BIZ DATA
4 # size // 0 : variable, > 0 fixed
5 # fieldType; // 0: ELEMENT, 1: ATTRIBUTE,
6 # length;
7 # dataType; // 0: String, 1: Number
8 #name,level,type,size,fieldType,length,dataType,refPath,refValue,value
9 ElinkHeader ,0,0,1,0, 0,0,,,
10 Header ,1,2,1,1, 0,0,,,
11 StndCicsTrncd ,2,1,1,1,10,0,,,
12 StndIntnlStndTelgmLen,2,1,1,1,10,11,,,0
13 StndTranBaseYmd ,2,1,1,1,10,0,,,
14 Common ,1,2,0,0, 0,0,Header.StndCicsTrncd,JI6H,null
15 TranInfo ,2,2,1,0, 0,0,,,
16 StndCicsTrncd ,3,1,1,0, 3,0,,,
17 StndTelgmRecvTranCd ,3,1,1,0,10,0,,,
18 StndPrcssRtdTranCd ,3,1,1,0,10,0,,,
19 Array ,1,3,0,0, 3,0,,,
20 Item1 ,2,1,1,0,10,0,,,JI6H
21 Group ,2,3,1,0, 1,0,,,
22 gitem1 ,3,1,1,0,10,1,,,726
23 gitem2 ,3,1,1,0,10,0,,,20220905
24 FArray ,1,4,0,0,10,0,,,
25 bizData ,1,9,1,0, 0,0,,,
26 zzData ,1,1,1,0, 2,10,,,ZZ
-41
View File
@@ -1,41 +0,0 @@
#-----------------------------------------------------------------------------
# comment start with #
# level; // 0 : root ~ n
# type; // 0: Message, 1: Field, 2:Group 3, Grid, 4 : Field Array, 9 : BIZ DATA
# size // 0 : variable, > 0 fixed
# fieldType; // 0: ELEMENT, 1: ATTRIBUTE,
# length;
# dataType; // 0: String, 1: Number,10: ZZ String, 11: LL Number
#-----------------------------------------------------------------------------
# name ,level ,type ,size ,fieldType ,length ,dataType ,,refPath, refValue,value
#-----------------------------------------------------------------------------
# name ,level ,type ,size ,fieldType ,length ,dataType ,refPath, refValue, value
STD_HNCPHEADER_REQ ,0 ,0 ,1 ,0 ,0 ,0 , , ,
msg_len ,1 ,1 ,1 ,0 ,6 ,1 , , ,199
global_id ,1 ,1 ,1 ,0 ,29 ,0 , , ,GIDNO00000000001111
service_id ,1 ,1 ,1 ,0 ,10 ,0 , , ,ELINKSVC01
service_cmt ,1 ,1 ,1 ,0 ,100 ,0 , , ,ELINK TEST Service
service_tn ,1 ,1 ,1 ,0 ,1 ,0 , , ,0
Session_id ,1 ,1 ,1 ,0 ,100 ,0 , , ,SESSIONID001
encrypt_yn ,1 ,1 ,1 ,0 ,2 ,0 , , ,NO
http_url ,1 ,1 ,1 ,0 ,100 ,0 , , ,
screen_id ,1 ,1 ,1 ,0 ,13 ,0 , , ,SCREEN0000001
scr_no ,1 ,1 ,1 ,0 ,30 ,0 , , ,000000000100000000020000000003
scr_dsc ,1 ,1 ,1 ,0 ,100 ,0 , , ,
usr_id ,1 ,1 ,1 ,0 ,10 ,0 , , ,USER000001
ip_addr ,1 ,1 ,1 ,0 ,47 ,0 , , ,
ip_mac ,1 ,1 ,1 ,0 ,12 ,0 , , ,
com_code ,1 ,1 ,1 ,0 ,4 ,0 , , ,EACT
head_code ,1 ,1 ,1 ,0 ,7 ,0 , , ,EACT001
dept_cd ,1 ,1 ,1 ,0 ,7 ,0 , , ,ELINK01
conn_tp ,1 ,1 ,1 ,0 ,2 ,0 , , ,CH
Inter_chn ,1 ,1 ,1 ,0 ,2 ,0 , , ,EA
recv_tm ,1 ,1 ,1 ,0 ,17 ,0 , , ,20220928000000000
send_tm ,1 ,1 ,1 ,0 ,17 ,0 , , ,
return_gubun ,1 ,1 ,1 ,0 ,1 ,0 , , ,S
return_value ,1 ,1 ,1 ,0 ,1 ,0 , , ,
msg_id ,1 ,1 ,1 ,0 ,7 ,0 , , ,
msg_nm ,1 ,1 ,1 ,0 ,250 ,0 , , ,
filler ,1 ,1 ,1 ,0 ,125 ,0 , , ,
bizData ,1 ,9 ,0 ,0 ,0 ,0 , , ,
1 #-----------------------------------------------------------------------------
2 # comment start with #
3 # level; // 0 : root ~ n
4 # type; // 0: Message, 1: Field, 2:Group 3, Grid, 4 : Field Array, 9 : BIZ DATA
5 # size // 0 : variable, > 0 fixed
6 # fieldType; // 0: ELEMENT, 1: ATTRIBUTE,
7 # length;
8 # dataType; // 0: String, 1: Number,10: ZZ String, 11: LL Number
9 #-----------------------------------------------------------------------------
10 # name ,level ,type ,size ,fieldType ,length ,dataType ,,refPath, refValue,value
11 #-----------------------------------------------------------------------------
12 # name ,level ,type ,size ,fieldType ,length ,dataType ,refPath, refValue, value
13 STD_HNCPHEADER_REQ ,0 ,0 ,1 ,0 ,0 ,0 , , ,
14 msg_len ,1 ,1 ,1 ,0 ,6 ,1 , , ,199
15 global_id ,1 ,1 ,1 ,0 ,29 ,0 , , ,GIDNO00000000001111
16 service_id ,1 ,1 ,1 ,0 ,10 ,0 , , ,ELINKSVC01
17 service_cmt ,1 ,1 ,1 ,0 ,100 ,0 , , ,ELINK TEST Service
18 service_tn ,1 ,1 ,1 ,0 ,1 ,0 , , ,0
19 Session_id ,1 ,1 ,1 ,0 ,100 ,0 , , ,SESSIONID001
20 encrypt_yn ,1 ,1 ,1 ,0 ,2 ,0 , , ,NO
21 http_url ,1 ,1 ,1 ,0 ,100 ,0 , , ,
22 screen_id ,1 ,1 ,1 ,0 ,13 ,0 , , ,SCREEN0000001
23 scr_no ,1 ,1 ,1 ,0 ,30 ,0 , , ,000000000100000000020000000003
24 scr_dsc ,1 ,1 ,1 ,0 ,100 ,0 , , ,
25 usr_id ,1 ,1 ,1 ,0 ,10 ,0 , , ,USER000001
26 ip_addr ,1 ,1 ,1 ,0 ,47 ,0 , , ,
27 ip_mac ,1 ,1 ,1 ,0 ,12 ,0 , , ,
28 com_code ,1 ,1 ,1 ,0 ,4 ,0 , , ,EACT
29 head_code ,1 ,1 ,1 ,0 ,7 ,0 , , ,EACT001
30 dept_cd ,1 ,1 ,1 ,0 ,7 ,0 , , ,ELINK01
31 conn_tp ,1 ,1 ,1 ,0 ,2 ,0 , , ,CH
32 Inter_chn ,1 ,1 ,1 ,0 ,2 ,0 , , ,EA
33 recv_tm ,1 ,1 ,1 ,0 ,17 ,0 , , ,20220928000000000
34 send_tm ,1 ,1 ,1 ,0 ,17 ,0 , , ,
35 return_gubun ,1 ,1 ,1 ,0 ,1 ,0 , , ,S
36 return_value ,1 ,1 ,1 ,0 ,1 ,0 , , ,
37 msg_id ,1 ,1 ,1 ,0 ,7 ,0 , , ,
38 msg_nm ,1 ,1 ,1 ,0 ,250 ,0 , , ,
39 filler ,1 ,1 ,1 ,0 ,125 ,0 , , ,
40 bizData ,1 ,9 ,0 ,0 ,0 ,0 , , ,
@@ -1,11 +0,0 @@
layout.file.type=CSV
layout.file.path=./resources/standard-layout-sample.csv
mapper.class=com.eactive.eai.message.test.TestInterfaceMapper
mapper.definition=./resources/standard-message-mapping-config.properties
reader.JSON=com.eactive.eai.message.parser.JsonReader
reader.JSN=com.eactive.eai.message.parser.JsonReader
reader.UJN=com.eactive.eai.message.parser.JsonReader
reader.XML=com.eactive.eai.message.parser.XmlReader
reader.UXL=com.eactive.eai.message.parser.XmlReader
reader.ASC=com.eactive.eai.message.parser.FlatReader
reader.FLAT=com.eactive.eai.message.parser.FlatReader
@@ -1,27 +0,0 @@
# layout : StandardMessage layout definition
#layout.file.type=CSV
layout.file.type=DB
#layout.file.path=standard-layout-sbi.csv
#layout.file.path=standard-layout-elk.csv
#layout.filter.FLAT=com.eactive.eai.custom.message.FlatMessageFilterSBI
layout.filter.FLAT=com.eactive.eai.message.filter.FlatMessageFilter
# mapper : StandardMessage's fields getter/setter interface
#mapper.class=com.eactive.eai.custom.message.InterfaceMapperSBI
mapper.class=com.eactive.eai.message.service.DefaultInterfaceMapper
#mapper.definition=standard-message-mapping-config-sbi.properties
#mapper.definition=standard-message-mapping-config-elk.properties
mapper.definition=standard-message-mapping-config-elk.properties
# StandardMessage Coordinator implementation
#message.coordinator.class=com.eactive.eai.custom.message.StandardMessageCoordinatorSBI
# RequestProcessor implementation
#requestProcessor.class=com.eactive.eai.inbound.processor.RequestProcessor
# reader : parsing input data to StandardMessage
reader.JSON=com.eactive.eai.message.parser.JsonReader
reader.JSN=com.eactive.eai.message.parser.JsonReader
reader.UJN=com.eactive.eai.message.parser.JsonReader
reader.XML=com.eactive.eai.message.parser.XmlReader
reader.UXL=com.eactive.eai.message.parser.XmlReader
reader.ASC=com.eactive.eai.message.parser.FlatReader
reader.FLAT=com.eactive.eai.message.parser.FlatReader
encode.flat=euc-kr
encode.xml=utf-8
@@ -1,16 +0,0 @@
# layout : StandardMessage layout definition
layout.file.type=DB
layout.db.testLayoutName=
layout.file.path=/development/intellij/elink-4.5/elink-online-multi/resources/standard-layout.csv
# mapper : StandardMessage's fields getter/setter interface
mapper.class=com.eactive.eai.message.service.DefaultInterfaceMapper
mapper.definition=/development/intellij/elink-4.5/elink-online-multi/resources/standard-message-mapping-config-elk.properties
# reader : parsing input data to StandardMessage
reader.JSON=com.eactive.eai.message.parser.JsonReader
reader.JSN=com.eactive.eai.message.parser.JsonReader
reader.UJN=com.eactive.eai.message.parser.JsonReader
reader.XML=com.eactive.eai.message.parser.XmlReader
reader.UXL=com.eactive.eai.message.parser.XmlReader
reader.ASC=com.eactive.eai.message.parser.FlatReader
reader.FLAT=com.eactive.eai.message.parser.FlatReader
@@ -1,26 +0,0 @@
REQ_SYS_CODE=commonHeader.firstReqSystemCode
CHANNEL_TYPE_CD=
CHANNEL_DETAIL_CD=
SEND_TIME=
GUID=commonHeader.globalId
SYSTEM_TYPE=
RECV_TIME=
RETURN_VALUE=
GUID_ORG=
GUID_SEQ=commonHeader.traceSeqNo
SERVICE_ID=commonHeader.serviceCode
RETURN_SERVICE_ID=
INTERFACE_ID=commonHeader.serviceCode
SESSION_ID=
SEND_RECV_DIVISION=commonHeader.reqResTypeCode
IN_EX_DIVISION=
OPERATION_ENV=
FIRST_REQ_IP=commonHeader.firstReqSystemIp
RECOVER_YN=
INST_CODE=
TIMEOUT=
ERROR_CODE=commonHeader.msgList[0].resultCode
ERROR_MSG=commonHeader.msgList[0].resultMsg
USER_ID=
RESPONSE_TYPE=
SYNC_ASYNC_TYPE=
@@ -1,29 +0,0 @@
REQ_SYS_CODE=systemHeader.DMND_SYS_CD
CHANNEL_TYPE_CD=stdcommon.chnlTycd
CHANNEL_DETAIL_CD=stdcommon.chnlDtlsClcd
SEND_TIME=stdheader.send_tm
GUID=stdheader.global_id
SYSTEM_TYPE=stdheader.Inter_chn
RECV_TIME=stdheader.recv_tm
RETURN_TYPE=stdheader.return_gubun
RETURN_VALUE=stdheader.return_value
GUID_ORG=stdcommon.ortrGuid
GUID_SEQ=stdheader.global_id
#SERVICE_ID=stdheader.service_id
SERVICE_ID=service_id
RETURN_SERVICE_ID=stdcommon.procsRsltRcmsSrvcId
INTERFACE_ID=stdheader.service_id
SESSION_ID=stdheader.Session_id
#SEND_RECV_DIVISION=stdheader.return_gubun
SEND_RECV_DIVISION=service_tn
IN_EX_DIVISION=stdcommon.hmabDvcd
OPERATION_ENV=stdcommon.sysOprtEnvDvcd
FIRST_REQ_IP=stdheader.ip_addr
RECOVER_YN=stdcommon.ortrRestrYn
INST_CODE=stdheader.com_code
TIMEOUT=stdheader.gnrzTmotTktm
ERROR_CODE=stdheader.msg_id
ERROR_MSG=stdheader.msg_nm
USER_ID=stdheader.usr_id
RESPONSE_TYPE=stdcommon.procsRsltDvcd
SYNC_ASYNC_TYPE=stdcommon.txSynzDvcd
@@ -1,27 +0,0 @@
REQ_SYS_CODE=Inter_chn
CHANNEL_TYPE_CD=
CHANNEL_DETAIL_CD=conn_tp
SEND_TIME=send_tm
GUID=global_id
SYSTEM_TYPE=service_tn
RECV_TIME=recv_tm
RETURN_TYPE=return_gubun
RETURN_VALUE=return_value
GUID_ORG=stdcommon.ortrGuid
GUID_SEQ=stdheader.global_id
SERVICE_ID=service_id
RETURN_SERVICE_ID=stdcommon.procsRsltRcmsSrvcId
INTERFACE_ID=stdheader.service_id
SESSION_ID=Session_id
SEND_RECV_DIVISION=service_tn
IN_EX_DIVISION=stdcommon.hmabDvcd
OPERATION_ENV=stdcommon.sysOprtEnvDvcd
FIRST_REQ_IP=ip_addr
RECOVER_YN=stdcommon.ortrRestrYn
INST_CODE=stdheader.com_code
TIMEOUT=stdheader.gnrzTmotTktm
ERROR_CODE=msg_id
ERROR_MSG=msg_nm
USER_ID=usr_id
RESPONSE_TYPE=stdcommon.procsRsltDvcd
SYNC_ASYNC_TYPE=stdcommon.txSynzDvcd
@@ -1,26 +0,0 @@
REQ_SYS_CODE=Inter_chn
CHANNEL_TYPE_CD=
CHANNEL_DETAIL_CD=conn_tp
SEND_TIME=send_tm
GUID=global_id
SYSTEM_TYPE=service_tn
RECV_TIME=recv_tm
RETURN_VALUE=return_value
GUID_ORG=stdcommon.ortrGuid
GUID_SEQ=stdheader.global_id
SERVICE_ID=service_id
RETURN_SERVICE_ID=stdcommon.procsRsltRcmsSrvcId
INTERFACE_ID=stdheader.service_id
SESSION_ID=Session_id
SEND_RECV_DIVISION=service_tn
IN_EX_DIVISION=return_gubun
OPERATION_ENV=stdcommon.sysOprtEnvDvcd
FIRST_REQ_IP=ip_addr
RECOVER_YN=stdcommon.ortrRestrYn
INST_CODE=stdheader.com_code
TIMEOUT=stdheader.gnrzTmotTktm
ERROR_CODE=msg_id
ERROR_MSG=msg_nm
USER_ID=usr_id
RESPONSE_TYPE=stdcommon.procsRsltDvcd
SYNC_ASYNC_TYPE=stdcommon.txSynzDvcd
@@ -21,6 +21,9 @@ import com.eactive.eai.adapter.http.dynamic.HttpDynamicInAdapterManager;
import com.eactive.eai.adapter.http.dynamic.HttpDynamicInAdapterUri;
import com.eactive.eai.common.stdmessage.STDMessageManager;
import com.eactive.eai.common.stdmessage.STDMsgInfoAddOnVO;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
public class ApiRequestBodyFilter extends OncePerRequestFilter {
@@ -32,17 +35,12 @@ public class ApiRequestBodyFilter extends OncePerRequestFilter {
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
System.out.println("ApiRequestBodyFilter : " + request.getRequestURI());
if (!isTarget(request)) {
filterChain.doFilter(request, response);
return;
}
String encoding = getInboundGroupAdapterEncoding(request);
//원본 바디를 byte[]로 읽기 (개행 포함 그대로) 왜? 뒤에 필터에서 HMAC값 계산할수도 있어서 변조되면 안됨. 개행문자도 그대로 가야함.
byte[] rawBody = readBodyAsBytes(request);
@@ -54,14 +52,16 @@ public class ApiRequestBodyFilter extends OncePerRequestFilter {
byte[] finalBody = rawBody;
try {
if(isJsonArray(rawBody)) {
String encoding = getInboundGroupAdapterEncoding(request);
String bodyStr = new String(rawBody, encoding);
Object json = JSONValue.parse(bodyStr);
String bodyStr = new String(rawBody, encoding);
Object json = JSONValue.parse(bodyStr);
if (json instanceof JSONArray) {
bodyStr = DJB_ROOTLESS_ARRAY + bodyStr + "}";
finalBody = bodyStr.getBytes(encoding);
}
if (json instanceof JSONArray) {
bodyStr = DJB_ROOTLESS_ARRAY + bodyStr + "}";
finalBody = bodyStr.getBytes(encoding);
}
}
} catch (Exception e) {
// JSON 파싱 실패 시 원본 유지
@@ -74,6 +74,14 @@ public class ApiRequestBodyFilter extends OncePerRequestFilter {
filterChain.doFilter(wrapped, response);
}
public static boolean isJsonArray(byte[] json) {
try (JsonParser parser = new JsonFactory().createParser(json)) {
return parser.nextToken() == JsonToken.START_ARRAY;
} catch (Exception e) {
return false;
}
}
private boolean isTarget(HttpServletRequest request) {
String uri = request.getRequestURI();
@@ -1,7 +1,6 @@
package com.eactive.eai.adapter.controller;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
@@ -9,13 +8,10 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
// jwhong
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -23,24 +19,23 @@ import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.adapter.AdapterPropManager;
import com.eactive.eai.adapter.AdapterVO;
import com.eactive.eai.adapter.handler.AdapterErrorMessageHandler;
import com.eactive.eai.adapter.handler.AdapterErrorMessageHandlerFactory;
import com.eactive.eai.adapter.http.HttpStatusException;
import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey;
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey;
import com.eactive.eai.adapter.http.dynamic.HttpDynamicInAdapterManager;
import com.eactive.eai.adapter.http.dynamic.HttpDynamicInAdapterUri;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilter;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilterFactory;
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException;
import com.eactive.eai.adapter.service.DJErpApiAdapterService;
import com.eactive.eai.common.TransactionContextKeys;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.stdmessage.STDMessageManager;
import com.eactive.eai.common.stdmessage.STDMsgInfoAddOnVO;
import com.eactive.eai.common.util.DatetimeUtil;
import com.eactive.eai.common.util.InboundErrorLogger;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageUtil;
import com.eactive.eai.common.util.TxFileLogger;
import com.eactive.eai.common.util.TxSiftContext;
import com.eactive.eai.common.util.UUIDGenerator;
import com.eactive.eai.inbound.error.InboundErrorInfoVO;
@@ -57,7 +52,16 @@ public class DJErpApiAdapterController implements HttpAdapterServiceKey {
* @See com.eactive.eai.authserver.config.AuthorizationServerConfig.configure(AuthorizationServerEndpointsConfigurer
* endpoints)
*/
@RequestMapping(value = { "/dj/{path:^(?!oauth).*$}", "/dj/{path:^(?!oauth).*$}/**" })
@RequestMapping(value = {
"/dj/{path:^(?!oauth).*$}", "/dj/{path:^(?!oauth).*$}/**",
"/kp/{path:^(?!oauth).*$}", "/kp/{path:^(?!oauth).*$}/**",
"/kkb/{path:^(?!oauth).*$}", "/kkb/{path:^(?!oauth).*$}/**",
"/nf/{path:^(?!oauth).*$}", "/nf/{path:^(?!oauth).*$}/**",
"/bsd/{path:^(?!oauth).*$}", "/bsd/{path:^(?!oauth).*$}/**",
"/tss/{path:^(?!oauth).*$}", "/tss/{path:^(?!oauth).*$}/**",
"/tsb/{path:^(?!oauth).*$}", "/tsb/{path:^(?!oauth).*$}/**",
"/shb/{path:^(?!oauth).*$}", "/shb/{path:^(?!oauth).*$}/**",
})
public ResponseEntity<String> callApi(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
throws Exception {
// /ONLWeb/api/v1/public/getUserInfo.svc
@@ -101,129 +105,49 @@ public class DJErpApiAdapterController implements HttpAdapterServiceKey {
MediaType mediaType = MediaType.valueOf("application/json;charset=" + encode);
String errorResponseFormat = httpProp.getProperty(ERROR_RESPONSE_FORMAT);
String responseType = httpProp.getProperty(RESPONSE_TYPE, "SYNC");
ResponseEntity responseEntity = null;
ResponseEntity<String> responseEntity = null;
Properties transactionProp = new Properties();
String uuid = UUIDGenerator.getUUID().toString().replaceAll("-", "");
transactionProp.setProperty(TransactionContextKeys.TRANSACTION_UUID, uuid);
TxSiftContext.begin(uuid);
// jwhong, put api received time, eaiSvcCode
transactionProp.put(INBOUND_REQUESTED_TIME, receivedTimeStr);
// ** jwhong TSEAIHS04의 api full path와 비교하여 adapter를 가져온다
// String bzwkSvcKeyName = ""; // Adapter Group별 Action Class에 따라 구성이 달라짐. 예)
// // _AGW_IN_RST_SyS:POST/account/{acc_no}
// String adapterGrpName = ""; // Adapter Group명 예) _AGW_IN_RST_SyS : API_PATH(/api/test)
String apiSvcCode = ""; // eaiSvcCd 예) LONNCHCON00005S2
String apiFullPathKey = ""; // 예) POST|/api/test/account/list, POST|/api/test/account/{acc_no}
Map<String, String> pathVariables = null;
try {
// PathVariable(ex:/api/test/account/{acc_no}) 대응 및 DAO조회 제거.
// /api/test/account/1234567 호출시 /api/test/account/{acc_no} API 로 식별.
// String methodAndUri = getRequestRuledPath(servletRequest, apiUri, adapterVO, transactionProp);
String methodAndUri = servletRequest.getMethod() + "|" + apiUri;
STDMessageManager manager = STDMessageManager.getInstance();
STDMsgInfoAddOnVO stdMsgInfo = manager.getStdMsgInfoAddOn(methodAndUri);
// bzwkSvcKeyName = stdMsgInfo.getBzwksvckeyname();
apiSvcCode = stdMsgInfo.getEaiSvcCd();
transactionProp.put(API_SERVICE_CODE, apiSvcCode);
// adapterGrpName = stdMsgInfo.gAdapterGroupName();
apiFullPathKey = stdMsgInfo.getApiFullPath();
if (STDMessageManager.isPathVariable(apiFullPathKey)) {
pathVariables = new AntPathMatcher().extractUriTemplateVariables(apiFullPathKey, methodAndUri);
}
// adptUri = findAdptUri(apiUri, HttpDynamicInAdapterManager.getInstance(), adapterGrpName);
} catch (Exception e) {
// adptUri = null;
}
// ***
if (pathVariables != null) {
transactionProp.put(INBOUND_PATH_VARIABLES, pathVariables);
}
String responseData = "";
try {
String responseData = service.callApi(servletRequest, servletResponse, httpProp, adapterGroupVO, adapterVO,
responseData = service.callApi(servletRequest, servletResponse, httpProp, adapterGroupVO, adapterVO,
transactionProp);
// if (RESPONSE_TYPE_ASYNC.equals(responseType)) { // table의 값이 ASYNC 로 들어가 있는데
// response_type_async는 ASYN 로 되어 있어 아래처럼 비교함 jwhong 2025
if ("ASYNC".equals(responseType)) {
// responseEntity = ResponseEntity.ok("dummy"); // comment by jwhong
// servletResponse.addHeader("traceId", responseData); // uuid를 response header에
servletResponse.addHeader("traceId",
transactionProp.getProperty(TransactionContextKeys.TRANSACTION_UUID)); // uuid를 response header에
int httpStatus = servletResponse.getStatus();
if (httpStatus == 200) {
// 업체별 aync response message 가 다르다.
String asyncMsgStyle = httpProp.getProperty("ASYNC_RTNMSG_TYPE", "");
String responseBody = "";
boolean encryptAsyncAckApply = StringUtils
.equalsIgnoreCase(httpProp.getProperty("ASYNC_ENCRYPT_ACK", "N"), "Y");
if (asyncMsgStyle == null || asyncMsgStyle.trim().isEmpty()) {
responseBody = makeResponseBodyMsg();
} else {
responseBody = asyncMsgStyle;
}
if (encryptAsyncAckApply) {
responseBody = service.doPostEncryption(responseBody, transactionProp, servletRequest);
}
responseEntity = ResponseEntity.status(httpStatus).contentType(mediaType).body(responseBody);
// jwhong
} else {
responseEntity = ResponseEntity.status(httpStatus).contentType(mediaType).body(responseData);
}
servletResponse.addHeader("traceId",
transactionProp.getProperty(TransactionContextKeys.TRANSACTION_UUID)); // uuid를 response header에
int httpStatus = servletResponse.getStatus();
if (httpStatus != 200) {
responseEntity = ResponseEntity.status(httpStatus).contentType(mediaType).body(responseData);
} else {
// responseEntity = ResponseEntity.ok().contentType(mediaType).body(responseData);
// 버즈빌 포인트 적립 처리하기 위하여 정상응답이더라도 응답코드(apiRsltCd) 값이 200이 아닌 경우 처리를 위하여 수정
// Filter에서 설정한 response status값을 responseEntity 생성시 적용 modify by lwk 2025.03.24
servletResponse.addHeader("traceId",
transactionProp.getProperty(TransactionContextKeys.TRANSACTION_UUID)); // uuid를 response header에
int httpStatus = servletResponse.getStatus();
if (httpStatus != 200) {
responseEntity = ResponseEntity.status(httpStatus).contentType(mediaType).body(responseData);
} else {
responseEntity = ResponseEntity.ok().contentType(mediaType).body(responseData);
}
responseEntity = ResponseEntity.ok().contentType(mediaType).body(responseData);
}
} catch (Exception e) {
logger.error(adapterGroupName + "-" + adapterName + ">>" + e.getMessage(), e);
String errorMsg = null;
if( e instanceof HttpStatusException ) {
errorMsg = genErrorResponseMessage(adapterGroupName, adapterName,
transactionProp, e, adptMsgType, encode, errorResponseFormat);
if (e instanceof HttpStatusException) {
logger.warn("ApiAdapterController] " + adapterGroupName + "-" + adapterName + ">>" + e.getMessage());
HttpStatusException e1 = (HttpStatusException) e;
errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode,
MessageUtil.ERROR_CODE_AP_ERROR, e1.getMessage(), errorResponseFormat);
responseEntity = ResponseEntity.status(e1.getStatus()).contentType(mediaType).body(errorMsg);
}
else if( e instanceof JwtAuthException )
{
} else if (e instanceof JwtAuthException) {
logger.error(adapterGroupName + "-" + adapterName + ">>" + e.getMessage(), e);
errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode,
MessageUtil.ERROR_CODE_AUTH_FAIL, e.getMessage(), errorResponseFormat);
responseEntity = ResponseEntity.status(HttpStatus.UNAUTHORIZED).contentType(mediaType).body(errorMsg);
}
else
{
} else {
logger.error(adapterGroupName + "-" + adapterName + ">>" + e.getMessage(), e);
errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode,
MessageUtil.ERROR_CODE_AP_ERROR, e.getMessage(), errorResponseFormat);
responseEntity = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(mediaType)
.body(errorMsg);
responseEntity = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(mediaType).body(errorMsg);
}
String postFilterNames = httpProp.getProperty("POST_FILTERS","");
if( postFilterNames.contains("HMAC_SHA256") ) {
HttpAdapterFilter filter = HttpAdapterFilterFactory.createFilter("HMAC_SHA256");
filter.doPostFilter(adapterGroupName, postFilterNames, errorMsg, transactionProp, servletRequest, servletResponse);
}
responseData = errorMsg;
} finally {
/**
@@ -231,31 +155,39 @@ public class DJErpApiAdapterController implements HttpAdapterServiceKey {
* 추후 더 좋은방법이 생길경우 개선 요망
*/
try {
servletRequest.setAttribute(TransactionContextKeys.TRANSACTION_PROP, transactionProp);
if (!"ASYNC".equals(responseType)) {
String uuid = transactionProp.getProperty(TransactionContextKeys.TRANSACTION_UUID);
String url = transactionProp.getProperty(HttpClientAdapterServiceKey.INBOUND_EXTURI);
String method = transactionProp.getProperty(HttpClientAdapterServiceKey.INBOUND_METHOD);
int httpStatusCode = servletResponse.getStatus();
Map<Object, Object> headerMap = new HashMap<>();
// 응답 헤더 로깅
for (String headerName : servletResponse.getHeaderNames()) {
String headerValue = servletResponse.getHeader(headerName);
logger.debug(String.format("httpHeader logging headerKey=%s, headerValue=%s",
headerName, headerValue));
headerMap.put(headerName, headerValue);
}
//HttpAdapterExtraLogUtil.insertHttpAdapterExtraLog(uuid, 400, adapterGroupName,adapterName, headerMap, url, method, httpStatusCode);
}
TxFileLogger.logTxFile(transactionProp, responseData, "[IN_SEND]");
servletRequest.setAttribute(TransactionContextKeys.TRANSACTION_PROP, transactionProp);
} catch (Exception e) {
logger.warn("http header db logging fail.", e);
} finally {
TxSiftContext.end();
}
}
return responseEntity;
}
private String genErrorResponseMessage(String adapterGroupName, String adapterName,
Properties callProp, Throwable e, String adptMsgType, String encode, String errorResponseFormat) {
String errorHandlerClass = AdapterPropManager.getInstance().getProperty(adapterName, "ERR_MSG_HANDLER");
if (StringUtils.isNotBlank(errorHandlerClass)) {
if (logger.isInfo())
logger.info("ExceptionHandler] errorSyncSend ERR_MSG_HANDLER=" + errorHandlerClass);
AdapterErrorMessageHandler handler = AdapterErrorMessageHandlerFactory.createHandler(errorHandlerClass);
if (handler != null) {
Object resposne;
try {
resposne = handler.generateNonStandardInboundErrorResponseMessage(adapterGroupName, adapterName,
callProp, null, null, e);
return (String)resposne;
} catch (Exception e1) {
logger.warn("AdapterErrorMessageHandler error.", e);
// handler 실패시 아래에서 처리한
}
}
}
return MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode,
MessageUtil.ERROR_CODE_AP_ERROR, e.getMessage(), errorResponseFormat);
}
/**
* url에서 뒤쪽 /이후를 제거하면서 찾는다.<br>
@@ -335,21 +267,21 @@ public class DJErpApiAdapterController implements HttpAdapterServiceKey {
InboundErrorLogger.error(errorInfoVO);
}
private String makeResponseBodyMsg() {
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("result", 1);
Map<String, Object> map = new HashMap<>();
map.put("code", "200");
map.put("data", dataMap);
map.put("message", "정상 처리 되었습니다.");
JSONObject json = new JSONObject();
json.putAll(map);
return json.toJSONString();
}
// private String makeResponseBodyMsg() {
//
// Map<String, Object> dataMap = new HashMap<>();
// dataMap.put("result", 1);
// Map<String, Object> map = new HashMap<>();
//
// map.put("code", "200");
// map.put("data", dataMap);
// map.put("message", "정상 처리 되었습니다.");
//
// JSONObject json = new JSONObject();
// json.putAll(map);
//
// return json.toJSONString();
// }
/*
* private String makeResponseBodyMsg(String asyncMsgStyle) {
@@ -1,18 +1,56 @@
package com.eactive.eai.adapter.service;
import java.io.IOException;
import java.io.StringWriter;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.mina.common.ByteBuffer;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;
import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterPropManager;
import com.eactive.eai.adapter.AdapterVO;
import com.eactive.eai.adapter.Keys;
import com.eactive.eai.adapter.http.HttpMemoryLogger;
import com.eactive.eai.adapter.http.HttpMethodType;
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceSupport;
import com.eactive.eai.adapter.http.dynamic.filter.ApiKeyExtractFilter;
import com.eactive.eai.adapter.http.filter.AbstractCryptoFilter;
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthFilter;
import com.eactive.eai.common.context.ElinkTransactionContext;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.message.MessageType;
import com.eactive.eai.common.util.CommonLib;
import com.eactive.eai.common.util.JSONUtils;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.TxFileLogger;
import com.eactive.eai.common.util.XMLUtils;
import com.eactive.eai.inbound.action.ActionFactory;
import com.eactive.eai.inbound.action.RequestAction;
import com.eactive.eai.inbound.processor.Processor;
@@ -21,43 +59,11 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.mina.common.ByteBuffer;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.JSONParser;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLDecoder;
import java.util.*;
//for encrypt/decrypt jwhong
import com.eactive.eai.authserver.service.OAuth2Manager;
import com.kjbank.encrypt.exchange.crypto.AES256Cipher;
import com.kjbank.encrypt.exchange.crypto.AESCipher;
import com.kjbank.encrypt.exchange.crypto.AES256GCMCipher;
import java.nio.charset.StandardCharsets;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import org.springframework.security.oauth2.provider.ClientDetails;
import com.nimbusds.jwt.SignedJWT;
import com.eactive.eai.common.context.ElinkTransactionContext;
@Service
public class DJErpApiAdapterService extends HttpAdapterServiceSupport {
static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
static Logger siftLogger = Logger.getLogger(Logger.LOGGER_SIFT);
public static final String HEADER_GROUP = "HEADER_GROUP";
public static final String HTTP_STATUS = "HTTP_STATUS"; // jwhong
@@ -65,17 +71,12 @@ public class DJErpApiAdapterService extends HttpAdapterServiceSupport {
public static final String HEADER_KEYS = "HEADER_KEYS";
public static final String PROPERTIES_NAME_HTTP_REQUEST_METHOD = "httpRequestMethod";
private static final String JSON_CONTENT_TYPE = "application/json";
private static final String JSON_FIELD_NAME = "json-body";
private static final String FILE_GROUP_NAME = "image-file";
private static final String UPLOAD_ROOT_PATH = "UPLOAD_ROOT_PATH";
public static final String PAYLOAD_PARAM_NAME_CLIENT_ID = "client_id"; // jwhong
private boolean encryptResponseApply; // inbound에 대한 응답 암호화 여부 flag
public String callApi(HttpServletRequest request, HttpServletResponse response, Properties httpProp, AdapterGroupVO adapterGroupVO, AdapterVO adapterVO, Properties transactionProp) throws Exception {
public static final String PAYLOAD_PARAM_NAME_CLIENT_ID = "client_id"; // jwhong
public String callApi(HttpServletRequest request, HttpServletResponse response, Properties httpProp,
AdapterGroupVO adapterGroupVO, AdapterVO adapterVO, Properties transactionProp) throws Exception {
int traceLevel = 0;
AdapterPropManager manager = null;
String adptGrpName = adapterGroupVO.getName();
String adptName = adapterVO.getName();
@@ -92,10 +93,11 @@ public class DJErpApiAdapterService extends HttpAdapterServiceSupport {
String paramValue = null;
String adptMsgType = null;
Properties inboundHeaderProp = getHeaders(request);
transactionProp.put(INBOUND_METHOD, request.getMethod());
transactionProp.put(INBOUND_URI, request.getRequestURI());
transactionProp.put(INBOUND_QUERY_STRING, StringUtils.defaultString(request.getQueryString()));
transactionProp.put(INBOUND_HEADER, getHeaders(request));
transactionProp.put(INBOUND_HEADER, inboundHeaderProp);
transactionProp.put(INBOUND_EXTPARAMS, StringUtils.defaultString(request.getQueryString()));
if (StringUtils.equals(adapterVO.getAdapterGroupVO().getType(), Keys.TYPE_REST)
|| StringUtils.equals(adapterVO.getAdapterGroupVO().getType(), Keys.TYPE_HTTP_CUSTOM)) {
@@ -130,13 +132,13 @@ public class DJErpApiAdapterService extends HttpAdapterServiceSupport {
transactionProp.put(ENC_PATHS, httpProp.getProperty(ENC_PATHS, ""));
transactionProp.put(ENCRYPT_ALGORITHM, httpProp.getProperty(ENCRYPT_ALGORITHM, "")); //jwhong
if (getHeaders(request).get(HEADER_NAME_CLIENT_ID) != null) { // jwhong
transactionProp.put(HEADER_NAME_CLIENT_ID, getHeaders(request).get(HEADER_NAME_CLIENT_ID));
if (inboundHeaderProp.get(HEADER_NAME_CLIENT_ID) != null) { // jwhong
transactionProp.put(HEADER_NAME_CLIENT_ID, inboundHeaderProp.get(HEADER_NAME_CLIENT_ID));
}
transactionProp.put(ENCRYPT_BASE_TYPE, httpProp.getProperty(ENCRYPT_BASE_TYPE, "")); //jwhong
// //transactionProp.put(INBOUND_TOKEN, getHeaders(request).get(INBOUND_TOKEN)); // jwhong
// transactionProp.put(INBOUND_TOKEN, getHeaders(request).get(INBOUND_TOKEN) != null ? getHeaders(request).get(INBOUND_TOKEN) : ""); //jwhong , null 이면 default로 "" put
String inboundToken = getHeaders(request).getOrDefault(INBOUND_TOKEN, "").toString();
String inboundToken = inboundHeaderProp.getOrDefault(INBOUND_TOKEN, "").toString();
if (StringUtils.isNotBlank(inboundToken) && StringUtils.startsWith(inboundToken, "Bearer ")) {
inboundToken = inboundToken.substring(7);
}
@@ -146,8 +148,11 @@ public class DJErpApiAdapterService extends HttpAdapterServiceSupport {
transactionProp.put(AbstractCryptoFilter.PROP_MODULE_NAME, httpProp.getProperty(AbstractCryptoFilter.PROP_MODULE_NAME, ""));
transactionProp.put(HEADER_GROUP, headerGroupName);
transactionProp.put(HEADER_KEYS, relayRequestHeaderKeys);
// SEED 컬럼암호하 시 Key로 사용함
String seedkey = getHeaders(request).getOrDefault("x-obp-partnercode", "").toString();
String seedkey = inboundHeaderProp.getOrDefault("x-obp-partnercode", "").toString();
ElinkTransactionContext.setSeedKey(seedkey);
try {
@@ -226,47 +231,47 @@ public class DJErpApiAdapterService extends HttpAdapterServiceSupport {
logger.debug("HttpAdapterServiceRest] RECV (" + adptGrpName + ") = [" + paramValue + "]\n"
+ CommonLib.getDumpMessage(paramValue.getBytes(encode)));
}
} else {
if (request.getContentLength() > 0) {
ServletInputStream sis = request.getInputStream();
ByteBuffer bb = ByteBuffer.allocate(1024).setAutoExpand(true);
int i = 0;
byte[] cbuf = new byte[1024];
while ((i = sis.read(cbuf, 0, 1024)) != -1) {
if (i == 1024) {
bb.put(cbuf);
} else {
byte[] tail = new byte[i];
System.arraycopy(cbuf, 0, tail, 0, i);
bb.put(tail);
} else {
if (request.getContentLength() > 0) {
ServletInputStream sis = request.getInputStream();
ByteBuffer bb = ByteBuffer.allocate(1024).setAutoExpand(true);
int i = 0;
byte[] cbuf = new byte[1024];
while ((i = sis.read(cbuf, 0, 1024)) != -1) {
if (i == 1024) {
bb.put(cbuf);
} else {
byte[] tail = new byte[i];
System.arraycopy(cbuf, 0, tail, 0, i);
bb.put(tail);
}
}
byte[] data = new byte[bb.position()];
bb.position(0);
bb.get(data);
String bodyEncode = encode;
String contentTypeHeader = request.getContentType();
if (StringUtils.isNotBlank(contentTypeHeader)) {
try {
MediaType mediaType = MediaType.parseMediaType(contentTypeHeader);
if (mediaType.getCharset() != null) {
bodyEncode = mediaType.getCharset().name();
}
} catch (Exception ignored) {}
}
paramValue = new String(data, bodyEncode);
if (traceLevel >= 3) {
HttpMemoryLogger.txlog(adptGrpName + adptName,
"RECV " + "[" + paramValue + "]" + CommonLib.getDumpMessage(data));
}
if (logger.isDebug()) {
logger.debug("HttpAdapterServiceRest] RECV (" + adptGrpName + ") = [" + paramValue + "]\n"
+ CommonLib.getDumpMessage(data));
}
}
}
byte[] data = new byte[bb.position()];
bb.position(0);
bb.get(data);
String bodyEncode = encode;
String contentTypeHeader = request.getContentType();
if (StringUtils.isNotBlank(contentTypeHeader)) {
try {
MediaType mediaType = MediaType.parseMediaType(contentTypeHeader);
if (mediaType.getCharset() != null) {
bodyEncode = mediaType.getCharset().name();
}
} catch (Exception ignored) {}
}
paramValue = new String(data, bodyEncode);
if (traceLevel >= 3) {
HttpMemoryLogger.txlog(adptGrpName + adptName,
"RECV " + "[" + paramValue + "]" + CommonLib.getDumpMessage(data));
}
if (logger.isDebug()) {
logger.debug("HttpAdapterServiceRest] RECV (" + adptGrpName + ") = [" + paramValue + "]\n"
+ CommonLib.getDumpMessage(data));
}
}
}
if (paramValue == null) { // parameter가 없는 경우때문에 처리
paramValue = "";
@@ -284,6 +289,8 @@ public class DJErpApiAdapterService extends HttpAdapterServiceSupport {
} else {
message = paramValue;
}
TxFileLogger.logTxFile(transactionProp, message, "[IN_RECV]");
if (logger.isDebug()) {
String[] msgArgs = new String[2];
@@ -298,47 +305,52 @@ public class DJErpApiAdapterService extends HttpAdapterServiceSupport {
// HttpHeaders responseHeaders = new HttpHeaders();
// responseHeaders.setContentType(MediaType.valueOf("application/json;charset=" + encode));
// HEADER_GROUP 셋팅
if (MessageType.JSON.equals(adptMsgType) && StringUtils.isNotBlank(headerGroupName)
&& StringUtils.isNotBlank(relayRequestHeaderKeys)) {
JSONObject jsonMessage = (JSONObject) JSONValue.parse(message);
JSONObject headerJson = new JSONObject();
if (StringUtils.equalsIgnoreCase(relayRequestHeaderKeys, "ALL")) {
for (Enumeration<String> e = request.getHeaderNames(); e.hasMoreElements(); ) {
String key = e.nextElement();
headerJson.put(key, request.getHeader(key));
}
} else {
String[] relayKeyArr = org.springframework.util.StringUtils
.tokenizeToStringArray(relayRequestHeaderKeys, ",");
for (String key : relayKeyArr) {
String headerValue = request.getHeader(key);
if (StringUtils.isNotBlank(headerValue)) {
headerJson.put(key, headerValue);
}
}
}
if (headerJson.size() > 0) {
jsonMessage.put(headerGroupName, headerJson);
message = jsonMessage.toJSONString();
}
}
if (message == null) {
message = "";
}
// if (MessageType.JSON.equals(adptMsgType) && StringUtils.isNotBlank(headerGroupName)
// && StringUtils.isNotBlank(relayRequestHeaderKeys)) {
// JSONObject jsonMessage = (JSONObject) JSONValue.parse(message);
// JSONObject headerJson = new JSONObject();
// if (StringUtils.equalsIgnoreCase(relayRequestHeaderKeys, "ALL")) {
// for (Enumeration<String> e = request.getHeaderNames(); e.hasMoreElements(); ) {
// String key = e.nextElement();
// headerJson.put(key, request.getHeader(key));
// }
// } else {
// String[] relayKeyArr = org.springframework.util.StringUtils
// .tokenizeToStringArray(relayRequestHeaderKeys, ",");
//
// for (String key : relayKeyArr) {
// String headerValue = request.getHeader(key);
// if (StringUtils.isNotBlank(headerValue)) {
// headerJson.put(key, headerValue);
// }
// }
// }
//
// if (headerJson.size() > 0) {
// jsonMessage.put(headerGroupName, headerJson);
// message = jsonMessage.toJSONString();
// }
// }
Object reqObject = assignHeaderGroupRequestHeaders(adptGrpName, adptName, message,
transactionProp, request, response, adptMsgType);
// 위치변경 : 가공되지 않은 Body값을 저장하기 위하여 위쪽으로 이동.
// transactionProp.put(INBOUND_REQUEST_MESSAGE, message);
// 로컬 서비스 호출 ,encoding 처리 추가
String result = (String) service(adptGrpName, adptName, message, transactionProp, request, response);
ApiKeyExtractFilter apiKeyExtractor = new ApiKeyExtractFilter();
apiKeyExtractor.doPreFilter(adptGrpName, adptName, reqObject, transactionProp, request, response);
String result = (String) service(adptGrpName, adptName, reqObject, transactionProp, request, response);
// bypass만 필요
applyOutboundResponseHeaders(transactionProp, response);
if (logger.isDebug()) {
result = applyHeaderGroupResponseHeaders(adptGrpName, adptName, result, transactionProp, request, response, adptMsgType);
if (logger.isDebug()) {
logger.debug("HttpAdapterServiceRest] result " + encode + " (" + adptGrpName + ") = [" + result + "]");
}
@@ -367,8 +379,116 @@ public class DJErpApiAdapterService extends HttpAdapterServiceSupport {
// if ( encryptResponseApply) {
// result = doPostEncryption(result, transactionProp, request); // jwhong Encrypt
// }
return result;
}
private Object assignHeaderGroupRequestHeaders(String adptGrpName, String adptName, Object message, Properties prop,
HttpServletRequest request, HttpServletResponse response, String adptMsgType) throws DocumentException, IOException {
// XML 지원 개발
String headerGroupName = prop.getProperty(HEADER_GROUP);
String relayRequestHeaderKeys = prop.getProperty(HEADER_KEYS);
if(StringUtils.isNotBlank(headerGroupName) && StringUtils.isNotBlank(relayRequestHeaderKeys)) {
if (MessageType.JSON.equals(adptMsgType)) {
if(message instanceof String && StringUtils.isEmpty((String)message))
message = "{}";
JSONObject jsonMessage = JSONUtils.parseJson(message);
JSONObject headerJson = JSONUtils.getChildJson(jsonMessage, headerGroupName);
if (headerJson == null)
headerJson = new JSONObject();
if (StringUtils.equalsIgnoreCase(relayRequestHeaderKeys, "ALL")) {
for (Enumeration<String> e = request.getHeaderNames(); e.hasMoreElements(); ) {
String key = e.nextElement();
headerJson.put(StringUtils.lowerCase(key), request.getHeader(key));
}
} else {
String[] relayKeyArr = org.springframework.util.StringUtils
.tokenizeToStringArray(relayRequestHeaderKeys, ",");
for (String key : relayKeyArr) {
String headerValue = request.getHeader(key);
if (StringUtils.isNotBlank(headerValue)) {
headerJson.put(StringUtils.lowerCase(key), headerValue);
}
}
}
if (headerJson.size() > 0) {
jsonMessage.put(headerGroupName, headerJson);
message = jsonMessage.toJSONString();
}
} else if(MessageType.XML.equals(adptMsgType)) {
Document document = XMLUtils.convertXmlDocument(message);
if(document != null) {
Element rootElement = document.getRootElement();
Element headerElement = rootElement.element(headerGroupName);
if(headerElement == null)
headerElement = DocumentHelper.createElement(headerGroupName);
boolean hasHeaderValues = false;
if (StringUtils.equalsIgnoreCase(relayRequestHeaderKeys, "ALL")) {
for (Enumeration<String> e = request.getHeaderNames(); e.hasMoreElements(); ) {
String key = e.nextElement();
String value = request.getHeader(key);
/*
* IBK 표준안에 따라 <{key}>{value}</{key}> 형태로 저장, KEY 는 소문자로 변경한다
* 대상 사이트의 표준안에 따라 작성 할 것
*
* HTTP 헤더 변환 예시
*
* 일반적인 HTTP 헤더 변환 예시:
* Content-Type: application/json
* X-Forwarded-For: 10.0.0.1
*
* <root>
* <data> original content </data>
* <httpHeaderGroup>
* <content-type>application/json</content-type>
* <x-forwarded-for>10.0.0.1</x-forwarded-for>
* </httpHeaderGroup>
* </root>
*/
if(StringUtils.isNotBlank(value)) {
Element headerItem = headerElement.addElement(key);
headerItem.setText(value);
hasHeaderValues = true;
}
}
} else {
String[] relayKeyArr = org.springframework.util.StringUtils
.tokenizeToStringArray(relayRequestHeaderKeys, ",");
for (String key : relayKeyArr) {
String headerValue = request.getHeader(key);
if (StringUtils.isNotBlank(headerValue)) {
String value = request.getHeader(key);
String keyName = StringUtils.lowerCase(key);
Element headerItem = headerElement.addElement(keyName);
headerItem.setText(value);
hasHeaderValues = true;
}
}
}
if (hasHeaderValues) {
rootElement.add(headerElement);
OutputFormat format = OutputFormat.createPrettyPrint();
StringWriter writer = new StringWriter();
XMLWriter xmlWriter = new XMLWriter(writer, format);
xmlWriter.write(document);
message = writer.toString();
}
}
}
}
if (message == null) {
message = "";
} // XML 지원 개발
return message;
}
/**
@@ -413,410 +533,93 @@ public class DJErpApiAdapterService extends HttpAdapterServiceSupport {
}
}
// jwhong decrypt
private String applyHeaderGroupResponseHeaders(String adptGrpName, String adptName, Object resultMessage, Properties prop,
HttpServletRequest request, HttpServletResponse response, String adptMsgType) throws Exception {
// body headergroup -> http header 세팅
String headerGroupName = prop.getProperty(ApiAdapterService.HEADER_GROUP);
if (StringUtils.isNotBlank(headerGroupName)) {
if (resultMessage instanceof Node) {
adptMsgType = MessageType.XML;
} else if (resultMessage instanceof String) {
String strMessage = (String) resultMessage;
if (StringUtils.startsWith(strMessage, "<")) {
adptMsgType = MessageType.XML;
}
} else if (resultMessage instanceof byte[]) {
String strMessage = new String((byte[]) resultMessage);
if (StringUtils.startsWith(strMessage, "<")) {
adptMsgType = MessageType.XML;
}
}
if (MessageType.JSON.equals(adptMsgType)) {
JSONObject jsonObject = JSONUtils.parseJson(resultMessage);
JSONObject headerGroup = (JSONObject)jsonObject.get(headerGroupName);
if (headerGroup != null) {
Set<Map.Entry<String, Object>> fieldEntrySet = JSONUtils.getField(headerGroup);
for (Map.Entry<String, Object> fieldEntry : fieldEntrySet) {
logger.info("header group entry : {} , {}", fieldEntry.getKey(), fieldEntry.getValue());
private String doPreDecryption(String eaiBody, Properties transactionProp, HttpServletRequest request) throws Exception {
String decryptAlgorithm = transactionProp.getProperty(ENCRYPT_ALGORITHM, "");
String xElinkClientId = transactionProp.getProperty(HEADER_NAME_CLIENT_ID, ""); // 이 값이 OAuth의 client id 값이다 . http header 에 포함되어 온다. jwhong
String encryptBaseKeyType = transactionProp.getProperty(ENCRYPT_BASE_TYPE);
//String inboundToken2 = transactionProp.getProperty(INBOUND_TOKEN, ""); // 이건 token 값이 아니고 authorization 값이다
String inboundToken = "";
String secretAES256Iv = transactionProp.getProperty("ENCRYPT_AES256_IV");
String secretAES256Key = transactionProp.getProperty("ENCRYPT_AES256_KEY");
if ( decryptAlgorithm == "" ) { // 복호화 대상이 아님
return eaiBody;
}
if (fieldEntry.getValue() instanceof String) {
if(fieldEntry.getKey().equalsIgnoreCase("content-type")) {
logger.debug("set content-type {}: {}", fieldEntry.getKey(), fieldEntry.getValue());
response.setContentType((String) fieldEntry.getValue());
} else {
logger.debug("add header {}: {}", fieldEntry.getKey(), fieldEntry.getValue());
response.addHeader(fieldEntry.getKey(), (String) fieldEntry.getValue());
}
} else {
logger.info("fieldEntry value is not String. {}", fieldEntry.getValue());
}
}
} else {
logger.info("headerGroup is null");
}
jsonObject.remove(headerGroupName);
return jsonObject.toJSONString();
} else if(MessageType.XML.equals(adptMsgType)) {
Document document = XMLUtils.convertXmlDocument(resultMessage);
if(document != null) {
Element rootElement = document.getRootElement();
Element headerGroupElement = rootElement.element(headerGroupName);
if(headerGroupElement != null) {
//헤더그룹의 모든 하위 엘리먼트를 HTTP 응답 헤더로 설정
for(Iterator<Element> it = headerGroupElement.elementIterator(); it.hasNext();) {
Element headerElement = it.next();
String name = headerElement.getName();
String value = headerElement.getTextTrim();
inboundToken = JwtTokenExtractor(request);
xElinkClientId = JwtClientIdExtractor(inboundToken); // token에서 client id를 추출함
// 암호화 key를 token 내용으로 할지 client secret 내용으로 할지 결정함. adapter property에 정의함
// ENCRYPT_ALGORITHM 을 설정했는데 ENCRYPT_BASE_TYPE을 설정안하면 Decrypt 수행시 Exception 발생함
String clientSecret = "";
if ("TOKEN".equalsIgnoreCase(encryptBaseKeyType)) {
clientSecret = inboundToken;
} else if ( "SECRETKEY".equalsIgnoreCase(encryptBaseKeyType)) {
OAuth2Manager manager = OAuth2Manager.getInstance();
ClientDetails clientDetail = manager.getClientDeatilsStore().get(xElinkClientId);
if ( clientDetail != null ) { // 여기서 not null 이라는 것은 apim oauth server에서 발급된 token 임.
// 즉 KJBank 에서 요청이 들어온 것이다.
clientSecret = clientDetail.getClientSecret();
} // 그럼 업체에서 요청이 들어오면?? 업체도 apim oauth server에서 발급된 token을 사용하는것이다.
}
byte[] decryptedMessage = null;
decryptedMessage = doInboundPreDecrypt(eaiBody, decryptAlgorithm,clientSecret,secretAES256Iv, secretAES256Key );
if (decryptedMessage == null) {
throw new Exception("[ApiAdapterService] Decrypt Error : Invalid encrypted message");
}
String resultMessage = new String(decryptedMessage, StandardCharsets.UTF_8 );
return resultMessage;
//return new String(decryptedMessage, StandardCharsets.UTF_8 );
}
// jwhong encrypt
public String doPostEncryption(String eaiBody, Properties transactionProp, HttpServletRequest request) throws Exception {
String decryptAlgorithm = transactionProp.getProperty(ENCRYPT_ALGORITHM, "");
String xElinkClientId = transactionProp.getProperty(HEADER_NAME_CLIENT_ID, ""); // 이 값이 OAuth의 client id 값이다 . http header 에 포함되어 온다. jwhong
String encryptBaseKeyType = transactionProp.getProperty(ENCRYPT_BASE_TYPE);
String inboundToken = "";
String secretAES256Iv = transactionProp.getProperty("ENCRYPT_AES256_IV");
String secretAES256Key = transactionProp.getProperty("ENCRYPT_AES256_KEY");
if ( decryptAlgorithm == "" ) { // 복호화 대상이 아님
return eaiBody;
}
inboundToken = JwtTokenExtractor(request);
xElinkClientId = JwtClientIdExtractor(inboundToken); // token에서 client id를 추출함
// 암호화 key를 token 내용으로 할지 client secret 내용으로 할지 결정함. adapter property에 정의함
// ENCRYPT_ALGORITHM 을 설정했는데 ENCRYPT_BASE_TYPE을 설정안하면 Decrypt 수행시 Exception 발생함
String clientSecret = "";
if ("TOKEN".equalsIgnoreCase(encryptBaseKeyType)) {
clientSecret = inboundToken;
} else if ( "SECRETKEY".equalsIgnoreCase(encryptBaseKeyType)) {
OAuth2Manager manager = OAuth2Manager.getInstance();
ClientDetails clientDetail = manager.getClientDeatilsStore().get(xElinkClientId);
if ( clientDetail != null ) {
clientSecret = clientDetail.getClientSecret();
if(StringUtils.isNoneBlank(value)) {
if(value.equalsIgnoreCase("content-type")) {
response.setContentType(value);
} else {
logger.debug("add header {}: {}", name, value);
response.addHeader(name, value);
}
} else {
logger.info("value is not String. {}", value);
}
}
} else {
logger.info("headerGroup is null");
}
// 헤더그룹 삭제
rootElement.remove(headerGroupElement);
return document.asXML();
}
}
}
String encryptedMessage = null;
encryptedMessage = doInboundPostEncrypt(eaiBody, decryptAlgorithm,clientSecret,secretAES256Iv, secretAES256Key );
if (encryptedMessage == null) {
throw new Exception("[ApiAdapterService] Encrypt Error : Invalid PlainText message");
} else {
logger.info("headerGroupName is blank");
}
return encryptedMessage;
//String resultMessage = new String(encryptedMessage, StandardCharsets.UTF_8 );
//return resultMessage;
}
private byte[] convertObjectToBytes(Object obj) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
return bos.toByteArray();
}
private byte[] convertObjectToBase64Bytes(Object obj) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
oos.close();
// 직렬화된 byte[] → Base64 문자열 → 다시 byte[]로 변환
String base64String = Base64.getEncoder().encodeToString(bos.toByteArray());
return base64String.getBytes(StandardCharsets.UTF_8);
}
public static Object convertBytesToObject(byte[] bytes) throws IOException, ClassNotFoundException {
try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis)) {
return ois.readObject();
}
}
private byte[] doInboundPreDecrypt(String eaiStringBody, String decryptAlgorithm, String clientSecretKey, String secretAES256Iv, String secretAES256Key) throws Exception {
byte[] decryptedMessage = null;
//String eaiStringBody = new String(eaiBody, StandardCharsets.UTF_8);
eaiStringBody = extractBodyMsg(decryptAlgorithm, eaiStringBody);
if (eaiStringBody == null) {
throw new Exception("[ApiAdapterService] Cannot decrypt Error : input is plain text");
}
//test source
logger.debug("Base64 문자열: " + eaiStringBody);
logger.debug("Base64 문자열 길이: " + eaiStringBody.length());
logger.debug("Base64 문자열 끝: " + eaiStringBody.substring(eaiStringBody.length() - 10));
// Base64 디코딩 테스트
try {
byte[] decoded = Base64.getDecoder().decode(eaiStringBody);
logger.debug("디코딩 성공, 길이: " + decoded.length);
} catch (IllegalArgumentException e) {
logger.debug("Base64 디코딩 실패: " + e.getMessage());
}
// end test source
switch (decryptAlgorithm) {
case "AES128":
case "AES128-TOSS":
try {
String key128 = clientSecretKey.substring(22,38); //togetherEncoder 경우는 substring(44,60) 이네??
//String decryptedStrMessage = AESCipher.decrypt(eaiStringBody, key128);
String decryptedStrMessage = AESCipher.decryptExistException(eaiStringBody, key128);
decryptedMessage = decryptedStrMessage.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClientAdapterServiceRest] AES128 Decryption error=" + e.getMessage());
}
break;
case "AES128-TOGETHER":
try {
String key128 = clientSecretKey.substring(44,60); //togetherEncoder 경우는 substring(44,60) 이네??
//String decryptedStrMessage = AESCipher.decrypt(eaiStringBody, key128);
String decryptedStrMessage = AESCipher.decryptExistException(eaiStringBody, key128);
decryptedMessage = decryptedStrMessage.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClientAdapterServiceRest] AES128 Decryption error=" + e.getMessage());
}
break;
case "AES256":
try {
String key = clientSecretKey.substring(10,42);
String decryptedStrMessage = AES256Cipher.decrypt(eaiStringBody, key);
decryptedMessage = decryptedStrMessage.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClientAdapterServiceRest] AES256 Decryption error=" + e.getMessage());
}
break;
case "AES256-KAKAO":
try {
String decryptedStrMessage = AES256Cipher.decrypt(eaiStringBody, secretAES256Iv, secretAES256Key);
decryptedMessage = decryptedStrMessage.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClientAdapterServiceRest] AES256 Decryption error=" + e.getMessage());
}
break;
case "AES256-TOSS":
try {
String decryptedStrMessage = AES256Cipher.decrypt(eaiStringBody, secretAES256Iv, secretAES256Key);
decryptedMessage = decryptedStrMessage.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClientAdapterServiceRest] AES256 Decryption error=" + e.getMessage());
}
break;
case "AES256GCM":
try {
byte[] key = AES256GCMCipher.generateKey();
AES256GCMCipher cipher = new AES256GCMCipher(key);
byte[] aad = "metadata".getBytes();
String decryptedStrMessage = cipher.decrypt(eaiStringBody , aad);
decryptedMessage = decryptedStrMessage.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClientAdapterServiceRest] AES256GCM Encryption error=" + e.getMessage());
}
break;
default:
try {
decryptedMessage = eaiStringBody.getBytes();
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClientAdapterServiceRest] doOutboundPostFilter Array copy error=" + e.getMessage());
}
break;
}
return decryptedMessage;
}
private String extractBodyMsg(String decryptAlgorithm, String eaiStringBody) {
String decryptedJsonKey = "";
String decryptedBodyMessage = "";
decryptedJsonKey = getJsonKey(decryptAlgorithm);
try {
JSONParser parser = new JSONParser();
JSONObject jsonObject = (JSONObject) parser.parse(eaiStringBody);
decryptedBodyMessage = (String) jsonObject.get(decryptedJsonKey);
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClient5AdapterServiceRest] extractBodyMsg error : " + e.getMessage());
}
return decryptedBodyMessage;
return (String)resultMessage;
}
private String getJsonKey(String Algorithm) {
String jsonKey = "";
switch (Algorithm) {
case "AES128":
case "AES128-TOSS":
jsonKey = "preScreeningRequest";
break;
case "AES128-TOGETHER":
jsonKey = "obpTxData";
break;
case "AES256":
jsonKey = "preScreeningRequest";
break;
case "AES256-KAKAO":
jsonKey = "encrypted_data";
break;
case "AES256-TOSS":
jsonKey = "encryptedData";
break;
case "AES256-NICEON":
jsonKey = "enc_data";
break;
case "AES256GCM":
break;
default:
break;
}
return jsonKey;
}
private String doInboundPostEncrypt(String eaiStringBody, String encryptAlgorithm, String clientSecretKey, String secretAES256Iv, String secretAES256Key) {
//byte[] encryptedMessage = null;
String encryptedStrMessage = null;
String encryptedJsonKey = "";
encryptedJsonKey = getJsonKey(encryptAlgorithm);
switch (encryptAlgorithm) {
case "AES128":
case "AES128-TOSS":
try {
String key128 = clientSecretKey.substring(22,38); //togetherEncoder 경우는 substring(44,60) 이네??
encryptedStrMessage = AESCipher.encrypt(eaiStringBody, key128);
//encryptedMessage = encryptedStrMessage.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClientAdapterServiceRest] AES128 Encryption error=" + e.getMessage());
}
break;
case "AES128-TOGETHER":
try {
String key128 = clientSecretKey.substring(44,60); //togetherEncoder 경우는 substring(44,60) 이네??
encryptedStrMessage = AESCipher.encrypt(eaiStringBody, key128);
//encryptedMessage = encryptedStrMessage.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClientAdapterServiceRest] AES128 Encryption error=" + e.getMessage());
}
break;
case "AES256":
try {
String key = clientSecretKey.substring(10,42);
encryptedStrMessage = AES256Cipher.encrypt(eaiStringBody, key);
//encryptedMessage = encryptedStrMessage.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClientAdapterServiceRest] AES256 Encryption error=" + e.getMessage());
}
break;
case "AES256-KAKAO":
try {
encryptedStrMessage = AES256Cipher.encrypt(eaiStringBody, secretAES256Iv, secretAES256Key);
//encryptedMessage = encryptedStrMessage.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClientAdapterServiceRest] AES256 Encryption error=" + e.getMessage());
}
break;
case "AES256-TOSS":
try {
encryptedStrMessage = AES256Cipher.encrypt(eaiStringBody, secretAES256Iv, secretAES256Key);
//encryptedMessage = encryptedStrMessage.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClientAdapterServiceRest] AES256 Encryption error=" + e.getMessage());
}
break;
case "AES256GCM":
try {
byte[] key = AES256GCMCipher.generateKey();
AES256GCMCipher cipher = new AES256GCMCipher(key);
byte[] aad = "metadata".getBytes();
encryptedStrMessage = cipher.encrypt(eaiStringBody , aad);
//encryptedMessage = encryptedStrMessage.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClientAdapterServiceRest] AES256GCM Encryption error=" + e.getMessage());
}
break;
default:
try {
encryptedStrMessage = eaiStringBody;
//encryptedMessage = eaiStringBody.getBytes();
} catch (Exception e) {
e.printStackTrace();
logger.error("HttpClientAdapterServiceRest] doOutboundPostFilter Array copy error=" + e.getMessage());
}
break;
}
Map<String, Object> map = new HashMap<>();
map.put(encryptedJsonKey, encryptedStrMessage);
JSONObject json = new JSONObject();
json.putAll(map);
return json.toJSONString();
//return encryptedMessage;
}
private String JwtTokenExtractor(HttpServletRequest request) {
String Token = "";
try {
Token = JwtAuthFilter.extractJWTToken(request);
} catch (Exception e) {
logger.error(e.getMessage());
}
logger.debug("Token is: " + Token);
return Token;
}
private String JwtClientIdExtractor(String inboundToken) {
String tokenClientId ="";
try {
SignedJWT signedJWT = SignedJWT.parse(inboundToken);
tokenClientId = (String) signedJWT.getJWTClaimsSet().getClaim(PAYLOAD_PARAM_NAME_CLIENT_ID);
} catch (Exception e) {
logger.error(e.getMessage());
tokenClientId = "";
}
logger.debug("Token Client ID: " + tokenClientId);
return tokenClientId;
}
// jwhong until here
private Map<String, String[]> assignParameterMap(HttpServletRequest request, String adptGrpName, String adptName,
Object requestBytes, Properties prop) {
@@ -0,0 +1,60 @@
package com.eactive.eai.agent.inflow;
import com.eactive.eai.agent.command.Command;
import com.eactive.eai.agent.command.CommandException;
import com.eactive.eai.common.inflow.AbstractInflowControlManager;
import com.eactive.eai.common.inflow.InflowControlUtil;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.custom.inflow.ClientDualInflowControlManager;
public class ReloadInflowClientControlCommand extends Command {
private static final long serialVersionUID = 1L;
public ReloadInflowClientControlCommand() {
super("ReloadInflowClientControlCommand");
}
public Object execute() throws CommandException {
Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
if (logger.isInfo())
logger.info(this.name + " is executed");
if (!(args instanceof String)) {
String rspErrorCode = "RECEAIMCM001";
String msg = makeException(rspErrorCode, null);
if (logger.isError())
logger.error(msg);
throw new CommandException(msg);
}
String keyName = (String) args;
try {
AbstractInflowControlManager base = InflowControlUtil.getInflowControlManager();
if (!(base instanceof ClientDualInflowControlManager)) {
throw new IllegalStateException("ClientDualInflowControlManager 가 활성화되지 않았습니다.");
}
ClientDualInflowControlManager manager = (ClientDualInflowControlManager) base;
if (keyName != null) {
if ("ALL".equals(keyName)) {
manager.reloadClient();
if (logger.isWarn())
logger.warn(this.name + "] all rule Reload.");
} else {
manager.reloadClient(keyName);
if (logger.isWarn())
logger.warn(this.name + "] " + keyName + " Reload.");
}
}
} catch (Exception e) {
String rspErrorCode = "RECEAIMCM002";
String msg = makeException(rspErrorCode, e);
if (logger.isError())
logger.error(msg, e);
throw new CommandException(msg);
}
return "success";
}
}
@@ -0,0 +1,50 @@
package com.eactive.eai.agent.inflow;
import com.eactive.eai.agent.command.Command;
import com.eactive.eai.agent.command.CommandException;
import com.eactive.eai.common.inflow.AbstractInflowControlManager;
import com.eactive.eai.common.inflow.InflowControlUtil;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.custom.inflow.ClientDualInflowControlManager;
public class RemoveInflowClientControlCommand extends Command {
private static final long serialVersionUID = 1L;
public RemoveInflowClientControlCommand() {
super("RemoveInflowClientControlCommand");
}
public Object execute() throws CommandException {
Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
if (logger.isInfo())
logger.info(this.name + " is executed");
if (!(args instanceof String)) {
String rspErrorCode = "RECEAIMCM001";
String msg = makeException(rspErrorCode, null);
if (logger.isError())
logger.error(msg);
throw new CommandException(msg);
}
String key = (String) args;
try {
AbstractInflowControlManager base = InflowControlUtil.getInflowControlManager();
if (!(base instanceof ClientDualInflowControlManager)) {
throw new IllegalStateException("ClientDualInflowControlManager 가 활성화되지 않았습니다.");
}
ClientDualInflowControlManager manager = (ClientDualInflowControlManager) base;
manager.removeClient(key);
if (logger.isWarn())
logger.warn(this.name + "] " + key + " removed.");
} catch (Exception e) {
String rspErrorCode = "RECEAIMCM002";
String msg = makeException(rspErrorCode, e);
if (logger.isError())
logger.error(msg, e);
throw new CommandException(msg);
}
return "success";
}
}
@@ -1,6 +1,8 @@
package com.eactive.eai.authserver.config;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.time.LocalDateTime;
import java.util.Arrays;
@@ -35,6 +37,7 @@ import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
import com.eactive.eai.authserver.dao.TokenIssuanceLogDAO;
import com.eactive.eai.authserver.jwt.PssJwtAccessTokenConverter;
import com.eactive.eai.authserver.service.OAuth2Manager;
import com.eactive.eai.authserver.vo.ClientVO;
import com.eactive.eai.common.dao.DAOException;
@@ -139,9 +142,10 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
Resource keystore = new ClassPathResource(keystorePath);
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(keystore, keystorePassword.toCharArray());
KeyPair keyPair = keyStoreKeyFactory.getKeyPair(keyAlias, keyPassword.toCharArray());
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setKeyPair(keyPair);
return converter;
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
return new PssJwtAccessTokenConverter(privateKey, publicKey);
}
@@ -1,52 +1,52 @@
package com.eactive.eai.custom.adapter.handler;
import java.util.Properties;
import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.adapter.handler.AdapterErrorMessageHandler;
import com.eactive.eai.common.message.MessageType;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.manager.StandardMessageManager;
import com.eactive.eai.message.service.InterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageKeys;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class LonErrorMsgHandler implements AdapterErrorMessageHandler {
@Override
public Object generateNonStandardErrorResponseMessage(String inboudnAdapterGroupName, String inboudnAdapterName,
Properties callProp, Object outboundRequestData, StandardMessage resStandardMessage) throws Exception{
if(resStandardMessage != null && isErrorMessage(resStandardMessage)) {
AdapterGroupVO adapterGroupVO = AdapterManager.getInstance().getAdapterGroupVO(inboudnAdapterGroupName);
if(MessageType.JSON.equals(adapterGroupVO.getMessageType())) {
ObjectMapper objectMapper = new ObjectMapper();
String requestMessage = (String) outboundRequestData;
JsonNode requestJson = objectMapper.readTree(requestMessage);
String alncInstCd = requestJson.get("dataCmn").get("alncInstCd").asText();
ObjectNode responseJson = objectMapper.createObjectNode();
ObjectNode dataCmnNode = objectMapper.createObjectNode();
responseJson.set("dataCmn", dataCmnNode);
dataCmnNode.put("fnclInstCd", "KBK");
dataCmnNode.put("alncInstCd", alncInstCd);
dataCmnNode.put("tlgrRspnsCd", "0210");
return responseJson.toString();
}
}
return "";
}
private boolean isErrorMessage(StandardMessage standardMessage) {
InterfaceMapper mapper = StandardMessageManager.getInstance().getMapper();
String responseType = mapper.getResponseType(standardMessage);
return STDMessageKeys.RESPONSE_TYPE_CODE_E.equals(responseType);
}
}
//package com.eactive.eai.custom.adapter.handler;
//
//import java.util.Properties;
//
//import com.eactive.eai.adapter.AdapterGroupVO;
//import com.eactive.eai.adapter.AdapterManager;
//import com.eactive.eai.adapter.handler.AdapterErrorMessageHandler;
//import com.eactive.eai.common.message.MessageType;
//import com.eactive.eai.message.StandardMessage;
//import com.eactive.eai.message.manager.StandardMessageManager;
//import com.eactive.eai.message.service.InterfaceMapper;
//import com.ext.eai.common.stdmessage.STDMessageKeys;
//import com.fasterxml.jackson.databind.JsonNode;
//import com.fasterxml.jackson.databind.ObjectMapper;
//import com.fasterxml.jackson.databind.node.ObjectNode;
//
//public class LonErrorMsgHandler implements AdapterErrorMessageHandler {
//
// @Override
// public Object generateNonStandardErrorResponseMessage(String inboudnAdapterGroupName, String inboudnAdapterName,
// Properties callProp, Object outboundRequestData, StandardMessage resStandardMessage) throws Exception{
//
// if(resStandardMessage != null && isErrorMessage(resStandardMessage)) {
// AdapterGroupVO adapterGroupVO = AdapterManager.getInstance().getAdapterGroupVO(inboudnAdapterGroupName);
// if(MessageType.JSON.equals(adapterGroupVO.getMessageType())) {
// ObjectMapper objectMapper = new ObjectMapper();
// String requestMessage = (String) outboundRequestData;
// JsonNode requestJson = objectMapper.readTree(requestMessage);
// String alncInstCd = requestJson.get("dataCmn").get("alncInstCd").asText();
//
// ObjectNode responseJson = objectMapper.createObjectNode();
// ObjectNode dataCmnNode = objectMapper.createObjectNode();
// responseJson.set("dataCmn", dataCmnNode);
// dataCmnNode.put("fnclInstCd", "KBK");
// dataCmnNode.put("alncInstCd", alncInstCd);
// dataCmnNode.put("tlgrRspnsCd", "0210");
//
// return responseJson.toString();
// }
// }
//
//
// return "";
// }
//
// private boolean isErrorMessage(StandardMessage standardMessage) {
// InterfaceMapper mapper = StandardMessageManager.getInstance().getMapper();
// String responseType = mapper.getResponseType(standardMessage);
// return STDMessageKeys.RESPONSE_TYPE_CODE_E.equals(responseType);
// }
//
//}
@@ -0,0 +1,31 @@
package com.eactive.eai.custom.adapter.http.client.impl.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.client.impl.filter.HttpClientAdapterFilter;
import com.eactive.eai.adapter.http.client.impl.filter.OutCryptoFilter;
/**
* 제주은행 Open API 기본 암복호화 필더
*/
public class EncFieldOutCryptoFilter implements HttpClientAdapterFilter {
private final OutCryptoFilter filter = new OutCryptoFilter();
protected Properties setProp(Properties p) {
p.setProperty(OutCryptoFilter.PROP_DEC_FROM_PATH, "/encryptedData");
p.setProperty(OutCryptoFilter.PROP_ENC_TO_PATH, "/encryptedData");
return p;
}
@Override
public Object doPreFilter(String adptGrpName, String adptName, Properties prop, Object message, Properties tempProp)
throws Exception {
return filter.doPreFilter(adptGrpName, adptName, prop, message, setProp(tempProp));
}
@Override
public Object doPostFilter(String adptGrpName, String adptName, Properties prop, Object message,
Properties tempProp) throws Exception {
return filter.doPostFilter(adptGrpName, adptName, prop, message, setProp(tempProp));
}
}
@@ -0,0 +1,18 @@
package com.eactive.eai.custom.adapter.http.client.impl.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.client.impl.filter.OutCryptoFilter;
/**
* 카카오뱅크 암복호화에 맟추어 커스텀
*/
public class KakaobankEncFieldOutCryptoFilter extends EncFieldOutCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(OutCryptoFilter.PROP_DEC_FROM_PATH, "/encrypted_data");
p.setProperty(OutCryptoFilter.PROP_ENC_TO_PATH, "/encrypted_data");
return p;
}
}
@@ -0,0 +1,17 @@
package com.eactive.eai.custom.adapter.http.client.impl.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.client.impl.filter.OutCryptoFilter;
/**
* 토스 암복호화에 맟추어 커스텀
*/
public class TossEncFieldOutCryptoFilter extends EncFieldOutCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(OutCryptoFilter.PROP_DEC_FROM_PATH, "/encrypted_data");
p.setProperty(OutCryptoFilter.PROP_ENC_TO_PATH, "/encrypted_data");
return p;
}
}
@@ -0,0 +1,17 @@
package com.eactive.eai.custom.adapter.http.client.impl.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.client.impl.filter.OutCryptoFilter;
/**
* 토스뱅크 암복호화에 맟추어 커스텀
*/
public class TossbankEncFieldOutCryptoFilter extends EncFieldOutCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(OutCryptoFilter.PROP_DEC_FROM_PATH, "/encryptedData");
p.setProperty(OutCryptoFilter.PROP_ENC_TO_PATH, "/encryptedData");
return p;
}
}
@@ -1,82 +0,0 @@
package com.eactive.eai.custom.adapter.http.dynamic.filter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.adapter.http.dynamic.filter.InCryptoFilter;
import com.eactive.eai.util.JsonPathUtil;
/**
* DJB ERP 연동용 암복호화 필터.
*
* DYNAMIC 키 컨텍스트 추출 규칙:
* HTTP 헤더 {@code httpHeaderGroup}의 값은 JSON 객체이며,
* 그 중 {@code x-emp-nm} 필드 값을 {@code groupSeq}로
* runtimeContext에 담아 키 도출 전략에 전달한다.
*
* 어댑터 프로퍼티 (부모 클래스 공통 설정 외 추가 키):
* crypto.context.key runtimeContext에 넣을 키 이름 (기본: groupSeq)
* crypto.context.header 컨텍스트 JSON이 담긴 HTTP 헤더명 (기본: httpHeaderGroup)
* crypto.context.header.field 헤더 JSON에서 추출할 필드명 (기본: x-emp-nm)
*
* 어댑터 프로퍼티 설정 예:
* crypto.module.name = AES_GCM_NoPadding_DYNAMIC_sample
* crypto.scope = FIELD
* crypto.dec.enabled = Y
* crypto.enc.enabled = N
* crypto.dec.from.path = /encryptedData
* crypto.dec.to.path = /
* crypto.context.key = groupSeq
* crypto.context.header = httpHeaderGroup
* crypto.context.header.field = x-emp-nm
*
* 필터 타입 등록 (FQCN):
* com.eactive.eai.custom.adapter.http.dynamic.filter.DJBErpCryptoFilter
*/
public class DJBErpCryptoFilter extends InCryptoFilter {
public static final String PROP_CONTEXT_KEY = "crypto.context.key";
public static final String PROP_CONTEXT_HEADER = "crypto.context.header";
public static final String PROP_CONTEXT_HEADER_FIELD = "crypto.context.header.field";
private static final String DEFAULT_CONTEXT_KEY = "groupSeq";
private static final String DEFAULT_CONTEXT_HEADER = "httpHeaderGroup";
private static final String DEFAULT_CONTEXT_HEADER_FIELD = "x-emp-nm";
/**
* httpHeaderGroup 헤더(JSON)에서 x-emp-nm 값을 추출하여 groupSeq로 매핑한다.
* 헤더가 없거나 필드를 찾을 수 없으면 빈 Map을 반환한다.
*/
@Override
protected Map<String, String> buildRuntimeContext(Properties prop, HttpServletRequest request) {
Map<String, String> ctx = new HashMap<>();
String contextKey = prop.getProperty(PROP_CONTEXT_KEY, DEFAULT_CONTEXT_KEY);
String contextHeaderName = prop.getProperty(PROP_CONTEXT_HEADER, DEFAULT_CONTEXT_HEADER);
String contextHeaderField = prop.getProperty(PROP_CONTEXT_HEADER_FIELD, DEFAULT_CONTEXT_HEADER_FIELD);
String headerJson = request.getHeader(contextHeaderName);
if (StringUtils.isBlank(headerJson)) {
logger.warn("DJBErpCryptoFilter] 컨텍스트 헤더 없음: " + contextHeaderName);
return ctx;
}
String value = JsonPathUtil.getValueAtPath(headerJson, "/" + contextHeaderField);
if (value == null) {
logger.warn("DJBErpCryptoFilter] 헤더 JSON에서 필드 추출 실패: header="
+ contextHeaderName + ", field=" + contextHeaderField);
return ctx;
}
// x-emp-nm 값은 "groupSeq|empNo" 형태 — '|' 앞부분만 groupSeq로 사용
String groupSeq = value.contains("|") ? value.substring(0, value.indexOf('|')) : value;
ctx.put(contextKey, groupSeq);
return ctx;
}
}
@@ -0,0 +1,61 @@
package com.eactive.eai.custom.adapter.http.dynamic.filter;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilter;
import com.eactive.eai.adapter.http.dynamic.filter.InCryptoFilter;
import com.eactive.eai.common.security.keyderiv.KeyDerivationStrategy;
/**
* 더존 연동용 수신 암복호화 필터.
*
* {@code HttpAdapterServiceKey.INBOUND_HEADER} 프로퍼티로 전달된 수신 헤더 Map에서
* 두 가지 컨텍스트 값을 추출하여 {@link InCryptoFilter}에 위임한다.
*
* x-emp-nm : GCM AAD 값 ({@code CRYPTO_AAD_HEADER} 프로퍼티에 설정)
* x-chnl-nm : DYNAMIC 키 도출 컨텍스트 ({@code contextKey} 프로퍼티에 설정)
* → {@code HsmContextSha256KeyDerivationStrategy}가 채널명 기반으로 키를 동적 생성
*
* 암복호화 필드 경로: {@code /encryptedData}
*
* 필터 타입 등록 (FQCN):
* com.eactive.eai.custom.adapter.http.dynamic.filter.DouzoneEncFieldInCryptoFilter
*/
public class DouzoneEncFieldInCryptoFilter implements HttpAdapterFilter {
private final InCryptoFilter filter = new InCryptoFilter();
protected Properties setProp(Properties p) {
p.setProperty(InCryptoFilter.PROP_DEC_FROM_PATH, "/encryptedData");
p.setProperty(InCryptoFilter.PROP_ENC_TO_PATH, "/encryptedData");
return p;
}
private void setContext(Properties tempProp) {
Properties inboundHeaders = (Properties) tempProp.get(HttpAdapterServiceKey.INBOUND_HEADER);
String empNm = inboundHeaders.getProperty("x-emp-nm");
tempProp.setProperty(InCryptoFilter.PROP_AAD_HEADER, empNm);
String chnlNm = inboundHeaders.getProperty("x-chnl-nm");
tempProp.setProperty(KeyDerivationStrategy.PARAM_CONTEXT_KEY, chnlNm);
}
@Override
public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop,
HttpServletRequest request, HttpServletResponse response) throws Exception {
setContext(prop);
return filter.doPreFilter(adptGrpName, adptName, message, setProp(prop), request, response);
}
@Override
public Object doPostFilter(String adptGrpName, String adptName, Object resultMessage, Properties prop,
HttpServletRequest request, HttpServletResponse response) throws Exception {
setContext(prop);
return filter.doPostFilter(adptGrpName, adptName, resultMessage, setProp(prop), request, response);
}
}
@@ -9,12 +9,12 @@ import com.eactive.eai.adapter.http.dynamic.filter.InCryptoFilter;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilter;
/**
* CryptoFilter 프로퍼티 멤버변수로 관리하는 HttpAdapterFilter 구현체.
* InCryptoFilter 멤버변수로 관리하는 HttpAdapterFilter 구현체.
*
* 멤버변수에 세팅된 값을 Properties로 변환하여 {@link InCryptoFilter} 위임한다.
* 값이 blank인 멤버변수는 Properties에 포함하지 않으며, CryptoFilter의 기본값이 적용된다.
* 값이 blank인 멤버변수는 Properties에 포함하지 않으며, InCryptoFilter의 기본값이 적용된다.
*/
public class EncFieldCryptoFilter implements HttpAdapterFilter {
public class EncFieldInCryptoFilter implements HttpAdapterFilter {
private final InCryptoFilter filter = new InCryptoFilter();
@@ -30,7 +30,7 @@ public class EncFieldCryptoFilter implements HttpAdapterFilter {
return filter.doPostFilter(adptGrpName, adptName, resultMessage, setProp(prop), request, response);
}
private Properties setProp(Properties p) {
protected Properties setProp(Properties p) {
p.setProperty(InCryptoFilter.PROP_DEC_FROM_PATH, "/encryptedData");
p.setProperty(InCryptoFilter.PROP_ENC_TO_PATH, "/encryptedData");
return p;
@@ -0,0 +1,18 @@
package com.eactive.eai.custom.adapter.http.dynamic.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.dynamic.filter.InCryptoFilter;
/**
* 카카오뱅크 암복호화에 맟추어 커스텀 필요
*/
public class KakaobankEncFieldInCryptoFilter extends EncFieldInCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(InCryptoFilter.PROP_DEC_FROM_PATH, "/encrypted_data");
p.setProperty(InCryptoFilter.PROP_ENC_TO_PATH, "/encrypted_data");
return p;
}
}
@@ -0,0 +1,18 @@
package com.eactive.eai.custom.adapter.http.dynamic.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.dynamic.filter.InCryptoFilter;
/**
* 토스 암복호화에 맟추어 커스텀 필요
*/
public class TossEncFieldInCryptoFilter extends EncFieldInCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(InCryptoFilter.PROP_DEC_FROM_PATH, "/encrypted_data");
p.setProperty(InCryptoFilter.PROP_ENC_TO_PATH, "/encrypted_data");
return p;
}
}
@@ -0,0 +1,18 @@
package com.eactive.eai.custom.adapter.http.dynamic.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.dynamic.filter.InCryptoFilter;
/**
* 토스뱅크 암복호화에 맟추어 커스텀 필요
*/
public class TossbankEncFieldInCryptoFilter extends EncFieldInCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(InCryptoFilter.PROP_DEC_FROM_PATH, "/encryptedData");
p.setProperty(InCryptoFilter.PROP_ENC_TO_PATH, "/encryptedData");
return p;
}
}
@@ -0,0 +1,62 @@
package com.eactive.eai.custom.common.security.keyderiv;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Map;
import javax.crypto.SecretKey;
import com.eactive.eai.common.hsm.HsmCryptoService;
import com.eactive.eai.common.security.keyderiv.DerivedKey;
import com.eactive.eai.common.security.keyderiv.KeyDerivationStrategy;
import com.eactive.eai.common.util.ApplicationContextProvider;
/**
* HSM 마스터키 + 런타임 컨텍스트값을 연결(concatenate)한 뒤 SHA-256 해싱으로 키를 도출하는 전략.
* SHA-256 출력은 항상 32바이트(AES-256)이므로 별도 keyLength 파라미터가 불필요하다.
*
* key_deriv_params (JSON) 예시:
* {
* "hsmKeyAlias" : "MASTER_KEY_AES",
* "contextKey" : "X-Api-Group-Seq" -- runtimeContext에서 꺼낼 키 이름
* }
*/
public class HsmContextSha256KeyDerivationStrategy implements KeyDerivationStrategy {
@Override
public DerivedKey deriveKey(Map<String, String> params, Map<String, String> runtimeContext) throws Exception {
String hsmKeyAlias = required(params, PARAM_HSM_KEY_ALIAS);
String contextKey = required(params, PARAM_CONTEXT_KEY);
SecretKey masterKey = hsmCryptoService().getSecretKey(hsmKeyAlias);
byte[] masterKeyBytes = masterKey.getEncoded();
byte[] contextBytes = runtimeContext.getOrDefault(contextKey, "")
.getBytes(StandardCharsets.UTF_8);
byte[] combined = new byte[masterKeyBytes.length + contextBytes.length];
System.arraycopy(masterKeyBytes, 0, combined, 0, masterKeyBytes.length);
System.arraycopy(contextBytes, 0, combined, masterKeyBytes.length, contextBytes.length);
byte[] derived = MessageDigest.getInstance("SHA-256").digest(combined);
return new DerivedKey(derived, derived);
}
@Override
public String buildCacheKey(String cryptoName, Map<String, String> params, Map<String, String> runtimeContext) {
String contextKey = params.getOrDefault(PARAM_CONTEXT_KEY, "");
String contextValue = runtimeContext.getOrDefault(contextKey, "");
return cryptoName + ":" + contextValue;
}
private String required(Map<String, String> params, String key) {
String value = params.get(key);
if (value == null || value.trim().isEmpty()) {
throw new IllegalArgumentException("key_deriv_params 필수값 누락: " + key);
}
return value;
}
private HsmCryptoService hsmCryptoService() {
return ApplicationContextProvider.getContext().getBean(HsmCryptoService.class);
}
}
@@ -0,0 +1,41 @@
package com.eactive.eai.custom.common.security.keyderiv;
import java.util.Map;
import javax.xml.bind.DatatypeConverter;
import com.eactive.eai.common.security.keyderiv.DerivedKey;
import com.eactive.eai.common.security.keyderiv.strategy.BaseHsmKeyDerivationStrategy;
/**
* HSM에서 키와 IV를 각각 가져오는 전략.
* IV는 HSM에서 가져온 바이트 배열을 hex 문자열로 변환한 뒤 substring(32, 64)를 적용하여 사용한다.
* (32바이트 HSM 키 → 64자 hex → substring(32,64) → 16바이트 IV)
*
* key_deriv_params (JSON) 예시:
* { "hsmKeyAlias" : "MASTER_KEY_AES", "hsmIvAlias" : "MASTER_IV_AES" }
*/
public class HsmKeyAndIvSliceDerivationStrategy extends BaseHsmKeyDerivationStrategy {
private static final int IV_HEX_OFFSET = 32;
private static final int IV_HEX_END = 64;
@Override
public DerivedKey deriveKey(Map<String, String> params, Map<String, String> runtimeContext) throws Exception {
byte[] keyBytes = super.getHsmKey(params);
byte[] rawIv = super.getHsmIv(params);
String ivHex = DatatypeConverter.printHexBinary(rawIv);
if (ivHex.length() < IV_HEX_END) {
throw new IllegalArgumentException(
"hsmIvAlias hex 길이 부족: 최소 " + IV_HEX_END + "자 필요, 실제=" + ivHex.length()
+ " (" + rawIv.length + "바이트)");
}
byte[] iv = DatatypeConverter.parseHexBinary(ivHex.substring(IV_HEX_OFFSET, IV_HEX_END));
return new DerivedKey(keyBytes, keyBytes, iv);
}
@Override
public String buildCacheKey(String cryptoName, Map<String, String> params, Map<String, String> runtimeContext) {
return cryptoName;
}
}
@@ -1,13 +1,25 @@
package com.eactive.eai.custom.inbound.processor;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.common.inflow.Bucket;
import com.eactive.eai.common.inflow.InflowTargetVO;
import com.eactive.eai.common.inflow.dual.ClientDualBucket;
import com.eactive.eai.common.inflow.dual.DualBucket;
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.custom.inflow.ClientDualBucket;
import com.eactive.eai.inbound.processor.ProcessVO;
import com.eactive.eai.inbound.processor.RequestProcessor;
import com.eactive.eai.message.StandardItem;
import com.eactive.eai.message.StandardMessage;
/**
* 어댑터/인터페이스/클라이언트 유량제어 차단 시 어느 버킷(PER_SECOND/THRESHOLD)에서
@@ -21,9 +33,85 @@ import com.eactive.eai.inbound.processor.RequestProcessor;
* <p>Spring Bean 등록 후 기존 RequestProcessor 대신 이 클래스를 어댑터에 설정한다.
*/
public class DJBRequestProcessor extends RequestProcessor {
static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
@Override
protected void afterFoundEaiMessage(EAIMessage eaiMsg, ProcessVO vo, Properties prop) {
logger.debug("DJBRequestProcessor interface found.");
try {
this.resolveStandardHeaderMapping(eaiMsg, prop);
} catch (Exception e) {
logger.warn("DJBRequestProcessor header set failed.", e);
}
}
private void resolveStandardHeaderMapping(EAIMessage eaiMsg, Properties prop) {
StandardMessage standardMessage = eaiMsg.getStandardMessage();
HashMap<String, String> headerMapping = getPropertyMap("DJB_IN_HTTHEAD_STDHEAD_MAPPING", eaiMsg.getSngSysItfTp());
for (Entry<String, String> entry : headerMapping.entrySet()) {
String stdHeaderPath = entry.getKey();
int dotIdx = stdHeaderPath.indexOf('.');
if(dotIdx > 0) {
String firstPath = stdHeaderPath.substring(0, dotIdx);
StandardItem topLevelItem = standardMessage.findItem(firstPath);
topLevelItem.setHidden(false);
}
StandardItem item = standardMessage.findItem(entry.getKey());
String value = resolveNestedValue(prop, entry.getValue());
if (item != null && value != null)
item.setValue(value);
else
logger.debug("header mapping item not found : {} ", entry);
}
}
private HashMap<String, String> getPropertyMap(String propertyGroupName, String prefix) {
Properties prop = PropManager.getInstance().getProperties(propertyGroupName);
Set<String> keys = prop.stringPropertyNames();
HashMap<String, String> tmpToJsonArrayInterface = new HashMap<>();
for (String key : keys) {
if (StringUtils.startsWith(key, prefix + ".")) {
String propValue = prop.getProperty(key);
String replacedKey = StringUtils.replace(key, prefix + ".", "");
tmpToJsonArrayInterface.put(replacedKey, propValue);
}
}
return tmpToJsonArrayInterface;
}
private String resolveNestedValue(Map<?, ?> map, String keyPath) {
int dotIdx = keyPath.indexOf('.');
if (dotIdx < 0) {
Object val = map.get(keyPath);
if (val == null)
return null;
if (val instanceof String)
return (String) val;
return val.toString();
}
String first = keyPath.substring(0, dotIdx);
String rest = keyPath.substring(dotIdx + 1);
Object val = map.get(first);
if (val instanceof Map) {
return resolveNestedValue((Map<?, ?>) val, rest);
}
// 폴백: 전체 keyPath를 단일 키로 조회
Object direct = map.get(keyPath);
if (direct == null)
return null;
if (direct instanceof String)
return (String) direct;
return direct.toString();
}
@Override
protected String checkClientInflow(Bucket bucket, String clientId) {
protected String checkCustomInflow(Bucket bucket, EAIMessage eaiMsg, Properties prop) {
String clientId = eaiMsg.getClientId();
if (StringUtils.isBlank(clientId)) return null;
if (bucket instanceof ClientDualBucket) {
return ((ClientDualBucket) bucket).isClientPassDetail(clientId);
@@ -32,9 +120,9 @@ public class DJBRequestProcessor extends RequestProcessor {
}
@Override
protected InflowTargetVO resolveClientInflowThreshold(Bucket bucket, String clientId) {
protected InflowTargetVO resolveCustomInflowThreshold(Bucket bucket, EAIMessage eaiMsg, Properties prop) {
if (bucket instanceof ClientDualBucket) {
return ((ClientDualBucket) bucket).getClientInflowThreshold(clientId);
return ((ClientDualBucket) bucket).getClientInflowThreshold(eaiMsg.getClientId());
}
return null;
}
@@ -0,0 +1,23 @@
package com.eactive.eai.custom.inflow;
import com.eactive.eai.common.inflow.InflowTargetVO;
import com.eactive.eai.common.inflow.dual.DualBucket;
/**
* DualBucket에 클라이언트 유량제어 메서드를 추가한 인터페이스.
* {@link ClientDualInflowControlManager}가 구현한다.
*/
public interface ClientDualBucket extends DualBucket {
/**
* 클라이언트 유량제어 체크 — 차단 원인 포함.
* @return null이면 통과, "PER_SECOND" 또는 "THRESHOLD"이면 해당 버킷에서 차단
*/
String isClientPassDetail(String clientId);
/**
* 클라이언트 유량제어 설정 조회 — 에러 메시지 생성용.
* @return 등록된 설정이 없으면 null
*/
InflowTargetVO getClientInflowThreshold(String clientId);
}
@@ -0,0 +1,114 @@
package com.eactive.eai.custom.inflow;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.stereotype.Component;
import com.eactive.eai.common.inflow.Bucket;
import com.eactive.eai.common.inflow.InflowTargetVO;
import com.eactive.eai.common.inflow.InflowType;
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
import com.eactive.eai.common.inflow.dual.DualInflowControlManager;
import com.eactive.eai.common.lifecycle.LifecycleException;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.common.util.Logger;
/**
* 어댑터/인터페이스 이중 버킷(DualInflowControlManager)에 클라이언트 유량제어를 추가한 관리자.
*
* <p>적용 방법: INFLOW.properties에 아래 한 줄 추가.
* <pre>inflow.control.bucket.className=com.eactive.eai.common.inflow.dual.ClientDualInflowControlManager</pre>
*/
@Component
public class ClientDualInflowControlManager extends DualInflowControlManager implements ClientDualBucket {
private static final Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
public static synchronized Bucket getBucket() {
return ApplicationContextProvider.getContext().getBean(ClientDualInflowControlManager.class);
}
private volatile Map<String, DualCustomBucket> clientBucketMap = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, TargetMetrics> clientMetricsMap = new ConcurrentHashMap<>();
// -------------------------------------------------------------------------
// Lifecycle
// -------------------------------------------------------------------------
@Override
public void start() throws LifecycleException {
super.start();
try {
initClients();
} catch (Exception e) {
throw new LifecycleException("ClientDualInflowControlManager init failed: " + e.getMessage());
}
}
// -------------------------------------------------------------------------
// 초기화 / 리로드
// -------------------------------------------------------------------------
private void initClients() throws Exception {
this.clientBucketMap = loadBucketMap(InflowType.CLIENT);
if (logger.isInfo()) logger.info("ClientDualInflowControlManager] initClients: " + clientBucketMap.size() + " buckets");
}
public synchronized void reloadClient() throws Exception {
initClients();
clientMetricsMap.clear();
}
public synchronized void reloadClient(String clientId) throws Exception {
reloadBucketMap(clientBucketMap, InflowType.CLIENT, clientId);
TargetMetrics m = clientMetricsMap.get(clientId);
if (m != null) m.reset();
}
public synchronized void removeClient(String clientId) {
clientBucketMap.remove(clientId);
clientMetricsMap.remove(clientId);
}
// -------------------------------------------------------------------------
// 클라이언트 메트릭 접근자
// -------------------------------------------------------------------------
public TargetMetrics getClientMetrics(String clientId) { return clientMetricsMap.get(clientId); }
public Map<String, TargetMetrics> getAllClientMetrics() { return Collections.unmodifiableMap(clientMetricsMap); }
public void resetClientMetrics(String clientId) { TargetMetrics m = clientMetricsMap.get(clientId); if (m != null) m.reset(); }
public void resetAllClientMetrics() { clientMetricsMap.values().forEach(TargetMetrics::reset); }
// -------------------------------------------------------------------------
// ClientDualBucket — 클라이언트 유량제어
// -------------------------------------------------------------------------
@Override
public String isClientPassDetail(String clientId) {
DualCustomBucket b = clientBucketMap.get(clientId);
if (b == null) return DualCustomBucket.RESULT_PASS;
String result = b.tryConsume();
recordMetrics(clientMetricsMap, clientId, result);
return result;
}
@Override
public InflowTargetVO getClientInflowThreshold(String clientId) {
DualCustomBucket b = clientBucketMap.get(clientId);
return (b == null) ? null : b.getInflowTargetVo();
}
// -------------------------------------------------------------------------
// 모니터링용 접근자
// -------------------------------------------------------------------------
public DualCustomBucket getClientBucket(String clientId) {
return clientBucketMap.get(clientId);
}
public Map<String, DualCustomBucket> getClientBucketMap() {
return clientBucketMap;
}
}
@@ -9,7 +9,6 @@ import org.springframework.stereotype.Service;
import com.eactive.eai.common.inflow.AbstractInflowControlManager;
import com.eactive.eai.common.inflow.InflowControlUtil;
import com.eactive.eai.common.inflow.InflowTargetVO;
import com.eactive.eai.common.inflow.dual.ClientDualInflowControlManager;
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
import com.eactive.eai.manage.inflow.GroupBucketStatusDTO;
import com.eactive.eai.manage.inflow.TargetBucketStatusDTO;
@@ -8,7 +8,6 @@ import org.springframework.stereotype.Service;
import com.eactive.eai.common.inflow.AbstractInflowControlManager;
import com.eactive.eai.common.inflow.InflowControlUtil;
import com.eactive.eai.common.inflow.InflowTargetVO;
import com.eactive.eai.common.inflow.dual.ClientDualInflowControlManager;
import com.eactive.eai.common.inflow.dual.DualInflowControlManager;
import com.eactive.eai.manage.inflow.TargetMetricDTO;
@@ -1,81 +0,0 @@
package com.eactive.eai.custom.message;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.common.server.Keys;
import com.eactive.eai.common.util.StringUtil;
import com.eactive.eai.common.util.UUID;
/**
* 1. 기능 : UUID Generation Class 2. 처리 개요 : * - 3. 주의사항
*
* @author :
* @version : v 1.0.0
* @see : 관련 기능을 참조
* @since : :
*/
public final class GUIDGeneratorKAKAOCARD {
private static final DateTimeFormatter SDF_YYYYMMDDHHMMSSMS = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
/*
* 날짜(17) + "-"(1) + 시스템코드(3) + hostname(6) + 일련번호(5) + "-"(1) + 001(3)
*
*/
public static final int GUID_LENGTH = 33; // seq값 제외부분
/**
* 1. 기능 : Private 생성자 2. 처리 개요 : - 3. 주의사항 - Instance 생성하지 못함
**/
private GUIDGeneratorKAKAOCARD() {
}
public synchronized static String getGUID(String systemCode) {
StringBuilder sb = new StringBuilder();
sb.append(SDF_YYYYMMDDHHMMSSMS.format(ZonedDateTime.now()));
sb.append("-");
sb.append(systemCode);
sb.append(UNIQUE_NUM);
char[] formatSeq = { '0', '0', '0', '0', '0' };
char[] seqCharArray = String.valueOf(seq).toCharArray();
int destPos = formatSeq.length - seqCharArray.length;
System.arraycopy(seqCharArray, 0, formatSeq, destPos, seqCharArray.length);
sb.append(formatSeq);
seq++;
if (seq > 99999) {
seq = 1;
}
return sb.toString() + "-" + "001";
}
private static String UNIQUE_NUM;
private static int seq = 1;
private static int hostlength = 6;
static {
String uniqueValue = System.getProperty(Keys.SERVER_KEY);
if (StringUtils.isBlank(uniqueValue)) {
try {
uniqueValue = java.net.InetAddress.getLocalHost().getHostName();
} catch (Exception e) {
uniqueValue = StringUtil.stringFormat("", false, 'X', hostlength);
}
}
if (uniqueValue.length() > hostlength) {
uniqueValue = uniqueValue.substring(uniqueValue.length() - hostlength, uniqueValue.length());
} else if (uniqueValue.length() < hostlength) {
uniqueValue = StringUtil.stringFormat(uniqueValue, false, 'X', hostlength);
}
UNIQUE_NUM = uniqueValue.toUpperCase();
}
public static void main(String[] args) {
String guid = getGUID("FEP");
// System.out.println("[" + guid.length() + "]" + guid);
}
}
@@ -1,40 +0,0 @@
package com.eactive.eai.custom.message;
import com.eactive.eai.common.server.Keys;
import com.eactive.eai.common.util.DatetimeUtil;
import com.eactive.eai.common.util.StringUtil;
public class GUIDGeneratorKBANK {
private static String UNIQUE_NUM;
private static int seq = 1;
static {
String uniqueValue = System.getProperty(Keys.SERVER_KEY);
if(uniqueValue.length() < 8) {
uniqueValue = StringUtil.stringFormat(uniqueValue, false, '0', 8);
}else if(uniqueValue.length() > 8){
uniqueValue = uniqueValue.substring(uniqueValue.length() - 8);
}
UNIQUE_NUM = uniqueValue.toUpperCase();
}
public synchronized static String makeGUID() {
StringBuilder sb = new StringBuilder();
sb.append(DatetimeUtil.getCurrentDateTime());
sb.append(UNIQUE_NUM);
char[] formatSeq = {'0','0','0','0','0','0','0','0'};
char[] seqCharArray = String.valueOf(seq).toCharArray();
int destPos = formatSeq.length - seqCharArray.length;
System.arraycopy(seqCharArray, 0, formatSeq, destPos, seqCharArray.length);
sb.append(formatSeq);
seq ++;
if(seq > 99999999) {
seq = 1;
}
return sb.toString() ;
}
}
@@ -1,98 +0,0 @@
package com.eactive.eai.custom.message;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import com.eactive.eai.common.util.DatetimeUtil;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.common.server.Keys;
import com.eactive.eai.common.util.StringUtil;
import com.eactive.eai.common.util.UUID;
/**
* 1. 기능 : UUID Generation Class 2. 처리 개요 : * - 3. 주의사항
*
* @author :
* @version : v 1.0.0
* @see : 관련 기능을 참조
* @since : :
*/
public final class GUIDGeneratorKJB {
/*
* 그룹사코드(3) + 호스트명(8) + 서버구분번호(2) + 일자(8) + 전문생성시간(6) + 일련번호(6) + 시스템경로번호(3, '001')
*/
public static final int GUID_LENGTH = 33; // 시스템경로번호 제외부분
/**
* 1. 기능 : Private 생성자 2. 처리 개요 : - 3. 주의사항 - Instance 생성하지 못함
**/
private GUIDGeneratorKJB() {
}
public synchronized static String getGUID(String groupCmpCd) {
String guid = groupCmpCd + UNIQUE_NUM;
guid = guid + DatetimeUtil.getCurrentDateTime();
if(seq < 10) {
guid = guid + "00000" + seq;
}
else if(seq < 100) {
guid = guid + "0000" + seq;
}
else if(seq < 1000) {
guid = guid + "000" + seq;
}
else if(seq < 10000) {
guid = guid + "00" + seq;
}
else if(seq < 100000) {
guid = guid + "0" + seq;
}
else {
guid = guid + seq;
}
seq ++;
if(seq > 999999) {
seq = 1;
}
return guid + "001";
}
private static String UNIQUE_NUM;
private static int seq = 1;
static {
String hostname = "";
try {
hostname = java.net.InetAddress.getLocalHost().getHostName();
}
catch(Exception e) {
hostname = "________";
}
if(hostname.getBytes().length != 8) {
if(hostname.getBytes().length < 8) {
hostname = StringUtils.leftPad(hostname, 8, '_');
} else if(hostname.getBytes().length > 8) {
hostname = StringUtils.substring(hostname, 0, 8);
}
}
String serverName = System.getProperty(Keys.SERVER_KEY);
String instid = "00";
if(serverName != null && serverName.length() > 2) {
instid = serverName.substring(serverName.length()-2, serverName.length());
}
UNIQUE_NUM = hostname.toUpperCase() + instid;
}
public static void main(String[] args) {
String guid = getGUID("051");
// System.out.println("[" + guid.length() + "]" + guid);
}
}
@@ -1,60 +0,0 @@
package com.eactive.eai.custom.message;
import java.text.SimpleDateFormat;
import com.eactive.eai.common.server.Keys;
import com.eactive.eai.common.util.StringUtil;
public final class GUIDGeneratorSBI {
private static final SimpleDateFormat SDF_YYYYMMDDHHMMSSMI = new SimpleDateFormat("yyyyMMddHHmmssSSS");
private GUIDGeneratorSBI() {
}
/**
* 시스템일시(17)+시스템환경코드(1)+시스템코드(3)+시스템고유번호(9)+일련번호(2)
*
* @param envDvcd
* @return
*/
public synchronized static String getGUID(String envDvcd, String systemType) {
String guid = (SDF_YYYYMMDDHHMMSSMI).format(new java.util.Date()) + envDvcd + systemType + UNIQUE_NUM;
if (seq < 10) {
guid = guid + "0" + seq;
} else {
guid = guid + seq;
}
seq++;
if (seq > 99) {
seq = 1;
}
return guid;
}
private static String UNIQUE_NUM;
private static int seq = 1;
static {
String hostname = "";
try {
hostname = java.net.InetAddress.getLocalHost().getHostName();
} catch (Exception e) {
hostname = "_______";
}
if (hostname.getBytes().length != 7) {
hostname = StringUtil.stringFormat(hostname, false, '_', 7);
}
String serverName = System.getProperty(Keys.SERVER_KEY); // inst.Name
String instid = "11";
if (serverName != null && serverName.length() > 2) {
instid = serverName.substring(serverName.length() - 2, serverName.length());
}
UNIQUE_NUM = hostname.toUpperCase() + instid;
}
}
@@ -2,6 +2,7 @@ package com.eactive.eai.custom.message;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.service.DefaultInterfaceMapper;
@@ -28,17 +29,24 @@ public class InterfaceMapperDJB extends DefaultInterfaceMapper {
// 처리결과구분코드 DJBank 값
private static final String PROCS_RSLT_SUCCESS = "S";
private static final String PROCS_RSLT_FAIL = "F";
private static String API_ID_PREFIX = StringUtils
.defaultString(PropManager.getInstance().getProperty("API_ID_PREFIX"));
@Override
public String getEaiSvcCode(StandardMessage standardMessage) {
String interfaceId = getInterfaceId(standardMessage);
if(StringUtils.isNotBlank(standardMessage.getEaiSvcCd()))
return standardMessage.getEaiSvcCd();
// String interfaceId = getInterfaceId(standardMessage);
String txId = getServiceId(standardMessage);
String sendRecvDvcd = getSendRecvDivision(standardMessage); // S | R
String inExDivision = getInExDivision(standardMessage); // 1 | 2
if(StringUtils.isEmpty(txId))
throw new RuntimeException("not found txid");
if (interfaceId == null) interfaceId = "";
interfaceId = interfaceId.trim();
return interfaceId + sendRecvDvcd + StringUtils.defaultString(inExDivision);
return API_ID_PREFIX + txId + sendRecvDvcd + StringUtils.defaultString(inExDivision);
}
// ----------------------------------------------------------------
@@ -1,202 +0,0 @@
package com.eactive.eai.custom.message;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.StringUtil;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.service.DefaultInterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageKeys;
@SuppressWarnings("serial")
public class InterfaceMapperKAKAOCARD extends DefaultInterfaceMapper {
private static String SESSION_ID = "INTERFACE_COMMON.MCI_SESN_ID";
private static String INSTANCE_ID = "INTERFACE_COMMON.MCI_INSTNC_ID";
@Override
public String getEaiSvcCode(StandardMessage standardMessage) {
String eaiSvcCode = null;
String interfaceId = getInterfaceId(standardMessage);
String returnType = getSendRecvDivision(standardMessage); // S | R
String inExDivision = getInExDivision(standardMessage); // 1 | 2
if (interfaceId == null)
interfaceId = "";
interfaceId = interfaceId.trim();
// TODO : site에 맞게 조합해야 함.
eaiSvcCode = interfaceId + returnType + StringUtils.defaultString(inExDivision);
return eaiSvcCode;
}
@Override
public void setGuid(StandardMessage standardMessage, String guid) {
if (guid == null)
throw new RuntimeException("guid is null");
if (guid.length() != 36)
throw new RuntimeException("The length of guid is not 36");
setItemValue(standardMessage, getPath(GUID), guid);
}
@Override
public String getGuid(StandardMessage standardMessage) {
String guid = getItemValue(standardMessage, getPath(GUID));
if (guid.length() == 36) {
guid = guid.substring(0, 33);
}
return guid;
}
@Override
public String getGuidSeq(StandardMessage standardMessage) {
String guidseq = null;
String guid = getItemValue(standardMessage, getPath(GUID));
if (guid.length() == 36) {
guidseq = guid.substring(33);
} else {
guidseq = "000";
}
return guidseq;
}
@Override
public void setGuidSeq(StandardMessage standardMessage, String guidSeq) {
setItemValue(standardMessage, getPath(GUID), getGuid(standardMessage) + guidSeq);
}
@Override
public String getOrgGuid(StandardMessage standardMessage) {
String orgGuid = getItemValue(standardMessage, getPath(GUID_ORG));
if (orgGuid.length() == 36) {
orgGuid = orgGuid.substring(0, 33);
}
return orgGuid;
}
@Override
public void setOrgGuid(StandardMessage standardMessage, String orgGuid) {
if (orgGuid.length() == 36) {
orgGuid = orgGuid.substring(0, 33);
}
setItemValue(standardMessage, getPath(GUID_ORG), orgGuid);
}
@Override
public String nextGuidSeq(StandardMessage standardMessage) {
String guidSeq = getGuidSeq(standardMessage);
if (guidSeq == null)
return "";
int seq = 0;
try {
seq = Integer.parseInt(guidSeq) + 1;
} catch (NumberFormatException e) {
seq = 1;
}
guidSeq = StringUtil.stringFormat(Integer.toString(seq), true, '0', 3);
setGuidSeq(standardMessage, guidSeq);
return guidSeq;
}
/**
* 표준전문의 복원은 COMMON.ORTR_RESTR_YN 의 value는 (Y/N) 엔진에서 복원여부 의 value는 (1/0)
*/
@Override
public String getRecoverYn(StandardMessage standardMessage) {
String data = getItemValue(standardMessage, getPath(RECOVER_YN));
if ("Y".equals(data)) {
return "1";
} else {
return "0";
}
}
@Override
public void setRecoverYn(StandardMessage standardMessage, String recoverYn) {
if ("1".equals(recoverYn)) {
setItemValue(standardMessage, getPath(RECOVER_YN), "Y");
} else {
setItemValue(standardMessage, getPath(RECOVER_YN), "N");
}
}
@Override
public String getInstCode(StandardMessage standardMessage) {
EAIServerManager server = EAIServerManager.getInstance();
if (server != null && server.isMCI()) {
return getItemValue(standardMessage, INSTANCE_ID);
} else {
return "";
}
}
@Override
public void setInstCode(StandardMessage standardMessage, String instCode) {
EAIServerManager server = EAIServerManager.getInstance();
if (server != null && server.isMCI()) {
setItemValue(standardMessage, INSTANCE_ID, instCode);
}
}
@Override
public String getSessionId(StandardMessage standardMessage) {
EAIServerManager server = EAIServerManager.getInstance();
if (server != null && server.isMCI()) {
return getItemValue(standardMessage, SESSION_ID);
} else {
return "";
}
}
@Override
public void setSessionId(StandardMessage standardMessage, String sessionId) {
EAIServerManager server = EAIServerManager.getInstance();
if (server != null && server.isMCI()) {
setItemValue(standardMessage, SESSION_ID, sessionId);
}
}
/*
* 엔진 에서는 public static final String RESPONSE_TYPE_CODE_N = "0";//정상(normal)
* public static final String RESPONSE_TYPE_CODE_E = "1";//오류(error)
*/
@Override
public void setResponseType(StandardMessage standardMessage, String responseType) {
if (responseType != null && (STDMessageKeys.RESPONSE_TYPE_CODE_N.equals(responseType)
|| STDMessageKeys.RESPONSE_TYPE_CODE_E.equals(responseType))) {
if (STDMessageKeys.RESPONSE_TYPE_CODE_N.equals(responseType)) {
setItemValue(standardMessage, getPath(RESPONSE_TYPE), "NR");
} else {
setItemValue(standardMessage, getPath(RESPONSE_TYPE), "ER");
}
} else {
setItemValue(standardMessage, getPath(RESPONSE_TYPE), responseType);
}
}
@Override
public String getInterfaceId(StandardMessage standardMessage) {
String interfaceId = getItemValue(standardMessage, getPath(INTERFACE_ID));
if (interfaceId == null)
return "";
interfaceId = interfaceId.trim();
return interfaceId;
}
@Override
public String getReqSysCode(StandardMessage standardMessage) {
// apiPath의 값에서 추출할 예정 : serviceId = api_path
String apiPath = getItemValue(standardMessage, getPath(SERVICE_ID));
if (apiPath != null) {
String[] split = apiPath.split("/");
if (split.length > 2) {
String route = split[1].toUpperCase();
if (route.length() > 3) {
route = route.substring(0, 3);
}
return route;
}
}
return null;
}
}
@@ -1,50 +0,0 @@
package com.eactive.eai.custom.message;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.service.DefaultInterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageKeys;
public class InterfaceMapperKBANK extends DefaultInterfaceMapper {
private static final long serialVersionUID = 1L;
//전문작성일시
String ITEM_TLGR_WRTN_DT = "header_part.tlgrWrtnDt";
//전문생성시스템
String ITEM_TLGR_CRTN_SYS_NM = "header_part.tlgrCrtnSysNm";
//전문일련번호
String ITEM_TLGR_SRL_NO = "header_part.tlgrSrlNo";
@Override
public String getInExDivision(StandardMessage standardMessage) {
return "2";
}
@Override
public void setGuid(StandardMessage standardMessage, String guid) {
String tlgrWrtnDt = StringUtils.substring(guid, 0, 14);
String tlgrCrtnSysNm = StringUtils.substring(guid, 14, 22);
String tlgrSrlNo = StringUtils.substring(guid, 22, 30);
setItemValue(standardMessage, ITEM_TLGR_WRTN_DT, tlgrWrtnDt);
setItemValue(standardMessage, ITEM_TLGR_CRTN_SYS_NM, tlgrCrtnSysNm);
setItemValue(standardMessage, ITEM_TLGR_SRL_NO, tlgrSrlNo);
}
@Override
public void setGuidSeq(StandardMessage standardMessage, String guidSeq) {
if(guidSeq.length() == 1) {
guidSeq = "0"+guidSeq;
}
super.setGuidSeq(standardMessage, guidSeq);
}
@Override
public String getGuid(StandardMessage standardMessage) {
String tlgrWrtnDt = getItemValue(standardMessage, ITEM_TLGR_WRTN_DT);
String tlgrCrtnSysNm = getItemValue(standardMessage, ITEM_TLGR_CRTN_SYS_NM);
String tlgrSrlNo = getItemValue(standardMessage, ITEM_TLGR_SRL_NO);
return tlgrWrtnDt+tlgrCrtnSysNm+tlgrSrlNo;
}
}
@@ -1,202 +0,0 @@
package com.eactive.eai.custom.message;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.StringUtil;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.service.DefaultInterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageKeys;
@SuppressWarnings("serial")
public class InterfaceMapperKJB extends DefaultInterfaceMapper {
private static String SESSION_ID = "INTERFACE_COMMON.MCI_SESN_ID";
private static String INSTANCE_ID = "INTERFACE_COMMON.MCI_INSTNC_ID";
@Override
public String getEaiSvcCode(StandardMessage standardMessage) {
String eaiSvcCode = null;
String interfaceId = getInterfaceId(standardMessage);
String returnType = getSendRecvDivision(standardMessage); // S | R
String inExDivision = getInExDivision(standardMessage); // 1 | 2
if (interfaceId == null)
interfaceId = "";
interfaceId = interfaceId.trim();
// TODO : site에 맞게 조합해야 함.
eaiSvcCode = interfaceId + returnType + StringUtils.defaultString(inExDivision);
return eaiSvcCode;
}
@Override
public void setGuid(StandardMessage standardMessage, String guid) {
if (guid == null)
throw new RuntimeException("guid is null");
if (guid.length() != 36)
throw new RuntimeException("The length of guid is not 36");
setItemValue(standardMessage, getPath(GUID), guid);
}
@Override
public String getGuid(StandardMessage standardMessage) {
String guid = getItemValue(standardMessage, getPath(GUID));
if (guid.length() == 36) {
guid = guid.substring(0, 33);
}
return guid;
}
@Override
public String getGuidSeq(StandardMessage standardMessage) {
String guidseq = null;
String guid = getItemValue(standardMessage, getPath(GUID));
if (guid.length() == 36) {
guidseq = guid.substring(33);
} else {
guidseq = "000";
}
return guidseq;
}
@Override
public void setGuidSeq(StandardMessage standardMessage, String guidSeq) {
setItemValue(standardMessage, getPath(GUID), getGuid(standardMessage) + guidSeq);
}
@Override
public String getOrgGuid(StandardMessage standardMessage) {
String orgGuid = getItemValue(standardMessage, getPath(GUID));
if (orgGuid.length() == 36) {
orgGuid = orgGuid.substring(0, 33);
}
return orgGuid;
}
@Override
public void setOrgGuid(StandardMessage standardMessage, String orgGuid) {
if (orgGuid.length() == 36) {
orgGuid = orgGuid.substring(0, 33);
}
setItemValue(standardMessage, getPath(GUID_ORG), orgGuid);
}
@Override
public String nextGuidSeq(StandardMessage standardMessage) {
String guidSeq = getGuidSeq(standardMessage);
if (guidSeq == null)
return "";
int seq = 0;
try {
seq = Integer.parseInt(guidSeq) + 1;
} catch (NumberFormatException e) {
seq = 1;
}
guidSeq = StringUtil.stringFormat(Integer.toString(seq), true, '0', 3);
setGuidSeq(standardMessage, guidSeq);
return guidSeq;
}
/**
* 표준전문의 복원은 COMMON.ORTR_RESTR_YN 의 value는 (Y/N) 엔진에서 복원여부 의 value는 (1/0)
*/
@Override
public String getRecoverYn(StandardMessage standardMessage) {
String data = getItemValue(standardMessage, getPath(RECOVER_YN));
if ("Y".equals(data)) {
return "1";
} else {
return "0";
}
}
@Override
public void setRecoverYn(StandardMessage standardMessage, String recoverYn) {
if ("1".equals(recoverYn)) {
setItemValue(standardMessage, getPath(RECOVER_YN), "Y");
} else {
setItemValue(standardMessage, getPath(RECOVER_YN), "N");
}
}
@Override
public String getInstCode(StandardMessage standardMessage) {
EAIServerManager server = EAIServerManager.getInstance();
if (server != null && server.isMCI()) {
return getItemValue(standardMessage, INSTANCE_ID);
} else {
return "";
}
}
@Override
public void setInstCode(StandardMessage standardMessage, String instCode) {
EAIServerManager server = EAIServerManager.getInstance();
if (server != null && server.isMCI()) {
setItemValue(standardMessage, INSTANCE_ID, instCode);
}
}
@Override
public String getSessionId(StandardMessage standardMessage) {
EAIServerManager server = EAIServerManager.getInstance();
if (server != null && server.isMCI()) {
return getItemValue(standardMessage, SESSION_ID);
} else {
return "";
}
}
@Override
public void setSessionId(StandardMessage standardMessage, String sessionId) {
EAIServerManager server = EAIServerManager.getInstance();
if (server != null && server.isMCI()) {
setItemValue(standardMessage, SESSION_ID, sessionId);
}
}
/*
* 엔진 에서는 public static final String RESPONSE_TYPE_CODE_N = "0";//정상(normal)
* public static final String RESPONSE_TYPE_CODE_E = "1";//오류(error)
*/
@Override
public void setResponseType(StandardMessage standardMessage, String responseType) {
if (responseType != null && (STDMessageKeys.RESPONSE_TYPE_CODE_N.equals(responseType)
|| STDMessageKeys.RESPONSE_TYPE_CODE_E.equals(responseType))) {
if (STDMessageKeys.RESPONSE_TYPE_CODE_N.equals(responseType)) {
setItemValue(standardMessage, getPath(RESPONSE_TYPE), "NR");
} else {
setItemValue(standardMessage, getPath(RESPONSE_TYPE), "ER");
}
} else {
setItemValue(standardMessage, getPath(RESPONSE_TYPE), responseType);
}
}
@Override
public String getInterfaceId(StandardMessage standardMessage) {
String interfaceId = getItemValue(standardMessage, getPath(INTERFACE_ID));
if (interfaceId == null)
return "";
interfaceId = interfaceId.trim();
return interfaceId;
}
@Override
public String getReqSysCode(StandardMessage standardMessage) {
// apiPath의 값에서 추출할 예정 : serviceId = api_path
String apiPath = getItemValue(standardMessage, getPath(SERVICE_ID));
if (apiPath != null) {
String[] split = apiPath.split("/");
if (split.length > 2) {
String route = split[1].toUpperCase();
if (route.length() > 3) {
route = route.substring(0, 3);
}
return route;
}
}
return null;
}
}
@@ -1,21 +0,0 @@
package com.eactive.eai.custom.message;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.service.DefaultInterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageKeys;
@SuppressWarnings("serial")
public class InterfaceMapperSBI extends DefaultInterfaceMapper {
@Override
public String getSendRecvDivision(StandardMessage standardMessage) {
String sendRecvDivision = super.getSendRecvDivision(standardMessage);
if (StringUtils.equals(sendRecvDivision, "Q")) {
return STDMessageKeys.SEND_RECV_CD_SEND;
} else {
return sendRecvDivision;
}
}
}
@@ -5,7 +5,10 @@ import java.net.NetworkInterface;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
@@ -15,6 +18,7 @@ import com.eactive.eai.common.util.MessageUtil;
import com.eactive.eai.inbound.processor.ProcessVO;
import com.eactive.eai.message.StandardItem;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.StandardType;
import com.eactive.eai.message.manager.StandardMessageManager;
import com.eactive.eai.message.service.DefaultStandardMessageCoordinator;
import com.eactive.eai.message.service.InterfaceMapper;
@@ -36,6 +40,10 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
private static final DateTimeFormatter FMT_DATE = DateTimeFormatter.ofPattern("yyyyMMdd");
private static final DateTimeFormatter FMT_TIME_MILLIS = DateTimeFormatter.ofPattern("HHmmssSSS");
// ${callProp.key} 또는 ${callProp.key:기본값} 패턴
private static final Pattern CALL_PROP_PATTERN =
Pattern.compile("\\$\\{callProp\\.([^}:]+)(?::([^}]*))?\\}");
// HEAD 필드 경로
private static final String HEAD_FRST_MESG_DMAN_DT = "HEAD.frst_mesg_dman_dt";
private static final String HEAD_FRST_MESG_DMAN_TIME = "HEAD.frst_mesg_dman_time";
@@ -67,9 +75,15 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
// DATA 영역 경로
private static final String DATA_SCOP_LEN = "DATA.data_scop_len";
private String[] netInfo;
@Override
public void coordinateAfterParsing(StandardMessage standardMessage, Object paramObject, Properties prop) {
// TODO 표준전문을 수신할 경우, 전문의 interface id로 가져온 eaiSvcCd가 다른 값으로 치환되어야 할 수도 있다.
// 수신한 if_id를 기준으로 api gw의 eaiSvcCd를 매핑하는 프러퍼티가 있어야 한다.
// PropGroup : DJB_IN_STDHEAD_IFID_MAPPING, DJB_IN_HTTHEAD_STDHEAD_MAPPING
// standardMessage.setEaiSvcCd(mappedIfId);
}
@Override
@@ -78,7 +92,7 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
InterfaceMapper mapper = manager.getMapper();
// GUID 생성 (40자) 및 설정
String guid = GUIDGeneratorDJB.getGUID("EAI");
String guid = GUIDGeneratorDJB.getGUID("OPA");
mapper.setGuid(standardMessage, guid);
// GUID 진행번호 초기화 (최초=001)
@@ -112,6 +126,9 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
if (ezdataItem != null && evaluateBlockCondition(standardMessage, ezdataItem)) {
setEzdataFields(standardMessage, ezdataItem, ipv4, mac);
}
// refValue="${callProp.키}" 필드에 Properties 값 주입
resolveCallPropRefValues(standardMessage, prop);
}
@Override
@@ -230,6 +247,67 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
// private helpers
// ----------------------------------------------------------------
private void resolveCallPropRefValues(StandardMessage standardMessage, Properties prop) {
if (prop == null) return;
resolveCallPropInChilds(standardMessage.getChilds(), prop);
}
private void resolveCallPropInChilds(LinkedHashMap<String, StandardItem> childs, Properties prop) {
if (childs == null) return;
for (StandardItem item : childs.values()) {
int type = item.getType();
if (type == StandardType.FIELD) {
String refValue = item.getRefValue();
if (refValue == null) continue;
Matcher m = CALL_PROP_PATTERN.matcher(refValue);
if (m.matches()) {
String key = m.group(1);
String defaultVal = m.group(2) != null ? m.group(2) : "";
String resolved = resolveCallPropValue(prop, key);
item.setValue(resolved != null ? resolved : defaultVal);
}
} else if (type == StandardType.GROUP) {
resolveCallPropInChilds(item.getChilds(), prop);
}
// GRID, FARRAY, BIZDATA: 배열/업무데이터 영역은 건너뜀
}
}
/**
* Properties/Map 중첩 구조에서 점(.) 구분 keyPath로 값을 탐색한다.
* Properties는 Map을 구현하므로 Map<?,?> 단일 메서드로 통일한다.
* - "aaa.bbb" : map.get("aaa")가 Map(Properties 포함)이면 그 안에서 "bbb" 재귀 조회
* - 중간 값이 Map이 아니면 전체 keyPath로 폴백 조회
* - 값을 찾지 못하면 null 반환
*/
private String resolveCallPropValue(Properties props, String keyPath) {
return resolveNestedValue(props, keyPath);
}
@SuppressWarnings("unchecked")
private String resolveNestedValue(Map<?, ?> map, String keyPath) {
int dotIdx = keyPath.indexOf('.');
if (dotIdx < 0) {
Object val = map.get(keyPath);
if (val == null) return null;
if (val instanceof String) return (String) val;
return val.toString();
}
String first = keyPath.substring(0, dotIdx);
String rest = keyPath.substring(dotIdx + 1);
Object val = map.get(first);
if (val instanceof Map) {
return resolveNestedValue((Map<?, ?>) val, rest);
}
// 폴백: 전체 keyPath를 단일 키로 조회
Object direct = map.get(keyPath);
if (direct == null) return null;
if (direct instanceof String) return (String) direct;
return direct.toString();
}
private String getSysEnvDvcd(EAIServerManager server) {
if (server.isPEAIServer()) return "P"; // 운영
if (server.isSEAIServer()) return "T"; // 검증/테스트
@@ -237,6 +315,9 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
}
private String[] collectNetworkInfo() {
if(this.netInfo != null)
return this.netInfo;
String ipv4 = "";
String mac = "";
try {
@@ -257,7 +338,8 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
} catch (Exception e) {
if (logger.isWarn()) logger.warn("Failed to collect network info", e);
}
return new String[]{ipv4, mac};
this.netInfo = new String[]{ipv4, mac};
return this.netInfo;
}
private void setEzdataFields(StandardMessage standardMessage, StandardItem ezdataItem, String ipv4, String mac) {
@@ -1,419 +0,0 @@
package com.eactive.eai.custom.message;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey;
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.DatetimeUtil;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageUtil;
import com.eactive.eai.custom.stderrorcode.ChannelErrorCodeManager;
import com.eactive.eai.custom.stderrorcode.ChannelErrorCodeVO;
import com.eactive.eai.custom.stderrorcode.StdErrorCodeManager;
import com.eactive.eai.custom.stderrorcode.StdErrorCodeVO;
import com.eactive.eai.inbound.error.InboundErrorKeys;
import com.eactive.eai.inbound.processor.ProcessVO;
import com.eactive.eai.message.StandardItem;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.manager.StandardMessageManager;
import com.eactive.eai.message.service.DefaultStandardMessageCoordinator;
import com.eactive.eai.message.service.InterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageErrorKeys;
import com.ext.eai.common.stdmessage.STDMessageKeys;
public class StandardMessageCoordinatorKAKAOCARD extends DefaultStandardMessageCoordinator {
static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
//private static int defaultTimeout = 30;
private static String GW_SESSION_ID = "INTERFACE_COMMON.GTWY_SESN_ID";
private static String GW_INSTANCE_ID = "INTERFACE_COMMON.GTWY_INSTNC_ID";
private static String MESSAGE_OUT_ATRB_CD = "MESSAGE.OUT_ATRB_CD";//출력속성코드
private static String MESSAGE_OUT_MSG_DESC = "MESSAGE.OUT_MSG_DESC";//출력메시지설명
private static String COMMON_OUT_FMSG_DSTCD = "COMMON.OUT_FMSG_DSTCD";//출력전문구별코드
private static String MESSAGE = "MESSAGE";//메시지부
@Override
public void coordinateAfterParsing(StandardMessage standardMessage, Object paramObject, Properties prop) {
StandardMessageManager standardManager = StandardMessageManager.getInstance();
InterfaceMapper mapper = standardManager.getMapper();
//표준에서 들어올때 표준전문의 값을 header에 셋팅
//표준전문 to prop
if (EAIServerManager.getInstance().isFEP()) {
StandardItem gwSesnId = standardMessage.findItem(GW_SESSION_ID);//transactionId
StandardItem gwNodeNo = standardMessage.findItem(GW_INSTANCE_ID);//instanceId
if (gwSesnId != null && gwNodeNo != null && StringUtils.isNotBlank(gwSesnId.getValue()) && StringUtils.isNotBlank(gwNodeNo.getValue())) {
prop.put(HttpClientAdapterServiceKey.TRANSACTION_ID, gwSesnId.getValue());
prop.put(HttpClientAdapterServiceKey.INSTANCE_ID, gwNodeNo.getValue());
}
}
// REST용 전달값 중 api_path 이후의 값을 표준전문 API_PATH에 셋팅
String adapterApiPath = prop.getProperty(HttpAdapterServiceKey.API_PATH);
if (StringUtils.isNotBlank(adapterApiPath)) {
String adapterExtUri = prop.getProperty(HttpAdapterServiceKey.INBOUND_EXTURI);
/*
* apiPath 나머지를 추출하기 위해서
* 예) 어댑터에 설정되어 있는 API_PATH = /api/cts
* 어댑터에 들어온 INBOUND_EXTURI = /api/cts/cmb/api/user/custom
* 표준전문에 셋팅하고 싶은값 /cmb/api/user/custom
*/
String standardApiPath = adapterExtUri.replaceAll(adapterApiPath, "");
if (!standardApiPath.startsWith("/")) {
standardApiPath = standardApiPath + "/";
}
if (standardApiPath.length() > 1) {
mapper.setServiceId(standardMessage,standardApiPath);
}
}
//아래로직은 표준전문에서 요청일때 MESSAGE부가 안보이고 응답일때 MESSAGE부 보이게 설정
String sendRecvDivision = mapper.getSendRecvDivision(standardMessage);
StandardItem msg = standardMessage.findItem(MESSAGE);
if (StringUtils.equals(sendRecvDivision, STDMessageKeys.SEND_RECV_CD_SEND)) {
msg.setHidden(true);
}
if (StringUtils.equals(sendRecvDivision, STDMessageKeys.SEND_RECV_CD_RECV)) {
msg.setHidden(false);
}
//mci이고 요청 거래시에 설정 인스턴스ID설정
EAIServerManager server = EAIServerManager.getInstance();
if (server != null && server.isMCI() && (StringUtils.equals(sendRecvDivision, STDMessageKeys.SEND_RECV_CD_SEND))) {
//인스턴스ID설정
String instCode = mapper.getInstCode(standardMessage);
String localServer = server.getLocalServerName();
if (instCode != null && localServer != null) {
mapper.setInstCode(standardMessage, localServer);
}
//타임아웃값이 없을경우 default값 설정
String timeout = mapper.getTimeout(standardMessage);
int defaultTimeout = getDefaultTimeout();
if (StringUtils.isBlank(timeout)) {
mapper.setTimeout(standardMessage, Integer.toString(defaultTimeout));
}else {
try {
Integer.parseInt(timeout);
}catch(Exception e) {
mapper.setTimeout(standardMessage, Integer.toString(defaultTimeout));
}
}
}
//TODO 표준전문 메시지 설정해야됨
//표준전문에 메시지 부에 값이 있을경우 처리
if (!msg.isHidden()) {
String errmsg = mapper.getErrorMsg(standardMessage);
if (StringUtils.isBlank(errmsg)) {
String errCode = mapper.getErrorCode(standardMessage);
if (StringUtils.isNotBlank(errCode)) {
StdErrorCodeManager manager = StdErrorCodeManager.getInstance();
StdErrorCodeVO vo = manager.getSTDErrorCode(errCode);
if (vo != null) {
mapper.setErrorMsg(standardMessage, vo.getErrMsg());
if (server != null && server.isMCI()) {
String type = mapper.getChannelDetailCd(standardMessage);
//채널오류코드 셋팅
ChannelErrorCodeManager cmanager = ChannelErrorCodeManager.getInstance();
ChannelErrorCodeVO cvo = cmanager.getChannelErrorCode(errCode+"_"+type);
if (cvo != null) {
mapper.setErrorMsg(standardMessage, cvo.getErrMsg());
}
}
}
}
}
}
}
@Override
//비표준처리
public void coordinateAfterCreateMessageByRule(StandardMessage standardMessage, Object paramObject, Properties prop) {
StandardMessageManager standardManager = StandardMessageManager.getInstance();
InterfaceMapper mapper = standardManager.getMapper();
//비표준에서 들어올때 header값을 표준전문에 셋팅
//prop to 표준전문
if (EAIServerManager.getInstance().isFEP()) {
String trandactionId = prop.getProperty(HttpClientAdapterServiceKey.TRANSACTION_ID);
String instanceId = prop.getProperty(HttpClientAdapterServiceKey.INSTANCE_ID);
if (StringUtils.isNotBlank(trandactionId) && StringUtils.isNotBlank(instanceId)) {
StandardItem gwSesnId = standardMessage.findItem(GW_SESSION_ID);//transactionId
if (gwSesnId != null) {
gwSesnId.setValue(trandactionId);
}
StandardItem gwNodeNo = standardMessage.findItem(GW_INSTANCE_ID);//instanceId
if (gwNodeNo != null) {
gwNodeNo.setValue(instanceId);
}
}
}
EAIServerManager eaiServerManager = EAIServerManager.getInstance();
//HEADER.GUID설정
mapper.setGuid(standardMessage,GUIDGeneratorKAKAOCARD.getGUID(eaiServerManager.getSystemType()));
//HEADER.FMSG_REQ_RES_DSTCD 전문요청응답구별코드 : 표준전문값
//HEADER.FRST_TRNM_IPAD 최초전송IP주소
mapper.setFirstReqIp(standardMessage, "0.0.0.0");
//HEADER.GNRZ_TMOT_TM 총괄타임아웃시간
mapper.setTimeout(standardMessage, "180");
// HEADER.SYS_ENV_DSTCD 시스템운영환경구분코드
String operationEnv = mapper.getOperationEnv(standardMessage);
if (operationEnv != null && StringUtils.isBlank(operationEnv)) {
mapper.setOperationEnv(standardMessage, getSysOprtEnvDvcd(eaiServerManager));
}
// HEADER.CARD_TX_TYP_DSTCD 거래유형구별코드
StandardItem cardTxTypDstcd = standardMessage.findItem("HEADER.CARD_TX_TYP_DSTCD");
if (cardTxTypDstcd != null ) {
cardTxTypDstcd.setValue("O");
}
//COMMON.GROUP_CMP_CD 그룹회사코드
StandardItem groupCmpCd = standardMessage.findItem("COMMON.GROUP_CMP_CD");
if (groupCmpCd != null ) {
groupCmpCd.setValue("090");
}
//COMMON.TX_BRCD 거래부점코드
StandardItem txBrcd = standardMessage.findItem("COMMON.TX_BRCD");
if (txBrcd != null ) {
txBrcd.setValue("0000");
}
//COMMON.RLTR_BRCD 실거래부점코드
StandardItem rltrBrcd = standardMessage.findItem("COMMON.RLTR_BRCD");
if (rltrBrcd != null ) {
rltrBrcd.setValue("0000");
}
//COMMON.TLRNO 텔러번호
StandardItem tlrno = standardMessage.findItem("COMMON.TLRNO");
if (tlrno != null ) {
tlrno.setValue("000000");
}
//COMMON.TX_DT 거래일자
StandardItem txDt = standardMessage.findItem("COMMON.TX_DT");
if (txDt != null ) {
txDt.setValue(DatetimeUtil.getFormattedDate("yyyyMMdd"));
}
//COMMON.TX_TM 거래시간
StandardItem txTm = standardMessage.findItem("COMMON.TX_TM");
if (txTm != null ) {
txTm.setValue(DatetimeUtil.getFormattedDate("HHmmssSSS"));
}
//아래로직은 표준전문에서 요청일때 MESSAGE부가 안보이고 응답일때 MESSAGE부 보이게 설정
String sendRecvDivision = mapper.getSendRecvDivision(standardMessage);
StandardItem msg = standardMessage.findItem(MESSAGE);
if (StringUtils.equals(sendRecvDivision, STDMessageKeys.SEND_RECV_CD_SEND)) {
msg.setHidden(true);
}
if (StringUtils.equals(sendRecvDivision, STDMessageKeys.SEND_RECV_CD_RECV)) {
msg.setHidden(false);
}
//TODO 표준전문 메시지 설정해야됨
//응답일경우 MESSAGE부에 정상 메시지 헤더를 설정하기 위해서
if (StringUtils.equals(sendRecvDivision, STDMessageKeys.SEND_RECV_CD_RECV)) {
StandardItem outputAtrbCd = standardMessage.findItem(MESSAGE_OUT_ATRB_CD);//출력속성코드
outputAtrbCd.setValue("1");
mapper.setErrorCode(standardMessage, STDMessageErrorKeys.SUCCESS_CODE_VALUE);
mapper.setErrorMsg(standardMessage, STDMessageErrorKeys.SUCCESS_MSG_VALUE);
mapper.setResponseType(standardMessage, STDMessageKeys.RESPONSE_TYPE_CODE_N);
}
}
@Override
public void coordinateInReturnObject(StandardMessage standardMessage) {
//아래로직은 표준전문에서 응답일때 MESSAGE부가 보이게 하기위해서
StandardMessageManager standardManager = StandardMessageManager.getInstance();
InterfaceMapper mapper = standardManager.getMapper();
mapper.setSendRecvDivision(standardMessage, STDMessageKeys.SEND_RECV_CD_RECV);
StandardItem msg = standardMessage.findItem(MESSAGE);
msg.setHidden(false);
}
public String getSysOprtEnvDvcd(EAIServerManager eaiServerManager) {
String result = "";
if (eaiServerManager.isPEAIServer()) { // 운영
result = "R";
} else if (eaiServerManager.isDEAIServer()) { // 개발
result = "D";
} else if (eaiServerManager.isSEAIServer()) { // 테스트/검증
result = "T";
}
return result;
}
@Override
public void coordinateBeforeInboundErrorResponse(StandardMessage standardMessage) {
StandardMessageManager standardManager = StandardMessageManager.getInstance();
InterfaceMapper mapper = standardManager.getMapper();
mapper.setSendRecvDivision(standardMessage, STDMessageKeys.SEND_RECV_CD_RECV);
StandardItem msg = standardMessage.findItem(MESSAGE);
msg.setHidden(false);
}
@Override
public boolean coordinateSetStandardMessageError(StandardMessage standardMessage, InterfaceMapper mapper,
String errCode, String errMsg) {
String siteErrCode = null;
String siteErrMessage = null;
if(errCode != null) {
siteErrCode = MessageUtil.getTobeCode(errCode);
siteErrMessage = MessageUtil.getTobeMessage(errCode);
}
String sendRecvDivision = mapper.getSendRecvDivision(standardMessage);
if (StringUtils.equals(sendRecvDivision, STDMessageKeys.SEND_RECV_CD_RECV)) {
StandardItem msg = standardMessage.findItem(MESSAGE);
msg.setHidden(false);
}
StandardItem outputAtrbCd = standardMessage.findItem(MESSAGE_OUT_ATRB_CD);//출력속성코드
outputAtrbCd.setValue("1");
if (siteErrCode != null) {
mapper.setErrorCode(standardMessage, siteErrCode);
}else if (errCode != null) {
mapper.setErrorCode(standardMessage, errCode);
}
if (siteErrMessage != null) {
mapper.setErrorMsg(standardMessage, siteErrMessage);
}else if (errMsg != null){
mapper.setErrorMsg(standardMessage, errMsg);
}
StandardItem outputMsgDesc = standardMessage.findItem(MESSAGE_OUT_MSG_DESC);//출력메시지설명
if (errMsg != null){
outputMsgDesc.setValue(errMsg);
}
mapper.setResponseType(standardMessage, STDMessageKeys.RESPONSE_TYPE_CODE_E);
return false;
}
@Override
//복원시
public void coordinateAfterRestored(StandardMessage dbMessage, StandardMessage responseMessage) {
StandardMessageManager standardManager = StandardMessageManager.getInstance();
InterfaceMapper mapper = standardManager.getMapper();
String interfaceId = mapper.getInterfaceId(responseMessage);
mapper.setInterfaceId(dbMessage, interfaceId);
String sendRecvDivision = mapper.getSendRecvDivision(responseMessage);
mapper.setSendRecvDivision(dbMessage, sendRecvDivision);
String inExDivision = mapper.getInExDivision(responseMessage);
mapper.setInExDivision(dbMessage, inExDivision);
String recoverYn = mapper.getRecoverYn(responseMessage);
mapper.setRecoverYn(dbMessage, recoverYn);
//복원시 처리결과수신 서비스코드를 서비스코드에 셋팅한다.
//처리결과수신값이 없을경우 원거래 서비스ID를 셋팅한다.
String returnServiceId = mapper.getReturnServiceId(dbMessage);
if (StringUtils.isBlank(returnServiceId)){
returnServiceId = mapper.getServiceId(dbMessage);
}
mapper.setServiceId(dbMessage, returnServiceId);
//표준전문 메시지 관련 설정
String dbSendRecvDivision = mapper.getSendRecvDivision(dbMessage);
StandardItem msg = dbMessage.findItem(MESSAGE);
if ( StringUtils.equals(dbSendRecvDivision, STDMessageKeys.SEND_RECV_CD_SEND)) {
msg.setHidden(true);
}
if (StringUtils.equals(dbSendRecvDivision, STDMessageKeys.SEND_RECV_CD_RECV)) {
msg.setHidden(false);
}
//응답일경우 MESSAGE부 정상설정
if (StringUtils.equals(dbSendRecvDivision, STDMessageKeys.SEND_RECV_CD_RECV)) {
StandardItem outputAtrbCd = dbMessage.findItem(MESSAGE_OUT_ATRB_CD);//출력속성코드
outputAtrbCd.setValue("1");
mapper.setErrorCode(dbMessage, STDMessageErrorKeys.SUCCESS_CODE_VALUE);//출력메시지코드
mapper.setErrorMsg(dbMessage, STDMessageErrorKeys.SUCCESS_MSG_VALUE);//출력메시지내용
mapper.setResponseType(dbMessage, STDMessageKeys.RESPONSE_TYPE_CODE_N);
}
}
@Override
public boolean coordinateIsWaitCheckForSync(StandardMessage responseMessage) {
StandardItem outputMesgTycd = responseMessage.findItem(COMMON_OUT_FMSG_DSTCD);
if (outputMesgTycd != null && StringUtils.equals(outputMesgTycd.getValue(), "9")) {
return true;
}
return false;
}
@Override
public int coordinateForTimeoutCodeToValue(EAIMessage eaiMessage) {
StandardMessageManager standardManager = StandardMessageManager.getInstance();
InterfaceMapper mapper = standardManager.getMapper();
EAIServerManager server = EAIServerManager.getInstance();
if (server != null && server.isMCI()) { //MCI 일경우 처리
StandardMessage standardMessage = eaiMessage.getStandardMessage();
String timeout = mapper.getTimeout(standardMessage);
int defaultTimeout = getDefaultTimeout();
if (StringUtils.isBlank(timeout)) {
return defaultTimeout;
}else {
try {
return Integer.parseInt(timeout);
}catch(Exception e) {
return defaultTimeout;
}
}
}else { //MCI 이외일 경우 처리 (인터페이스에 있는 타임아웃기준)
return eaiMessage.getCurrentSvcMsg().getTmoVl();
}
}
private int getDefaultTimeout() {
PropManager manager = PropManager.getInstance();
int defaultTimeout = 30;
try {
String sdefaultTimeout = manager.getProperty("KAKAO_CARD", "DEFAULT_TIMEOUT", Integer.toString(defaultTimeout));
defaultTimeout = Integer.parseInt(sdefaultTimeout);
}catch(Exception e) {
}
return defaultTimeout;
}
@Override
public boolean coordinateValidation(StandardMessage standardMessage, ProcessVO vo) {
// RECEAIIRP110 인터페이스 ({1}) 에 표준전문 항목 ({2}) 의 값이 없습니다.
// RECEAIIRP120 인터페이스 ({1}) 에 표준전문 항목 ({2}) 의 값을 확인하세요.
StandardMessageManager standardManager = StandardMessageManager.getInstance();
InterfaceMapper mapper = standardManager.getMapper();
String interfaceId = mapper.getInterfaceId(standardMessage);
String guid = mapper.getGuid(standardMessage);
if (StringUtils.isBlank(guid)) {
vo.setRspErrorCode("RECEAIIRP110");
vo.setRspErrorMsg(ExceptionUtil.make(vo.getRspErrorCode(), new String[] { interfaceId, "GUID" }));
vo.setErrTypeCode(InboundErrorKeys.IN_ERROR);
return false;
}
String guidSeq = mapper.getGuidSeq(standardMessage);
if (StringUtils.isBlank(guidSeq)) {
vo.setRspErrorCode("RECEAIIRP110");
vo.setRspErrorMsg(ExceptionUtil.make(vo.getRspErrorCode(), new String[] { interfaceId, "GUID" }));
vo.setErrTypeCode(InboundErrorKeys.IN_ERROR);
return false;
}
if (guid.length() + guidSeq.length() != 36) {
vo.setRspErrorCode("RECEAIIRP120");
vo.setRspErrorMsg(ExceptionUtil.make(vo.getRspErrorCode(), new String[] { interfaceId, "GUID" }));
vo.setErrTypeCode(InboundErrorKeys.IN_ERROR);
return false;
}
return true;
}
}
@@ -1,90 +0,0 @@
package com.eactive.eai.custom.message;
import java.util.Properties;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.server.Keys;
import com.eactive.eai.common.util.DatetimeUtil;
import com.eactive.eai.common.util.MessageUtil;
import com.eactive.eai.common.util.StringUtil;
import com.eactive.eai.message.StandardItem;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.manager.StandardMessageManager;
import com.eactive.eai.message.service.DefaultStandardMessageCoordinator;
import com.eactive.eai.message.service.InterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageKeys;
public class StandardMessageCoordinatorKBANK extends DefaultStandardMessageCoordinator {
private static final String MESSAGE_PART_SUB_MSG_GOUP = "message_part.subMsgGoup";
private static final String MESSAGE_PART_MSG_TYPE = "message_part.msgType";
private static final String MESSAGE_PART = "message_part";
@Override
public void coordinateAfterParsing(StandardMessage standardMessage, Object paramObject, Properties prop) {
}
@Override
public void coordinateAfterCreateMessageByRule(StandardMessage standardMessage, Object paramObject, Properties prop) {
// guid 설정
StandardMessageManager standardManager = StandardMessageManager.getInstance();
InterfaceMapper mapper = standardManager.getMapper();
String guid = GUIDGeneratorKBANK.makeGUID();
mapper.setGuid(standardMessage, guid);
String orgGuid = guid + mapper.getGuidSeq(standardMessage);
mapper.setOrgGuid(standardMessage, orgGuid);
mapper.setOperationEnv(standardMessage, System.getProperty(Keys.EAI_SYSTEMMODE));
mapper.setFirstReqIp(standardMessage, EAIServerManager.getInstance().getServerIp());
}
@Override
public boolean coordinateSetStandardMessageError(StandardMessage standardMessage, InterfaceMapper mapper,
String errCode, String errMsg) {
mapper.setResponseType(standardMessage, STDMessageKeys.RESPONSE_TYPE_CODE_E);
StandardItem messagePart = standardMessage.findItem(MESSAGE_PART);
messagePart.setHidden(false);
messagePart.setSize(1);
StandardItem messageType = standardMessage.findItem(MESSAGE_PART_MSG_TYPE);
messageType.setValue("99");
StandardItem subMsgGoup = standardMessage.findItem(MESSAGE_PART_SUB_MSG_GOUP);
subMsgGoup.getList().clear();
subMsgGoup.setRefValue("0");
if(errCode != null) {
String siteErrCode = MessageUtil.getTobeCode(errCode);
String siteErrMessage;
switch(errCode) {
case("RECEAIIRP070"):
siteErrMessage = "거래 통제 되었습니다.";
break;
default:
siteErrMessage = MessageUtil.getTobeMessage(errCode); break;
}
mapper.setErrorCode(standardMessage, siteErrCode);
mapper.setErrorMsg(standardMessage, siteErrMessage);
}
return false;
}
@Override
public void coordinateAfterRecvNonStdSyncResponse(StandardMessage responseMessage) {
StandardItem messagePart = responseMessage.findItem(MESSAGE_PART);
messagePart.setHidden(false);
messagePart.setSize(1);
StandardItem subMsgGoup = responseMessage.findItem(MESSAGE_PART_SUB_MSG_GOUP);
subMsgGoup.getList().clear();
subMsgGoup.setRefValue("0");
}
}
@@ -1,198 +0,0 @@
package com.eactive.eai.custom.message;
import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.common.dao.Keys;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.DatetimeUtil;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageUtil;
import com.eactive.eai.common.util.StringUtil;
import com.eactive.eai.inbound.processor.ProcessVO;
import com.eactive.eai.inbound.processor.Processor;
import com.eactive.eai.message.StandardItem;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.manager.StandardMessageManager;
import com.eactive.eai.message.service.DefaultStandardMessageCoordinator;
import com.eactive.eai.message.service.InterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageKeys;
import org.apache.commons.lang.StringUtils;
import java.net.UnknownHostException;
import java.util.LinkedHashMap;
import java.util.Properties;
public class StandardMessageCoordinatorKJB extends DefaultStandardMessageCoordinator {
private static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
private static final String MESSAGE_PART = "Message";
private static final String MESSAGE_PART_HEADER_PART = "Message.Msg_Header";
private static final String MESSAGE_PART_MSG_HEDR_KNCD = "Message.Msg_Header.MSG_HEDR_KNCD";
private static final String MESSAGE_PART_MSG_HEDR_LEN = "Message.Msg_Header.MSG_HEDR_LEN";
private static final String MESSAGE_PART_BODY_PART = "Message.Msg_Body";
private static final String MESSAGE_PART_OUTPUT_MSG_CD = "Message.Msg_Body.OUTPUT_MSG_CD";
private static final String MESSAGE_PART_OUTPUT_MSG_CTNT = "Message.Msg_Body.OUTPUT_MSG_CTNT";
private static final String MESSAGE_PART_OUTPUT_MSG_GRID = "Message.Msg_Body.Output_Msg_Grid";
private static final String COMMON_PART_GROUP_CMD_CD = "Common.Service_info.GROUP_CMP_CD";
private static final String COMMON_PART_OTSD_CHNL_INST_CD = "Common.Service_info.OTSD_CHNL_INST_CD";
private static final String DATA_HEADER_DATA_HEDR_LEN = "Data_Part.Data_Header.DATA_HEDR_LEN";
@Override
public void coordinateAfterParsing(StandardMessage standardMessage, Object paramObject, Properties prop) {
}
@Override
public void coordinateBeforeStandardMessageSend(StandardMessage standardMessage, String msgType, String charset) {
makeupDataHeaderLength(standardMessage, charset);
}
@Override
public void coordinateBeforeResponse(StandardMessage standardMessage, ProcessVO processVO, Properties prop, String charset) {
makeupDataHeaderLength(standardMessage, charset);
}
@Override
public void coordinateAfterCreateMessageByRule(StandardMessage standardMessage, Object paramObject, Properties prop) {
// guid 설정
StandardMessageManager standardManager = StandardMessageManager.getInstance();
InterfaceMapper mapper = standardManager.getMapper();
//GUID 설정
String groupCmdCd = standardMessage.findItemValue(COMMON_PART_GROUP_CMD_CD);
String guid = GUIDGeneratorKJB.getGUID(groupCmdCd);
mapper.setGuid(standardMessage, guid);
StandardItem dataHeaderEtc = standardMessage.findItem("Data_Part.Data_Header_Etc");
dataHeaderEtc.setHidden(true);
//기관코드, 텔러번호 설정
//Adapter에 셋팅된 기관코드를 셋팅한다.
String adapterGroupName = prop.getProperty(Processor.ADAPTER_GROUP_NAME);
AdapterManager adapterManager = AdapterManager.getInstance();
AdapterGroupVO adptGrpVO = adapterManager.getAdapterGroupVO(adapterGroupName);
// Adapter의 기관코드를 얻어온다.
//TODO: 기관코드의 경우 현재 EAPIM 시스템에 컬럼은 있으나 설정을 사용하지 않고있으므로 불필요 할 경우 사용하지 않는다, 필요 할 경우 추가한다.
String inAdapterOsidInstiNo = adptGrpVO.getOsidInstiNo();
if(inAdapterOsidInstiNo != null && inAdapterOsidInstiNo.trim().length() > 0) {
standardMessage.setData(COMMON_PART_OTSD_CHNL_INST_CD, inAdapterOsidInstiNo);
if (logger.isDebug()) {
logger.debug("FIELD SET " + COMMON_PART_OTSD_CHNL_INST_CD + " << "+inAdapterOsidInstiNo);
}
}
//2012-12-17 나영채 차장 타발요청에만 셋팅해달라고 요청
//전문요청일자
standardMessage.setData("Common.BizProc_Info.MESG_DMAN_DT", DatetimeUtil.getCurrentDate());
//전문요청시간
standardMessage.setData("Common.BizProc_Info.MESG_DMAN_TKTM", DatetimeUtil.getFormattedDate("HHmmssSSS"));
//2012-07-24 임의 로 영업일자에 system시간 설정
standardMessage.setData("Common.BizProc_Info.BZOP_DT", DatetimeUtil.getCurrentDate());
EAIServerManager eaiServerManager = EAIServerManager.getInstance();
//비표준일경우 시스템 운영환경 구분코드를 셋팅한다.
standardMessage.setData("Common.Service_info.SYS_OPRT_ENV_DVCD", getSysOprtEnvDvcd(eaiServerManager));
//헤더부 최초전송IP주소 FRST_TRNM_IPAD
try {
standardMessage.setData("Header.Src_System.FRST_TRNM_IPAD", java.net.InetAddress.getLocalHost().getHostAddress());
} catch (UnknownHostException e) {
}
}
@Override
public boolean coordinateSetStandardMessageError(StandardMessage standardMessage, InterfaceMapper mapper,
String errCode, String errMsg) {
mapper.setResponseType(standardMessage, STDMessageKeys.RESPONSE_TYPE_CODE_E);
mapper.setSendRecvDivision(standardMessage, STDMessageKeys.SEND_RECV_CD_RECV);
StandardItem messagePart = standardMessage.findItem(MESSAGE_PART);
messagePart.setHidden(false);
messagePart.setSize(1);
StandardItem messageHeaderPart = standardMessage.findItem(MESSAGE_PART_HEADER_PART);
messageHeaderPart.setSize(1);
StandardItem messageBodyPart = standardMessage.findItem(MESSAGE_PART_BODY_PART);
messageBodyPart.setSize(1);
errCode = StringUtils.defaultString(errCode);
String siteErrCode = MessageUtil.getTobeCode(errCode);
String siteErrMessage;
switch(errCode) {
case("RECEAIIRP070"):
siteErrMessage = "거래 통제 되었습니다.";
break;
default:
siteErrMessage = MessageUtil.getTobeMessage(errCode);
break;
}
mapper.setErrorCode(standardMessage, siteErrCode);
standardMessage.setData(MESSAGE_PART_MSG_HEDR_KNCD, "EM");
standardMessage.setData(MESSAGE_PART_OUTPUT_MSG_CD, siteErrCode);
StandardItem msgGrid = standardMessage.findItem(MESSAGE_PART_OUTPUT_MSG_GRID);
LinkedHashMap<String, StandardItem> msgGridFirstChilds = msgGrid.getArrayChilds(0, true);
msgGridFirstChilds.get("OUTPUT_MSG_CD").setValue(siteErrCode);
msgGridFirstChilds.get("OUTPUT_MSG_CTNT").setValue(siteErrMessage);
//Message.Msg_Body.OUTPUT_MSG_CTNT
mapper.setErrorMsg(standardMessage, siteErrMessage);
int len = standardMessage.getBytesDataLengthForPath(MESSAGE_PART_BODY_PART);
String lenStr = StringUtils.leftPad(String.valueOf(len), 8, '0');
standardMessage.setData(MESSAGE_PART_MSG_HEDR_LEN, lenStr);
return false;
}
@Override
public void coordinateAfterRecvNonStdSyncResponse(StandardMessage responseMessage) {
StandardItem messagePart = responseMessage.findItem(MESSAGE_PART);
messagePart.setHidden(false);
messagePart.setSize(1);
StandardItem messageHeaderPart = responseMessage.findItem(MESSAGE_PART_HEADER_PART);
messageHeaderPart.setSize(1);
StandardItem messageBodyPart = responseMessage.findItem(MESSAGE_PART_BODY_PART);
messageBodyPart.setSize(1);
responseMessage.setData(MESSAGE_PART_MSG_HEDR_KNCD, "NM");
responseMessage.setData(MESSAGE_PART_OUTPUT_MSG_CD, "100000 ");
responseMessage.setData(MESSAGE_PART_OUTPUT_MSG_CTNT, "정상처리");
StandardItem msgGrid = responseMessage.findItem(MESSAGE_PART_OUTPUT_MSG_GRID);
LinkedHashMap<String, StandardItem> msgGridFirstChilds = msgGrid.getArrayChilds(0, true);
msgGridFirstChilds.get("OUTPUT_MSG_CD").setValue("100000 ");
msgGridFirstChilds.get("OUTPUT_MSG_CTNT").setValue("정상처리");
int len = responseMessage.getBytesDataLengthForPath(MESSAGE_PART_BODY_PART);
String lenStr = StringUtils.leftPad(String.valueOf(len), 8, '0');
responseMessage.setData(MESSAGE_PART_MSG_HEDR_LEN, lenStr);
}
public String getSysOprtEnvDvcd(EAIServerManager eaiServerManager) {
String result = "";
if (eaiServerManager.isPEAIServer()){ //운영
result = STDMessageKeys.SYS_OPRT_ENV_DVCD_ONLINE;
}else if (eaiServerManager.isDEAIServer()){ //개발
result = STDMessageKeys.SYS_OPRT_ENV_DVCD_DEV;
}else if (eaiServerManager.isSEAIServer()){ //테스트/검증
result = STDMessageKeys.SYS_OPRT_ENV_DVCD_TESTSTAGE;
}
return result;
}
private static void makeupDataHeaderLength(StandardMessage standardMessage, String charset) {
String dataBytesLengthStr = null;
try {
dataBytesLengthStr = String.valueOf(standardMessage.getBizDataBytes(charset).length);
String dataHeaderLength = StringUtils.leftPad(dataBytesLengthStr, 8, '0');
standardMessage.setData(DATA_HEADER_DATA_HEDR_LEN, dataHeaderLength);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -1,142 +0,0 @@
package com.eactive.eai.custom.message;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.DatetimeUtil;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.inbound.processor.ProcessVO;
import com.eactive.eai.message.StandardItem;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.manager.StandardMessageManager;
import com.eactive.eai.message.service.DefaultStandardMessageCoordinator;
import com.eactive.eai.message.service.InterfaceMapper;
import com.eactive.eai.message.service.StandardMessageCoordinator;
public class StandardMessageCoordinatorSBI extends DefaultStandardMessageCoordinator {
static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
@Override
public void coordinateAfterCreateMessageByRule(StandardMessage message, Object paramObject, Properties prop) {
// STD_HEADER.mesgDvcd 설정
StandardItem mesgDvcdItem = message.findItem("STD_HEADER.mesgDvcd");
if (mesgDvcdItem != null && StringUtils.equals(mesgDvcdItem.getValue(), "S")) {
mesgDvcdItem.setValue("Q");
}
// STD_HEADER.mesgKind 설정
StandardItem mesgKindItem = message.findItem("STD_HEADER.mesgKind");
if (mesgKindItem != null && StringUtils.isBlank(mesgKindItem.getValue())) {
mesgKindItem.setValue("3"); // 3:데이터 4:시스템
}
// STD_HEADER.envDvcd 설정
StandardItem envDvcdItem = message.findItem("STD_HEADER.envDvcd");
EAIServerManager eaiServerManager = EAIServerManager.getInstance();
if (envDvcdItem != null && StringUtils.isBlank(envDvcdItem.getValue())) {
envDvcdItem.setValue(getSysOprtEnvDvcd(eaiServerManager));
}
// guid 설정
StandardMessageManager standardManager = StandardMessageManager.getInstance();
InterfaceMapper mapper = standardManager.getMapper();
mapper.setGuid(message,
GUIDGeneratorSBI.getGUID(getSysOprtEnvDvcd(eaiServerManager), eaiServerManager.getSystemType()));
// STD_HEADER.frstTrnmChnlCd 설정
StandardItem frstTrnmChnlCdItem = message.findItem("STD_HEADER.frstTrnmChnlCd");
if (frstTrnmChnlCdItem != null && StringUtils.isBlank(frstTrnmChnlCdItem.getValue())) {
frstTrnmChnlCdItem.setValue(eaiServerManager.getSystemType());
}
// STD_HEADER.trnmChnlCd 설정
StandardItem trnmChnlCdItem = message.findItem("STD_HEADER.trnmChnlCd");
if (trnmChnlCdItem != null && StringUtils.isBlank(trnmChnlCdItem.getValue())) {
trnmChnlCdItem.setValue(eaiServerManager.getSystemType());
}
// STD_HEADER.userNo 설정
StandardItem userNoItem = message.findItem("STD_HEADER.userNo");
if (userNoItem != null && StringUtils.isBlank(userNoItem.getValue())) {
ProcessVO processVo = (ProcessVO) paramObject;
if (StringUtils.isNotBlank(processVo.getInAdapterUserEmpid())) {
userNoItem.setValue(eaiServerManager.getSystemType());
}
}
// STD_HEADER.mesgDmndDttm 설정
StandardItem mesgDmndDttmItem = message.findItem("STD_HEADER.mesgDmndDttm");
if (mesgDmndDttmItem != null && StringUtils.isBlank(mesgDmndDttmItem.getValue())) {
mesgDmndDttmItem.setValue(DatetimeUtil.getCurrentTimeMillis());
}
// STD_HEADER.ipAd 설정
StandardItem ipAdItem = message.findItem("STD_HEADER.ipAd");
if (ipAdItem != null && StringUtils.isBlank(ipAdItem.getValue())) {
try {
ipAdItem.setValue(InetAddress.getLocalHost().getHostAddress());
} catch (UnknownHostException e) {
logger.error(e.getMessage());
}
}
// STD_HEADER.mesgTycd 설정
StandardItem mesgTycdItem = message.findItem("STD_HEADER.mesgTycd");
if (mesgTycdItem != null && StringUtils.isBlank(mesgTycdItem.getValue())) {
mesgTycdItem.setValue("1");
}
// STD_HEADER.mesgCntySrno 설정
StandardItem mesgCntySrnoItem = message.findItem("STD_HEADER.mesgCntySrno");
if (mesgCntySrnoItem != null && StringUtils.isBlank(mesgCntySrnoItem.getValue())) {
mesgCntySrnoItem.setValue("00");
}
// STD_HEADER.bfrDtLoinYn 설정
StandardItem bfrDtLoinYnItem = message.findItem("STD_HEADER.bfrDtLoinYn");
if (bfrDtLoinYnItem != null && StringUtils.isBlank(bfrDtLoinYnItem.getValue())) {
bfrDtLoinYnItem.setValue("N");
}
// STD_HEADER.canCrctDvcd 설정
StandardItem canCrctDvcdItem = message.findItem("STD_HEADER.canCrctDvcd");
if (canCrctDvcdItem != null && StringUtils.isBlank(canCrctDvcdItem.getValue())) {
canCrctDvcdItem.setValue("0");
}
// STD_HEADER.cmpgRelmUseDvcd 설정
StandardItem cmpgRelmUseDvcdItem = message.findItem("STD_HEADER.cmpgRelmUseDvcd");
if (cmpgRelmUseDvcdItem != null && StringUtils.isBlank(cmpgRelmUseDvcdItem.getValue())) {
cmpgRelmUseDvcdItem.setValue("0");
}
// STD_HEADER.bzwrSvrCd 설정
StandardItem bzwrSvrCdItem = message.findItem("STD_HEADER.bzwrSvrCd");
if (bzwrSvrCdItem != null && StringUtils.isBlank(bzwrSvrCdItem.getValue())) {
String serverName = eaiServerManager.getLocalServerName();
if (StringUtils.isNotBlank(serverName)) {
String instanceid1 = serverName.substring(0, 2);
String instanceid2 = serverName.substring(serverName.length() - 2, serverName.length());
bzwrSvrCdItem.setValue(StringUtils.upperCase(instanceid1 + instanceid2));
}
}
}
public String getSysOprtEnvDvcd(EAIServerManager eaiServerManager) {
String result = "";
if (eaiServerManager.isPEAIServer()) { // 운영
result = "R";
} else if (eaiServerManager.isDEAIServer()) { // 개발
result = "D";
} else if (eaiServerManager.isSEAIServer()) { // 테스트/검증
result = "T";
}
return result;
}
}
@@ -63,10 +63,11 @@ public class HourStatsAggregator {
// 로그 시퀀스 100: 총 건수만 증가 (첫 호출)
if (logSeq == 100) {
totalCnt.incrementAndGet();
// totalCnt.incrementAndGet();
}
// 로그 시퀀스 400: 응답시간 및 에러 타입 기록
else if (logSeq == 400) {
totalCnt.incrementAndGet();
// 성공 여부 카운트
if (event.isSuccess()) {
successCnt.incrementAndGet();
@@ -63,10 +63,11 @@ public class MinuteStatsAggregator {
// 로그 시퀀스 100: 총 건수만 증가 (첫 호출)
if (logSeq == 100) {
totalCnt.incrementAndGet();
// totalCnt.incrementAndGet();
}
// 로그 시퀀스 400: 응답시간 및 에러 타입 기록
else if (logSeq == 400) {
totalCnt.incrementAndGet();
// 성공 여부 카운트
if (event.isSuccess()) {
successCnt.incrementAndGet();
@@ -22,7 +22,7 @@ public class ApiStatsConfig {
/** 기본값 상수 */
private static final boolean DEFAULT_ENABLED = true;
private static final boolean DEFAULT_MINUTE_ENABLED = true;
private static final boolean DEFAULT_HOUR_ENABLED = true;
private static final boolean DEFAULT_HOUR_ENABLED = false;
private final PropManager propManager;
@@ -0,0 +1,52 @@
package com.eactive.eai.custom.transformer.function;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Stack;
import org.nfunk.jep.ParseException;
import org.nfunk.jep.function.PostfixMathCommand;
import com.eactive.eai.common.security.CryptoModuleService;
/**
* JEP 트랜스포머 함수 — DJB ERP 연동 복호화.
*
* 사용법: DJBErpDecryt(encBase64, moduleName)
*
* 파라미터:
* encBase64 : Base64 인코딩된 암호문
* moduleName : DB에 등록된 암호화 모듈명
*
* 반환값: 복호화된 평문 (String)
*/
public class DJBDecrypt extends PostfixMathCommand {
public DJBDecrypt() {
numberOfParameters = -1;
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public void run(Stack inStack) throws ParseException {
checkStack(inStack);
if (curNumberOfParameters != 2) {
throw new ParseException("DJBErpDecryt: 파라미터는 2개개여야 합니다 (encBase64, moduleName");
}
String moduleName = inStack.pop().toString();
String encBase64 = inStack.pop().toString();
try {
byte[] cipherBytes = Base64.getDecoder().decode(encBase64.trim());
byte[] plainBytes = CryptoModuleService.getInstance().decrypt(moduleName, new HashMap<>(), null, cipherBytes);
inStack.push(new String(plainBytes, StandardCharsets.UTF_8));
} catch (ParseException e) {
throw e;
} catch (Exception e) {
throw new ParseException("DJBErpDecryt 복호화 실패: " + e.getMessage());
}
}
}
@@ -0,0 +1,52 @@
package com.eactive.eai.custom.transformer.function;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Stack;
import org.nfunk.jep.ParseException;
import org.nfunk.jep.function.PostfixMathCommand;
import com.eactive.eai.common.security.CryptoModuleService;
/**
* JEP 트랜스포머 함수 — DJB ERP 연동 암호화.
*
* 사용법: DJBErpEncryt(plainText, moduleName) DJBErpEncryt(plainText, moduleName,
* groupSeq)
*
* 파라미터: plainText : 암호화할 평문 (String) moduleName : DB에 등록된 암호화 모듈명 (String)
* groupSeq : 키 도출용 그룹 시퀀스 (String, 선택). 미전달 시 빈 context로 호출.
*
* 반환값: Base64 인코딩된 암호문 (String)
*/
public class DJBEncrypt extends PostfixMathCommand {
public DJBEncrypt() {
numberOfParameters = -1;
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public void run(Stack inStack) throws ParseException {
checkStack(inStack);
if (curNumberOfParameters != 2) {
throw new ParseException("DJBErpEncryt: 파라미터는 2개여야 합니다 (plainText, moduleName)");
}
String moduleName = inStack.pop().toString();
String plainText = inStack.pop().toString();
try {
byte[] cipherBytes = CryptoModuleService.getInstance().encrypt(moduleName, new HashMap<>(), null,
plainText.getBytes(StandardCharsets.UTF_8));
inStack.push(Base64.getEncoder().encodeToString(cipherBytes));
} catch (ParseException e) {
throw e;
} catch (Exception e) {
throw new ParseException("DJBErpEncryt 암호화 실패: " + e.getMessage());
}
}
}
Binary file not shown.
@@ -1,9 +0,0 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXoqB4PrgZpJISjBe9ht
Y1R3Ne9ehxugWucwA4cBWAnYwvmrRAK0p8p+HuDikdZPq2hyAG02ucNt9xoru+Va
K4spNGieORbh0hmLRdvVBBM7Ureia3WhKED5abNnnPQw+jCLZNVYtO9rbtRhpUEG
t73sN1+0bOZlVBkbLenvWKJs2+tyE0gHhwgS8Fzrb++LHYN/c0KoTm+G9ITuPWoM
Vu/iME5WHqR95TkLKpx6s5J/le4BvncQDmkvKFIX9/DFN57orXQVB2lzDF8fMeWC
xaaHXtgfo2ercKKEdHQ5GFIgWN8+j2ZgU2JqfucazJpOpOGcizHiQKzh//NE7beD
IwIDAQAB
-----END PUBLIC KEY-----
@@ -1,9 +0,0 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqCW0auFk5bqt7OZ2AtFw
xa/se93/hgNwDNC1kxKZpnvNM5YVj5gjlf0jOSVGNJlFTVvjIBcyPC7s1zlFDhgm
ebUKplRuw82lkIkS7mPjsqfPvMQlFjjLgrnECQ3AD86EkRcUT/bVliOtwLY6YJUa
5/1eqZCIRfLPVxOApSHuQLJ9JmSPhttwfKwTED3G2dB85D+QN5+Nre5nnWDjMScT
KOcyUZHOLO6m0UupBYU94XGJG4EEMwzSE/Lq1eJ49/wUsvaKY6Kz5G30d/ANwRZI
ex82Wp91ZPOasKKOB6vnQ/LNcMhhyYf6IzCliMUUFl53YeheXmvfWX6VLfWgjlLk
HQIDAQAB
-----END PUBLIC KEY-----
@@ -1,27 +0,0 @@
#-----------------------------------------------------------------------------
# comment start with #
# level; // 0 : root ~ n
# type; // 0: Message, 1: Field, 2:Group 3, Grid, 4 : Field Array, 9 : BIZ DATA
# size // 0 : variable, > 0 fixed
# fieldType; // 0: ELEMENT, 1: ATTRIBUTE,
# length;
# dataType; // 0: String, 1: Number,10: ZZ String, 11: LL Number
#-----------------------------------------------------------------------------
# name ,level ,type ,size ,fieldType ,length ,dataType ,,refPath, refValue,value
#-----------------------------------------------------------------------------
# name ,level ,type ,size ,fieldType ,length ,dataType ,refPath, refValue, value
commonHeader ,1 ,2 ,1 ,0 ,0 ,0 , , ,,공통헤더
firstReqSystemCode ,2 ,1 ,1 ,0 ,0 ,0 , , ,,최초요청시스템코드
firstReqSystemIp ,2 ,1 ,1 ,0 ,0 ,0 , , ,,최초요청IP주소
msgCreationTime ,2 ,1 ,1 ,0 ,0 ,0 , , ,,전문생성일시
globalId ,2 ,1 ,1 ,0 ,0 ,0 , , ,,guid
traceSeqNo ,2 ,1 ,1 ,0 ,0 ,1 , , ,1,시스템경유이력번호
serviceCode ,2 ,1 ,1 ,0 ,0 ,0 , , ,,거래코드
personalInfoYn ,2 ,1 ,1 ,0 ,0 ,0 , , ,,개인정보포함여부
receivingSystemCode ,2 ,1 ,1 ,0 ,0 ,0 , , ,,수신시스템코드
reqResTypeCode ,2 ,1 ,1 ,0 ,0 ,0 , , ,,요청응답구분코드
msgList ,2 ,3 ,0 ,0 ,0 ,0 , , ,,메시지목록
resultCode ,3 ,1 ,1 ,0 ,0 ,0 , , ,,결과코드
resultMsg ,3 ,1 ,1 ,0 ,0 ,0 , , ,,결과메시지
msgStackTrace ,2 ,1 ,1 ,0 ,0 ,0 , , ,,에러내용
payload ,1 ,9 ,0 ,0 ,0 ,0 , , ,,업무데이터
1 #-----------------------------------------------------------------------------
2 # comment start with #
3 # level; // 0 : root ~ n
4 # type; // 0: Message, 1: Field, 2:Group 3, Grid, 4 : Field Array, 9 : BIZ DATA
5 # size // 0 : variable, > 0 fixed
6 # fieldType; // 0: ELEMENT, 1: ATTRIBUTE,
7 # length;
8 # dataType; // 0: String, 1: Number,10: ZZ String, 11: LL Number
9 #-----------------------------------------------------------------------------
10 # name ,level ,type ,size ,fieldType ,length ,dataType ,,refPath, refValue,value
11 #-----------------------------------------------------------------------------
12 # name ,level ,type ,size ,fieldType ,length ,dataType ,refPath, refValue, value
13 commonHeader ,1 ,2 ,1 ,0 ,0 ,0 , , ,,공통헤더
14 firstReqSystemCode ,2 ,1 ,1 ,0 ,0 ,0 , , ,,최초요청시스템코드
15 firstReqSystemIp ,2 ,1 ,1 ,0 ,0 ,0 , , ,,최초요청IP주소
16 msgCreationTime ,2 ,1 ,1 ,0 ,0 ,0 , , ,,전문생성일시
17 globalId ,2 ,1 ,1 ,0 ,0 ,0 , , ,,guid
18 traceSeqNo ,2 ,1 ,1 ,0 ,0 ,1 , , ,1,시스템경유이력번호
19 serviceCode ,2 ,1 ,1 ,0 ,0 ,0 , , ,,거래코드
20 personalInfoYn ,2 ,1 ,1 ,0 ,0 ,0 , , ,,개인정보포함여부
21 receivingSystemCode ,2 ,1 ,1 ,0 ,0 ,0 , , ,,수신시스템코드
22 reqResTypeCode ,2 ,1 ,1 ,0 ,0 ,0 , , ,,요청응답구분코드
23 msgList ,2 ,3 ,0 ,0 ,0 ,0 , , ,,메시지목록
24 resultCode ,3 ,1 ,1 ,0 ,0 ,0 , , ,,결과코드
25 resultMsg ,3 ,1 ,1 ,0 ,0 ,0 , , ,,결과메시지
26 msgStackTrace ,2 ,1 ,1 ,0 ,0 ,0 , , ,,에러내용
27 payload ,1 ,9 ,0 ,0 ,0 ,0 , , ,,업무데이터
-233
View File
@@ -1,233 +0,0 @@
#-----------------------------------------------------------------------------
# comment start with #
# level; // 0 : root ~ n
# type; // 0: Message, 1: Field, 2:Group 3, Grid, 4 : Field Array, 9 : BIZ DATA
# size // 0 : variable, > 0 fixed
# fieldType; // 0: ELEMENT, 1: ATTRIBUTE,
# length;
# dataType; // 0: String, 1: Number,10: ZZ String, 11: LL Number
#-----------------------------------------------------------------------------
# name ,level ,type ,size ,fieldType ,length ,dataType ,,refPath, refValue,value
#-----------------------------------------------------------------------------
# name ,level ,type ,size ,fieldType ,length ,dataType ,refPath, refValue, value
Header,1,3,1,1,0,1,,,
Sys_Info,2,3,1,1,0,1,,,
STND_MESG_LEN,3,2,1,1,8,12,,,
ENCD_CMPI_DVCD,3,2,1,1,1,1,,,0
GUID,3,2,1,1,36,1,,,
MESG_DMAN_DVCD,3,2,1,1,1,1,,,S
MESG_VER_NO,3,2,1,1,3,1,,,R10
Src_System,2,3,1,1,0,1,,,
FRST_TRNM_IPAD,3,2,1,1,39,1,,,
FRST_TRNM_SYS_CD,3,2,1,1,3,1,,,API
TRNM_SYS_CD,3,2,1,1,3,1,,,
TRNM_NODE_NO,3,2,1,1,4,1,,,
MCI_SESN_ID,3,2,1,1,8,1,,,
GNRZ_TMOT_TKTM,3,2,1,1,3,1,,,070
TX_TMOT_TKTM,3,2,1,1,3,1,,,060
KJB_Add,2,3,1,1,0,1,,,
OTSD_DMAN_SYS_CD,3,2,1,1,3,1,,,OBP
EAI_NODE_NO,3,2,1,1,2,1,,,
FEP_NODE_NO,3,2,1,1,2,1,,,
FEP_SESN_ID,3,2,1,1,6,1,,,
Spare_Zone,2,3,1,1,0,1,,,
HEDR_SPR_CTNT,3,2,1,1,25,1,,,
Common,1,3,1,1,0,1,,,
Service_info,2,3,1,1,0,1,,,
GROUP_CMP_CD,3,2,1,1,3,1,,,034
SRVC_ID,3,2,1,1,11,1,,,
PROCS_RSLT_RCMS_SRVC_ID,3,2,1,1,11,1,,,
IF_ID,3,2,1,1,20,1,,,
TX_SYNZ_DVCD,3,2,1,1,1,1,,,
HMAB_DVCD,3,2,1,1,1,1,,,2
OTSD_CHNL_INST_CD,3,2,1,1,3,1,,,
SYS_OPRT_ENV_DVCD,3,2,1,1,1,1,,,
TX_TYP_DVCD,3,2,1,1,1,1,,,O
ORTR_RESTR_YN,3,2,1,1,1,1,,,
ORTR_GUID,3,2,1,1,36,1,,,
Channel_Info,2,3,1,1,0,1,,,
BANK_CD,3,2,1,1,3,1,,,
TX_BRCD,3,2,1,1,4,1,,,
DSPC_RCV_BRN_DVCD,3,2,1,1,2,1,,,
RLTR_BRCD,3,2,1,1,4,1,,,
TRMN_INSL_BRCD,3,2,1,1,4,1,,,
CHNL_TYCD,3,2,1,1,1,1,,,
CHNL_DTLS_CLCD,3,2,1,1,3,1,,,
TMNL_KIND_DVCD,3,2,1,1,2,1,,,
TRMN_NO,3,2,1,1,6,1,,,
SCN_NO,3,2,1,1,13,1,,,
SCN_FILE_VER,3,2,1,1,10,2,,,
SCN_FILE_NM,3,2,1,1,30,1,,,
LANG_DVCD,3,2,1,1,3,1,,,KOR
CHNL_COM_SCTN_EXIS_YN,3,2,1,1,1,1,,,N
Confirm_Info,2,3,1,1,0,1,,,
PRCG_APRV_PROCS_STCD,3,2,1,1,1,1,,,
PRCG_APRV_TYCD,3,2,1,1,1,1,,,
APRV_PRCG_EMPNO,3,2,1,1,7,1,,,
NURN_RSBT_EMPNO,3,2,1,1,7,1,,,
PRCG_APRV_SEQNO,3,2,1,1,10,2,,,
NURN_AGNCY_APRV_YN,3,2,1,1,1,1,,,
DSGT_PRCG_CHNG_YN,3,2,1,1,1,1,,,
CHNG_DSGT_PRCG_EMPNO,3,2,1,1,7,1,,,
PRCG_APRV_DMAN_RSN,3,2,1,1,40,1,,,
PRCG_APRV_RSN,3,2,1,1,40,1,,,
BizProc_Info,2,3,1,1,0,1,,,
BZOP_DT,3,2,1,1,8,1,,,
ANTT_YN,3,2,1,1,1,1,,,
MESG_IQRY_DVCD,3,2,1,1,1,1,,,
ATMC_CLSN_DVCD,3,2,1,1,1,1,,,
TLRNO,3,2,1,1,7,1,,,
ASST_TLRNO,3,2,1,1,7,1,,,
PSWD_VALDTN_YN,3,2,1,1,1,1,,,
TX_TELR_PSWD,3,2,1,1,44,1,,,
CSIF_IDNT_DVCD,3,2,1,1,3,1,,,
CSIF_ID,3,2,1,1,30,1,,,
CSIF_CUST_NM,3,2,1,1,30,1,,,
CSIF_MASK_REVOC_YN,3,2,1,1,1,1,,,
CUST_PTLET_MASK_YN,3,2,1,1,1,1,,,
IDC_IMG_NO,3,2,1,1,32,1,,,
SMTWKP_TX_YN,3,2,1,1,1,1,,,
SECU_ACCO_REG_YN,3,2,1,1,1,1,,,
ABC_TX_DTLS_DVCD,3,2,1,1,2,1,,,
CLNT_TELR_CSHN_RFLC_YN,3,2,1,1,1,1,,,
SLIP_DIV_YN,3,2,1,1,1,1,,,
SLIP_NO,3,2,1,1,9,1,,,
TELR_SLIP_SEQNO,3,2,1,1,10,2,,,
TELR_CASH_AMT,3,2,1,1,17,2,,,
TELR_CBPC_AMT,3,2,1,1,17,2,,,
TELR_TRFAMT,3,2,1,1,17,2,,,
LOGIN_DVCD,3,2,1,1,1,1,,,
TX_DT_EXTNS_YN ,3,2,1,1,1,1,,,
TX_DT,3,2,1,1,8,1,,,
TX_TIME,3,2,1,1,8,1,,,
SYS_DT,3,2,1,1,8,1,,,
SYS_TIME,3,2,1,1,8,1,,,
MESG_DMAN_DT,3,2,1,1,8,1,,,
MESG_DMAN_TKTM,3,2,1,1,9,1,,,
MESG_CNTY_YN,3,2,1,1,1,1,,,
MESG_RSPN_DT,3,2,1,1,8,1,,,
MESG_RSPN_TKTM,3,2,1,1,9,1,,,
PROCS_RSLT_DVCD,3,2,1,1,2,1,,,
OUTPUT_MESG_TYCD,3,2,1,1,1,1,,,
LRQN_OUTPUT_DSCT_TRGT_YN,3,2,1,1,1,1,,,
MESG_CNTY_SEQNO,3,2,1,1,3,1,,,
Error_Info,2,3,1,1,0,1,,,
ERR_CD,3,2,1,1,6,1,,,
ERR_SYS_CD,3,2,1,1,3,1,,,
KJB_Add,2,3,1,1,0,1,,,
ORTR_SCN_ID,3,2,1,1,13,1,,,
CORP_DPRM_NO,3,2,1,1,5,1,,,
CSIF_IQRY_RSCD,3,2,1,1,2,1,,,
Com_Spare_Zone,2,3,1,1,0,1,,,
COM_SPR_CTNT,3,2,1,1,212,1,,,
Channel_Common,1,3,0,1,0,1,Std_Header.Common.Channel_Info.CHNL_COM_SCTN_EXIS_YN,Y,
Data_Header,2,3,0,1,0,1,,,
DATA_HEDR_KNCD,3,2,1,1,2,1,,,
DATA_HEDR_LEN,3,2,1,1,8,1,,,
Data_For_Each,2,3,0,1,0,1,,,
PSWD_ERR_DVCD,3,2,1,1,2,1,,,
ELFN_CUST_TYCD,3,2,1,1,2,1,,,
USER_ID_S14,3,2,1,1,14,1,,,
MST_ID_S14,3,2,1,1,14,1,,,
SVR_TX_NO,3,2,1,1,10,1,,,
HOST_TX_NO_S10,3,2,1,1,10,1,,,
NEXT_PAGE_EXIS_YN1,3,2,1,1,1,1,,,
SCCR_ISS_CD,3,2,1,1,2,1,,,
SQ1_SCCR_SSBP_NO_SER,3,2,1,1,2,1,,,
SQ2_SCCR_SSBP_NO_SER,3,2,1,1,2,1,,,
SECU_MEDIA_SEQNO_S4,3,2,1,1,4,1,,,
SECU_MEDIA_DTL_DVCD_N3,3,2,1,1,3,1,,,
PAGE_NO,3,2,1,1,5,1,,,
PAGE_SIZE,3,2,1,1,5,1,,,
TTCN_N5,3,2,1,1,5,1,,,
IQRY_CCNT_N5,3,2,1,1,5,1,,,
PRIQR_TX_NO,3,2,1,1,10,1,,,
SQ1_CUST_CNFR_INFO_CTNT_S39,3,2,1,1,39,1,,,
SQ2_CUST_CNFR_INFO_CTNT_S39,3,2,1,1,39,1,,,
MAC_S17,3,2,1,1,17,1,,,
HDD_SEQ_NO_S24,3,2,1,1,24,1,,,
CMCM_CD,3,2,1,1,1,1,,,
TLNO_S14,3,2,1,1,14,1,,,
OTP_EXPR_GDNC_DVCD_S1,3,2,1,1,1,1,,,
KFTC_ENCD_MST_KEY_VER_S2,3,2,1,1,2,1,,,
KFTC_ENCD_RAND1_S32,3,2,1,1,32,1,,,
KFTC_ENCD_RAND2_S32,3,2,1,1,32,1,,,
ADDT_ATHN_YN_S1,3,2,1,1,1,1,,,
ADDT_ATHN_METH_DVCD_S2,3,2,1,1,2,1,,,
ADDT_ATHN_ATHN_VAL_S40,3,2,1,1,40,1,,,
DUP_TX_YN_S1,3,2,1,1,1,1,,,
ABR_IP_BLC_YN_S1,3,2,1,1,1,1,,,
VIRT_ACCO_DVCD_S1,3,2,1,1,1,1,,,
BZWK_DVCD1_S1,3,2,1,1,1,1,,,
BZWK_DVCD2_S1,3,2,1,1,1,1,,,
BZWK_DVCD3_S1,3,2,1,1,1,1,,,
BZWK_DVCD4_S1,3,2,1,1,1,1,,,
BZWK_DVCD5_S1,3,2,1,1,1,1,,,
TX_SER_SEQNO_N3,3,2,1,1,3,1,,,
SECU_MEDIA_SEQNO_DMAN_VAL_S4,3,2,1,1,4,1,,,
MEDIA_D1_UZ_POSB_AMT_N12,3,2,1,1,12,1,,,
CPHR_KEY_SECU_CO_CD_S1,3,2,1,1,1,1,,,
HDD_VOLU_ID_S35,3,2,1,1,35,1,,,
SPR_FILD_S197,3,2,1,1,197,1,,,
Message,1,3,0,1,0,1,Std_Header.Header.Sys_Info.MESG_DMAN_DVCD,R,
Msg_Header,2,3,0,1,0,1,,,
MSG_HEDR_KNCD,3,2,1,1,2,1,,,NM
MSG_HEDR_LEN,3,2,1,1,8,2,,,
Msg_Body,2,3,0,1,0,1,,,
OUTPUT_ATRB_CD,3,2,1,1,1,1,,,0
OUTPUT_MSG_CD,3,2,1,1,10,1,,,
OUTPUT_MSG_CTNT,3,2,1,1,200,1,,,
OUTPUT_MSG_DESC,3,2,1,1,300,1,,,
ERR_MNGM_CTNT,3,2,1,1,200,1,,,
ERR_CHGR_NM,3,2,1,1,10,1,,,
ERR_CHGR_CNPL_NO,3,2,1,1,20,1,,,
OUTPUT_MSG_NCNT,3,2,1,1,4,2,,,0000
Output_Msg_Grid,3,4,0,1,0,1,Message.Msg_Body.OUTPUT_MSG_NCNT,,
OUTPUT_MSG_CD,4,2,0,1,10,1,,,
OUTPUT_MSG_CTNT,4,2,0,1,200,1,,,
OUTPUT_MSG_DESC,4,2,0,1,300,1,,,
ERR_MNGM_CTNT,4,2,0,1,200,1,,,
ERR_LOCT_CTNT,4,2,0,1,200,1,,,
ERR_OCCU_ITEM_NM,4,2,0,1,20,1,,,
Manager_Confirm,1,3,0,1,0,1,Std_Header.Header.Sys_Info.MESG_DMAN_DVCD,R,
Data_Header,2,3,0,1,0,1,,,
DATA_HEDR_KNCD,3,2,1,1,2,1,,,
DATA_HEDR_LEN,3,2,1,1,8,2,,,
Data_Header_Etc,2,3,0,1,0,1,,,
OUTPUT_SRVC_ID,3,2,1,1,13,1,,,
OUTPUT_SCN_ID,3,2,1,1,13,1,,,
OUTPUT_SCN_DRVTN_MSG_CTNT,3,2,1,1,50,1,,,
DCG_DVCD,3,2,1,1,1,1,,,
Data_For_Each,2,3,0,1,0,1,,,
ACNO,3,2,1,1,16,1,,,
TRMN_CUST_FLNM,3,2,1,1,20,1,,,
TX_AMT,3,2,1,1,17,2,,,
APRV_RSCD_CCNT,3,2,1,1,5,2,,,
APRV_RSCD,3,2,1,1,5,1,,,
PRCG_APRV_DESC,3,2,1,1,50,1,,,
PRCG_APRV_TYCD,3,2,1,1,1,1,,,
PRCG_APRV_LIST_CCNT,3,2,1,1,5,2,,,
TX_DVCD,3,2,1,1,2,1,,,
PRCG_EMPNO,3,2,1,1,6,1,,,
KOR_FLNM,3,2,1,1,40,1,,,
BLNG_BRCD,3,2,1,1,4,1,,,
BRN_KOR_NM ,3,2,1,1,100,1,,,
LOGIN_IPAD,3,2,1,1,30,1,,,
JOBCLS_CD,3,2,1,1,2,1,,,
LOGIN_STCD,3,2,1,1,2,1,,,
ABSC_YN,3,2,1,1,1,1,,,
AGNCY_APRV_TLRNO,3,2,1,1,7,1,,,
BRMNR_YN,3,2,1,1,1,1,,,
AUDT_UNCN_PRCG_YN,3,2,1,1,1,1,,,
Data_Part,1,3,0,1,0,1,,,
Data_Header,2,3,0,1,0,1,,,
DATA_HEDR_KNCD,3,2,1,1,2,1,,,IO
DATA_HEDR_LEN,3,2,1,1,8,2,,,
Data_Header_Etc,2,3,0,1,0,1,Std_Header.Header.Sys_Info.MESG_DMAN_DVCD,R,
OUTPUT_SRVC_ID,3,2,1,1,13,1,,,
OUTPUT_SCN_ID,3,2,1,1,13,1,,,
OUTPUT_SCN_DRVTN_MSG_CTNT,3,2,1,1,50,1,,,
DCG_DVCD,3,2,1,1,1,1,,,
Data_For_Each,2,3,0,1,0,1,,,
BizData,3,9,1,1,0,1,,,
END_BIT_CTNT,1,2,1,1,2,11,,,@@
1 #-----------------------------------------------------------------------------
2 # comment start with #
3 # level; // 0 : root ~ n
4 # type; // 0: Message, 1: Field, 2:Group 3, Grid, 4 : Field Array, 9 : BIZ DATA
5 # size // 0 : variable, > 0 fixed
6 # fieldType; // 0: ELEMENT, 1: ATTRIBUTE,
7 # length;
8 # dataType; // 0: String, 1: Number,10: ZZ String, 11: LL Number
9 #-----------------------------------------------------------------------------
10 # name ,level ,type ,size ,fieldType ,length ,dataType ,,refPath, refValue,value
11 #-----------------------------------------------------------------------------
12 # name ,level ,type ,size ,fieldType ,length ,dataType ,refPath, refValue, value
13 Header,1,3,1,1,0,1,,,
14 Sys_Info,2,3,1,1,0,1,,,
15 STND_MESG_LEN,3,2,1,1,8,12,,,
16 ENCD_CMPI_DVCD,3,2,1,1,1,1,,,0
17 GUID,3,2,1,1,36,1,,,
18 MESG_DMAN_DVCD,3,2,1,1,1,1,,,S
19 MESG_VER_NO,3,2,1,1,3,1,,,R10
20 Src_System,2,3,1,1,0,1,,,
21 FRST_TRNM_IPAD,3,2,1,1,39,1,,,
22 FRST_TRNM_SYS_CD,3,2,1,1,3,1,,,API
23 TRNM_SYS_CD,3,2,1,1,3,1,,,
24 TRNM_NODE_NO,3,2,1,1,4,1,,,
25 MCI_SESN_ID,3,2,1,1,8,1,,,
26 GNRZ_TMOT_TKTM,3,2,1,1,3,1,,,070
27 TX_TMOT_TKTM,3,2,1,1,3,1,,,060
28 KJB_Add,2,3,1,1,0,1,,,
29 OTSD_DMAN_SYS_CD,3,2,1,1,3,1,,,OBP
30 EAI_NODE_NO,3,2,1,1,2,1,,,
31 FEP_NODE_NO,3,2,1,1,2,1,,,
32 FEP_SESN_ID,3,2,1,1,6,1,,,
33 Spare_Zone,2,3,1,1,0,1,,,
34 HEDR_SPR_CTNT,3,2,1,1,25,1,,,
35 Common,1,3,1,1,0,1,,,
36 Service_info,2,3,1,1,0,1,,,
37 GROUP_CMP_CD,3,2,1,1,3,1,,,034
38 SRVC_ID,3,2,1,1,11,1,,,
39 PROCS_RSLT_RCMS_SRVC_ID,3,2,1,1,11,1,,,
40 IF_ID,3,2,1,1,20,1,,,
41 TX_SYNZ_DVCD,3,2,1,1,1,1,,,
42 HMAB_DVCD,3,2,1,1,1,1,,,2
43 OTSD_CHNL_INST_CD,3,2,1,1,3,1,,,
44 SYS_OPRT_ENV_DVCD,3,2,1,1,1,1,,,
45 TX_TYP_DVCD,3,2,1,1,1,1,,,O
46 ORTR_RESTR_YN,3,2,1,1,1,1,,,
47 ORTR_GUID,3,2,1,1,36,1,,,
48 Channel_Info,2,3,1,1,0,1,,,
49 BANK_CD,3,2,1,1,3,1,,,
50 TX_BRCD,3,2,1,1,4,1,,,
51 DSPC_RCV_BRN_DVCD,3,2,1,1,2,1,,,
52 RLTR_BRCD,3,2,1,1,4,1,,,
53 TRMN_INSL_BRCD,3,2,1,1,4,1,,,
54 CHNL_TYCD,3,2,1,1,1,1,,,
55 CHNL_DTLS_CLCD,3,2,1,1,3,1,,,
56 TMNL_KIND_DVCD,3,2,1,1,2,1,,,
57 TRMN_NO,3,2,1,1,6,1,,,
58 SCN_NO,3,2,1,1,13,1,,,
59 SCN_FILE_VER,3,2,1,1,10,2,,,
60 SCN_FILE_NM,3,2,1,1,30,1,,,
61 LANG_DVCD,3,2,1,1,3,1,,,KOR
62 CHNL_COM_SCTN_EXIS_YN,3,2,1,1,1,1,,,N
63 Confirm_Info,2,3,1,1,0,1,,,
64 PRCG_APRV_PROCS_STCD,3,2,1,1,1,1,,,
65 PRCG_APRV_TYCD,3,2,1,1,1,1,,,
66 APRV_PRCG_EMPNO,3,2,1,1,7,1,,,
67 NURN_RSBT_EMPNO,3,2,1,1,7,1,,,
68 PRCG_APRV_SEQNO,3,2,1,1,10,2,,,
69 NURN_AGNCY_APRV_YN,3,2,1,1,1,1,,,
70 DSGT_PRCG_CHNG_YN,3,2,1,1,1,1,,,
71 CHNG_DSGT_PRCG_EMPNO,3,2,1,1,7,1,,,
72 PRCG_APRV_DMAN_RSN,3,2,1,1,40,1,,,
73 PRCG_APRV_RSN,3,2,1,1,40,1,,,
74 BizProc_Info,2,3,1,1,0,1,,,
75 BZOP_DT,3,2,1,1,8,1,,,
76 ANTT_YN,3,2,1,1,1,1,,,
77 MESG_IQRY_DVCD,3,2,1,1,1,1,,,
78 ATMC_CLSN_DVCD,3,2,1,1,1,1,,,
79 TLRNO,3,2,1,1,7,1,,,
80 ASST_TLRNO,3,2,1,1,7,1,,,
81 PSWD_VALDTN_YN,3,2,1,1,1,1,,,
82 TX_TELR_PSWD,3,2,1,1,44,1,,,
83 CSIF_IDNT_DVCD,3,2,1,1,3,1,,,
84 CSIF_ID,3,2,1,1,30,1,,,
85 CSIF_CUST_NM,3,2,1,1,30,1,,,
86 CSIF_MASK_REVOC_YN,3,2,1,1,1,1,,,
87 CUST_PTLET_MASK_YN,3,2,1,1,1,1,,,
88 IDC_IMG_NO,3,2,1,1,32,1,,,
89 SMTWKP_TX_YN,3,2,1,1,1,1,,,
90 SECU_ACCO_REG_YN,3,2,1,1,1,1,,,
91 ABC_TX_DTLS_DVCD,3,2,1,1,2,1,,,
92 CLNT_TELR_CSHN_RFLC_YN,3,2,1,1,1,1,,,
93 SLIP_DIV_YN,3,2,1,1,1,1,,,
94 SLIP_NO,3,2,1,1,9,1,,,
95 TELR_SLIP_SEQNO,3,2,1,1,10,2,,,
96 TELR_CASH_AMT,3,2,1,1,17,2,,,
97 TELR_CBPC_AMT,3,2,1,1,17,2,,,
98 TELR_TRFAMT,3,2,1,1,17,2,,,
99 LOGIN_DVCD,3,2,1,1,1,1,,,
100 TX_DT_EXTNS_YN ,3,2,1,1,1,1,,,
101 TX_DT,3,2,1,1,8,1,,,
102 TX_TIME,3,2,1,1,8,1,,,
103 SYS_DT,3,2,1,1,8,1,,,
104 SYS_TIME,3,2,1,1,8,1,,,
105 MESG_DMAN_DT,3,2,1,1,8,1,,,
106 MESG_DMAN_TKTM,3,2,1,1,9,1,,,
107 MESG_CNTY_YN,3,2,1,1,1,1,,,
108 MESG_RSPN_DT,3,2,1,1,8,1,,,
109 MESG_RSPN_TKTM,3,2,1,1,9,1,,,
110 PROCS_RSLT_DVCD,3,2,1,1,2,1,,,
111 OUTPUT_MESG_TYCD,3,2,1,1,1,1,,,
112 LRQN_OUTPUT_DSCT_TRGT_YN,3,2,1,1,1,1,,,
113 MESG_CNTY_SEQNO,3,2,1,1,3,1,,,
114 Error_Info,2,3,1,1,0,1,,,
115 ERR_CD,3,2,1,1,6,1,,,
116 ERR_SYS_CD,3,2,1,1,3,1,,,
117 KJB_Add,2,3,1,1,0,1,,,
118 ORTR_SCN_ID,3,2,1,1,13,1,,,
119 CORP_DPRM_NO,3,2,1,1,5,1,,,
120 CSIF_IQRY_RSCD,3,2,1,1,2,1,,,
121 Com_Spare_Zone,2,3,1,1,0,1,,,
122 COM_SPR_CTNT,3,2,1,1,212,1,,,
123 Channel_Common,1,3,0,1,0,1,Std_Header.Common.Channel_Info.CHNL_COM_SCTN_EXIS_YN,Y,
124 Data_Header,2,3,0,1,0,1,,,
125 DATA_HEDR_KNCD,3,2,1,1,2,1,,,
126 DATA_HEDR_LEN,3,2,1,1,8,1,,,
127 Data_For_Each,2,3,0,1,0,1,,,
128 PSWD_ERR_DVCD,3,2,1,1,2,1,,,
129 ELFN_CUST_TYCD,3,2,1,1,2,1,,,
130 USER_ID_S14,3,2,1,1,14,1,,,
131 MST_ID_S14,3,2,1,1,14,1,,,
132 SVR_TX_NO,3,2,1,1,10,1,,,
133 HOST_TX_NO_S10,3,2,1,1,10,1,,,
134 NEXT_PAGE_EXIS_YN1,3,2,1,1,1,1,,,
135 SCCR_ISS_CD,3,2,1,1,2,1,,,
136 SQ1_SCCR_SSBP_NO_SER,3,2,1,1,2,1,,,
137 SQ2_SCCR_SSBP_NO_SER,3,2,1,1,2,1,,,
138 SECU_MEDIA_SEQNO_S4,3,2,1,1,4,1,,,
139 SECU_MEDIA_DTL_DVCD_N3,3,2,1,1,3,1,,,
140 PAGE_NO,3,2,1,1,5,1,,,
141 PAGE_SIZE,3,2,1,1,5,1,,,
142 TTCN_N5,3,2,1,1,5,1,,,
143 IQRY_CCNT_N5,3,2,1,1,5,1,,,
144 PRIQR_TX_NO,3,2,1,1,10,1,,,
145 SQ1_CUST_CNFR_INFO_CTNT_S39,3,2,1,1,39,1,,,
146 SQ2_CUST_CNFR_INFO_CTNT_S39,3,2,1,1,39,1,,,
147 MAC_S17,3,2,1,1,17,1,,,
148 HDD_SEQ_NO_S24,3,2,1,1,24,1,,,
149 CMCM_CD,3,2,1,1,1,1,,,
150 TLNO_S14,3,2,1,1,14,1,,,
151 OTP_EXPR_GDNC_DVCD_S1,3,2,1,1,1,1,,,
152 KFTC_ENCD_MST_KEY_VER_S2,3,2,1,1,2,1,,,
153 KFTC_ENCD_RAND1_S32,3,2,1,1,32,1,,,
154 KFTC_ENCD_RAND2_S32,3,2,1,1,32,1,,,
155 ADDT_ATHN_YN_S1,3,2,1,1,1,1,,,
156 ADDT_ATHN_METH_DVCD_S2,3,2,1,1,2,1,,,
157 ADDT_ATHN_ATHN_VAL_S40,3,2,1,1,40,1,,,
158 DUP_TX_YN_S1,3,2,1,1,1,1,,,
159 ABR_IP_BLC_YN_S1,3,2,1,1,1,1,,,
160 VIRT_ACCO_DVCD_S1,3,2,1,1,1,1,,,
161 BZWK_DVCD1_S1,3,2,1,1,1,1,,,
162 BZWK_DVCD2_S1,3,2,1,1,1,1,,,
163 BZWK_DVCD3_S1,3,2,1,1,1,1,,,
164 BZWK_DVCD4_S1,3,2,1,1,1,1,,,
165 BZWK_DVCD5_S1,3,2,1,1,1,1,,,
166 TX_SER_SEQNO_N3,3,2,1,1,3,1,,,
167 SECU_MEDIA_SEQNO_DMAN_VAL_S4,3,2,1,1,4,1,,,
168 MEDIA_D1_UZ_POSB_AMT_N12,3,2,1,1,12,1,,,
169 CPHR_KEY_SECU_CO_CD_S1,3,2,1,1,1,1,,,
170 HDD_VOLU_ID_S35,3,2,1,1,35,1,,,
171 SPR_FILD_S197,3,2,1,1,197,1,,,
172 Message,1,3,0,1,0,1,Std_Header.Header.Sys_Info.MESG_DMAN_DVCD,R,
173 Msg_Header,2,3,0,1,0,1,,,
174 MSG_HEDR_KNCD,3,2,1,1,2,1,,,NM
175 MSG_HEDR_LEN,3,2,1,1,8,2,,,
176 Msg_Body,2,3,0,1,0,1,,,
177 OUTPUT_ATRB_CD,3,2,1,1,1,1,,,0
178 OUTPUT_MSG_CD,3,2,1,1,10,1,,,
179 OUTPUT_MSG_CTNT,3,2,1,1,200,1,,,
180 OUTPUT_MSG_DESC,3,2,1,1,300,1,,,
181 ERR_MNGM_CTNT,3,2,1,1,200,1,,,
182 ERR_CHGR_NM,3,2,1,1,10,1,,,
183 ERR_CHGR_CNPL_NO,3,2,1,1,20,1,,,
184 OUTPUT_MSG_NCNT,3,2,1,1,4,2,,,0000
185 Output_Msg_Grid,3,4,0,1,0,1,Message.Msg_Body.OUTPUT_MSG_NCNT,,
186 OUTPUT_MSG_CD,4,2,0,1,10,1,,,
187 OUTPUT_MSG_CTNT,4,2,0,1,200,1,,,
188 OUTPUT_MSG_DESC,4,2,0,1,300,1,,,
189 ERR_MNGM_CTNT,4,2,0,1,200,1,,,
190 ERR_LOCT_CTNT,4,2,0,1,200,1,,,
191 ERR_OCCU_ITEM_NM,4,2,0,1,20,1,,,
192 Manager_Confirm,1,3,0,1,0,1,Std_Header.Header.Sys_Info.MESG_DMAN_DVCD,R,
193 Data_Header,2,3,0,1,0,1,,,
194 DATA_HEDR_KNCD,3,2,1,1,2,1,,,
195 DATA_HEDR_LEN,3,2,1,1,8,2,,,
196 Data_Header_Etc,2,3,0,1,0,1,,,
197 OUTPUT_SRVC_ID,3,2,1,1,13,1,,,
198 OUTPUT_SCN_ID,3,2,1,1,13,1,,,
199 OUTPUT_SCN_DRVTN_MSG_CTNT,3,2,1,1,50,1,,,
200 DCG_DVCD,3,2,1,1,1,1,,,
201 Data_For_Each,2,3,0,1,0,1,,,
202 ACNO,3,2,1,1,16,1,,,
203 TRMN_CUST_FLNM,3,2,1,1,20,1,,,
204 TX_AMT,3,2,1,1,17,2,,,
205 APRV_RSCD_CCNT,3,2,1,1,5,2,,,
206 APRV_RSCD,3,2,1,1,5,1,,,
207 PRCG_APRV_DESC,3,2,1,1,50,1,,,
208 PRCG_APRV_TYCD,3,2,1,1,1,1,,,
209 PRCG_APRV_LIST_CCNT,3,2,1,1,5,2,,,
210 TX_DVCD,3,2,1,1,2,1,,,
211 PRCG_EMPNO,3,2,1,1,6,1,,,
212 KOR_FLNM,3,2,1,1,40,1,,,
213 BLNG_BRCD,3,2,1,1,4,1,,,
214 BRN_KOR_NM ,3,2,1,1,100,1,,,
215 LOGIN_IPAD,3,2,1,1,30,1,,,
216 JOBCLS_CD,3,2,1,1,2,1,,,
217 LOGIN_STCD,3,2,1,1,2,1,,,
218 ABSC_YN,3,2,1,1,1,1,,,
219 AGNCY_APRV_TLRNO,3,2,1,1,7,1,,,
220 BRMNR_YN,3,2,1,1,1,1,,,
221 AUDT_UNCN_PRCG_YN,3,2,1,1,1,1,,,
222 Data_Part,1,3,0,1,0,1,,,
223 Data_Header,2,3,0,1,0,1,,,
224 DATA_HEDR_KNCD,3,2,1,1,2,1,,,IO
225 DATA_HEDR_LEN,3,2,1,1,8,2,,,
226 Data_Header_Etc,2,3,0,1,0,1,Std_Header.Header.Sys_Info.MESG_DMAN_DVCD,R,
227 OUTPUT_SRVC_ID,3,2,1,1,13,1,,,
228 OUTPUT_SCN_ID,3,2,1,1,13,1,,,
229 OUTPUT_SCN_DRVTN_MSG_CTNT,3,2,1,1,50,1,,,
230 DCG_DVCD,3,2,1,1,1,1,,,
231 Data_For_Each,2,3,0,1,0,1,,,
232 BizData,3,9,1,1,0,1,,,
233 END_BIT_CTNT,1,2,1,1,2,11,,,@@
@@ -1,28 +0,0 @@
#-----------------------------------------------------------------------------
# comment start with #
# level; // 0 : root ~ n
# type; // 0: Message, 1: Field, 2:Group 3, Grid, 4 : Field Array, 9 : BIZ DATA
# size // 0 : variable, > 0 fixed
# fieldType; // 0: ELEMENT, 1: ATTRIBUTE,
# length;
# dataType; // 0: String, 1: Number,10: ZZ String, 11: LL Number
#-----------------------------------------------------------------------------
#name ,level,type,size,fieldType,length,dataType,refPath ,refValue,value
ElinkHeader ,0 ,0 ,1 ,0 ,0 ,0 , , ,
Header ,1 ,2 ,1 ,1 ,0 ,0 , , ,
StndCicsTrncd ,2 ,1 ,1 ,1 ,10 ,0 , , ,
StndIntnlStndTelgmLen,2 ,1 ,1 ,1 ,10 ,11 , , ,0
StndTranBaseYmd ,2 ,1 ,1 ,1 ,10 ,0 , , ,
Common ,1 ,2 ,0 ,0 ,0 ,0 ,Header.StndCicsTrncd,JI6H ,
TranInfo ,2 ,2 ,1 ,0 ,0 ,0 , , ,
StndCicsTrncd ,3 ,1 ,1 ,0 ,3 ,0 , , ,
StndTelgmRecvTranCd ,3 ,1 ,1 ,0 ,10 ,0 , , ,
StndPrcssRtdTranCd ,3 ,1 ,1 ,0 ,10 ,0 , , ,
Array ,1 ,3 ,0 ,0 ,3 ,0 , , ,
Item1 ,2 ,1 ,1 ,0 ,10 ,0 , , ,JI6H
Group ,2 ,3 ,1 ,0 ,1 ,0 , , ,
gitem1 ,3 ,1 ,1 ,0 ,10 ,1 , , ,726
gitem2 ,3 ,1 ,1 ,0 ,10 ,0 , , ,20220905
FArray ,1 ,4 ,0 ,0 ,10 ,0 , , ,
bizData ,1 ,9 ,1 ,0 ,0 ,0 , , ,
zzData ,1 ,1 ,1 ,0 ,2 ,10 , , ,ZZ
1 #-----------------------------------------------------------------------------
2 # comment start with #
3 # level; // 0 : root ~ n
4 # type; // 0: Message, 1: Field, 2:Group 3, Grid, 4 : Field Array, 9 : BIZ DATA
5 # size // 0 : variable, > 0 fixed
6 # fieldType; // 0: ELEMENT, 1: ATTRIBUTE,
7 # length;
8 # dataType; // 0: String, 1: Number,10: ZZ String, 11: LL Number
9 #-----------------------------------------------------------------------------
10 #name ,level,type,size,fieldType,length,dataType,refPath ,refValue,value
11 ElinkHeader ,0 ,0 ,1 ,0 ,0 ,0 , , ,
12 Header ,1 ,2 ,1 ,1 ,0 ,0 , , ,
13 StndCicsTrncd ,2 ,1 ,1 ,1 ,10 ,0 , , ,
14 StndIntnlStndTelgmLen,2 ,1 ,1 ,1 ,10 ,11 , , ,0
15 StndTranBaseYmd ,2 ,1 ,1 ,1 ,10 ,0 , , ,
16 Common ,1 ,2 ,0 ,0 ,0 ,0 ,Header.StndCicsTrncd,JI6H ,
17 TranInfo ,2 ,2 ,1 ,0 ,0 ,0 , , ,
18 StndCicsTrncd ,3 ,1 ,1 ,0 ,3 ,0 , , ,
19 StndTelgmRecvTranCd ,3 ,1 ,1 ,0 ,10 ,0 , , ,
20 StndPrcssRtdTranCd ,3 ,1 ,1 ,0 ,10 ,0 , , ,
21 Array ,1 ,3 ,0 ,0 ,3 ,0 , , ,
22 Item1 ,2 ,1 ,1 ,0 ,10 ,0 , , ,JI6H
23 Group ,2 ,3 ,1 ,0 ,1 ,0 , , ,
24 gitem1 ,3 ,1 ,1 ,0 ,10 ,1 , , ,726
25 gitem2 ,3 ,1 ,1 ,0 ,10 ,0 , , ,20220905
26 FArray ,1 ,4 ,0 ,0 ,10 ,0 , , ,
27 bizData ,1 ,9 ,1 ,0 ,0 ,0 , , ,
28 zzData ,1 ,1 ,1 ,0 ,2 ,10 , , ,ZZ
-104
View File
@@ -1,104 +0,0 @@
#-----------------------------------------------------------------------------,,,,,,,,,,
# comment start with #,,,,,,,,,,
# level; // 0 : root ~ n,,,,,,,,,,
# type; // 0: Message, 1: Field, 2:Group 3, Grid, 4 : Field Array, 9 : BIZ DATA,,,,,
# size // 0 : variable, > 0 fixed,,,,,,,,,
# fieldType; // 0: ELEMENT, 1: ATTRIBUTE,,,,,,,,,
# length;,,,,,,,,,,
# dataType; // 0: String, 1: Number,10: ZZ String, 11: LL Number,,,,,,,
#-----------------------------------------------------------------------------,,,,,,,,,,
# name ,level ,type ,size ,fieldType ,length ,dataType ,,refPath, refValue,value
#-----------------------------------------------------------------------------,,,,,,,,,,
# name ,level ,type ,size ,fieldType ,length ,dataType ,refPath, refValue, value
STD_SBI_HEADER_REQ ,0,0,1,0,0,0, , ,
STD_HEADER ,1,2,1,0,0,0, , ,
mesgLen,2,1,1,0,8,11, , ,
mesgKind,2,1,1,0,1,0, , ,
dtlDstc1,2,1,1,0,1,0, , ,
dtlDstc2,2,1,1,0,1,0, , ,
rsltCd,2,1,1,0,2,0, , ,
filler,2,1,1,0,11,0, , ,
whlMesgLen,2,1,1,0,8,1, , ,
stndHdrLen,2,1,1,0,8,1, , ,
globId,2,1,1,0,32,0, , ,
prgsSrno,2,1,1,0,3,1, , ,
ipAd,2,1,1,0,15,0, , ,
prcmMac,2,1,1,0,12,0, , ,
trnTrnmNo,2,1,1,0,9,0, , ,
ssoSesnKey,2,1,1,0,30,0, , ,
frstTrnmChnlCd,2,1,1,0,3,0, , ,
trnmChnlCd,2,1,1,0,3,0, , ,
trnmNodeNo,2,1,1,0,2,1, , ,
mciTrnmNodeNo,2,1,1,0,2,1, , ,
trmnDeptCd,2,1,1,0,4,0, , ,
envDvcd,2,1,1,0,1,0, , ,
mesgDmndDttm,2,1,1,0,17,0, , ,
mesgVrsnDvcd,2,1,1,0,3,0, , ,
trnCd,2,1,1,0,8,0, , ,
scrnNo,2,1,1,0,9,0, , ,
mesgRespDttm,2,1,1,0,17,0, , ,
trnPtrnDvcd,2,1,1,0,1,0, , ,
mesgDvcd,2,1,1,0,1,0, , ,
mesgTycd,2,1,1,0,1,0,,,
mesgCntySrno,2,1,1,0,2,1,,,
bfrDtLoinYn,2,1,1,0,1,0,,,
canCrctDvcd,2,1,1,0,1,0,,,
trtmRsltCd,2,1,1,0,1,0,,,
cmpgRelmUseDvcd,2,1,1,0,1,0,,,
bankCd,2,1,1,0,3,0,,,
deptCd,2,1,1,0,4,0,,,
brCd,2,1,1,0,4,0,,,
atmBrCd,2,1,1,0,2,0,,,
userNo,2,1,1,0,6,0,,,
corpAuthYn,2,1,1,0,1,0,,,
ctiYn,2,1,1,0,1,0,,,
cshnOcrnYn,2,1,1,0,1,0,,,
cashAmt,2,1,1,0,18,1,,,
otbrAmt1,2,1,1,0,18,1,,,
otbrAmt2,2,1,1,0,18,1,,,
sumAmt,2,1,1,0,18,1,,,
altrDiffAmt,2,1,1,0,18,1,,,
xtisCd,2,1,1,0,4,0,,,
bzwrSvrCd,2,1,1,0,4,0,,,
otsdMesgCd,2,1,1,0,32,0,,,
otsdMesgTrtmCd,2,1,1,0,32,0,,,
otsdTrnUnqNo,2,1,1,0,32,0,,,
otsdRespTrnCd,2,1,1,0,8,0,,,
chnlMsgCd,2,1,1,0,10,0,,,
sprChrsCntn,2,1,1,0,80,0,,,
STD_COMMON,1,2,1,0,0,0,,,
aprvStcd,2,1,1,0,2,0,,,
aprvDmndTrnAmt,2,1,1,0,18,1,,,
aprvDmndCustNm,2,1,1,0,50,0,,,
aprvDmndMsg,2,1,1,0,100,0,,,
aprvMsgCcnt,2,1,1,0,2,1,,,
STDCommonApprovalMsg,2,3,0,0,0,0,STD_COMMON.aprvMsgCcnt,,
aprvMsgCd,3,1,1,0,8,0,,,
aprvMsgCntn,3,1,1,0,100,0,,,
aprvAlwnSqcnt,2,1,1,0,1,1,,,
loinPrcgPcnt,2,1,1,0,2,1,,,
STDCommonLoginManager,2,3,0,0,0,0,STD_COMMON.loinPrcgPcnt,,
loinPrcgEmno,3,1,1,0,6,0,,,
loinPrcgNm,3,1,1,0,20,0,,,
loinPrcgIpad,3,1,1,0,15,0,,,
aprrPcnt,2,1,1,0,2,1,,,
STDCommonApprover,2,3,0,0,0,0,STD_COMMON.aprrPcnt,,
aprrEmno,3,1,1,0,6,0,,,
aprrMsg,3,1,1,0,100,0,,,
STDMsg,1,2,1,0,0,0,,,
msgCcnt,2,1,1,0,2,1,,,
STDMsgError,2,3,0,0,0,0,STDMsg.msgCcnt,,
msgCd,3,1,1,0,8,0,,,
msgCntn,3,1,1,0,100,0,,,
erorOcrnPrrmLine,3,1,1,0,7,1,,,
erorOcrnPrrmNm,3,1,1,0,100,0,,,
STDDataHeader,1,2,1,0,0,0,,,
otptMediPtrnCcnt,2,1,1,0,2,1,,,
STDDataHeaderItem,2,3,0,0,0,0,STDDataHeader.otptMediPtrnCcnt,,
otptTrnCd,3,1,1,0,8,0,,,
otptYn,3,1,1,0,1,0,,,
otptScrnNo,3,1,1,0,9,0,,,
drvtnDvcd,3,1,1,0,1,0,,,
gdncMsg,3,1,1,0,50,0,,,
bizData,1,9,1,0,0,0,,,
zzData,1,1,1,0,2,10,,,@@
1 #-----------------------------------------------------------------------------
2 # comment start with #
3 # level; // 0 : root ~ n
4 # type; // 0: Message 1: Field 2:Group 3 Grid 4 : Field Array 9 : BIZ DATA
5 # size // 0 : variable > 0 fixed
6 # fieldType; // 0: ELEMENT 1: ATTRIBUTE
7 # length;
8 # dataType; // 0: String 1: Number 10: ZZ String 11: LL Number
9 #-----------------------------------------------------------------------------
10 # name level type size fieldType length dataType refPath refValue value
11 #-----------------------------------------------------------------------------
12 # name level type size fieldType length dataType refPath refValue value
13 STD_SBI_HEADER_REQ 0 0 1 0 0 0
14 STD_HEADER 1 2 1 0 0 0
15 mesgLen 2 1 1 0 8 11
16 mesgKind 2 1 1 0 1 0
17 dtlDstc1 2 1 1 0 1 0
18 dtlDstc2 2 1 1 0 1 0
19 rsltCd 2 1 1 0 2 0
20 filler 2 1 1 0 11 0
21 whlMesgLen 2 1 1 0 8 1
22 stndHdrLen 2 1 1 0 8 1
23 globId 2 1 1 0 32 0
24 prgsSrno 2 1 1 0 3 1
25 ipAd 2 1 1 0 15 0
26 prcmMac 2 1 1 0 12 0
27 trnTrnmNo 2 1 1 0 9 0
28 ssoSesnKey 2 1 1 0 30 0
29 frstTrnmChnlCd 2 1 1 0 3 0
30 trnmChnlCd 2 1 1 0 3 0
31 trnmNodeNo 2 1 1 0 2 1
32 mciTrnmNodeNo 2 1 1 0 2 1
33 trmnDeptCd 2 1 1 0 4 0
34 envDvcd 2 1 1 0 1 0
35 mesgDmndDttm 2 1 1 0 17 0
36 mesgVrsnDvcd 2 1 1 0 3 0
37 trnCd 2 1 1 0 8 0
38 scrnNo 2 1 1 0 9 0
39 mesgRespDttm 2 1 1 0 17 0
40 trnPtrnDvcd 2 1 1 0 1 0
41 mesgDvcd 2 1 1 0 1 0
42 mesgTycd 2 1 1 0 1 0
43 mesgCntySrno 2 1 1 0 2 1
44 bfrDtLoinYn 2 1 1 0 1 0
45 canCrctDvcd 2 1 1 0 1 0
46 trtmRsltCd 2 1 1 0 1 0
47 cmpgRelmUseDvcd 2 1 1 0 1 0
48 bankCd 2 1 1 0 3 0
49 deptCd 2 1 1 0 4 0
50 brCd 2 1 1 0 4 0
51 atmBrCd 2 1 1 0 2 0
52 userNo 2 1 1 0 6 0
53 corpAuthYn 2 1 1 0 1 0
54 ctiYn 2 1 1 0 1 0
55 cshnOcrnYn 2 1 1 0 1 0
56 cashAmt 2 1 1 0 18 1
57 otbrAmt1 2 1 1 0 18 1
58 otbrAmt2 2 1 1 0 18 1
59 sumAmt 2 1 1 0 18 1
60 altrDiffAmt 2 1 1 0 18 1
61 xtisCd 2 1 1 0 4 0
62 bzwrSvrCd 2 1 1 0 4 0
63 otsdMesgCd 2 1 1 0 32 0
64 otsdMesgTrtmCd 2 1 1 0 32 0
65 otsdTrnUnqNo 2 1 1 0 32 0
66 otsdRespTrnCd 2 1 1 0 8 0
67 chnlMsgCd 2 1 1 0 10 0
68 sprChrsCntn 2 1 1 0 80 0
69 STD_COMMON 1 2 1 0 0 0
70 aprvStcd 2 1 1 0 2 0
71 aprvDmndTrnAmt 2 1 1 0 18 1
72 aprvDmndCustNm 2 1 1 0 50 0
73 aprvDmndMsg 2 1 1 0 100 0
74 aprvMsgCcnt 2 1 1 0 2 1
75 STDCommonApprovalMsg 2 3 0 0 0 0 STD_COMMON.aprvMsgCcnt
76 aprvMsgCd 3 1 1 0 8 0
77 aprvMsgCntn 3 1 1 0 100 0
78 aprvAlwnSqcnt 2 1 1 0 1 1
79 loinPrcgPcnt 2 1 1 0 2 1
80 STDCommonLoginManager 2 3 0 0 0 0 STD_COMMON.loinPrcgPcnt
81 loinPrcgEmno 3 1 1 0 6 0
82 loinPrcgNm 3 1 1 0 20 0
83 loinPrcgIpad 3 1 1 0 15 0
84 aprrPcnt 2 1 1 0 2 1
85 STDCommonApprover 2 3 0 0 0 0 STD_COMMON.aprrPcnt
86 aprrEmno 3 1 1 0 6 0
87 aprrMsg 3 1 1 0 100 0
88 STDMsg 1 2 1 0 0 0
89 msgCcnt 2 1 1 0 2 1
90 STDMsgError 2 3 0 0 0 0 STDMsg.msgCcnt
91 msgCd 3 1 1 0 8 0
92 msgCntn 3 1 1 0 100 0
93 erorOcrnPrrmLine 3 1 1 0 7 1
94 erorOcrnPrrmNm 3 1 1 0 100 0
95 STDDataHeader 1 2 1 0 0 0
96 otptMediPtrnCcnt 2 1 1 0 2 1
97 STDDataHeaderItem 2 3 0 0 0 0 STDDataHeader.otptMediPtrnCcnt
98 otptTrnCd 3 1 1 0 8 0
99 otptYn 3 1 1 0 1 0
100 otptScrnNo 3 1 1 0 9 0
101 drvtnDvcd 3 1 1 0 1 0
102 gdncMsg 3 1 1 0 50 0
103 bizData 1 9 1 0 0 0
104 zzData 1 1 1 0 2 10 @@
@@ -1,31 +0,0 @@
# layout : StandardMessage layout definition
#layout.file.type=CSV
layout.file.type=DB
#layout.file.path=standard-layout-sbi.csv
#layout.file.path=standard-layout-elk.csv
#layout.filter.FLAT=com.eactive.eai.custom.message.FlatMessageFilterSBI
layout.filter.FLAT=com.eactive.eai.message.filter.FlatMessageFilter
# mapper : StandardMessage's fields getter/setter interface
#mapper.class=com.eactive.eai.custom.message.InterfaceMapperSBI
mapper.class=com.eactive.eai.custom.message.InterfaceMapperKAKAOCARD
#mapper.definition=standard-message-mapping-config-sbi.properties
#mapper.definition=standard-message-mapping-config-elk.properties
mapper.definition=standard-message-mapping-config.properties
# StandardMessage Coordinator implementation
message.coordinator.class=com.eactive.eai.custom.message.StandardMessageCoordinatorKAKAOCARD
# RequestProcessor implementation
#requestProcessor.class=com.eactive.eai.inbound.processor.RequestProcessor
# reader : parsing input data to StandardMessage
reader.JSON=com.eactive.eai.message.parser.JsonReader
reader.JSN=com.eactive.eai.message.parser.JsonReader
reader.UJN=com.eactive.eai.message.parser.JsonReader
reader.XML=com.eactive.eai.message.parser.XmlReader
reader.UXL=com.eactive.eai.message.parser.XmlReader
reader.ASC=com.eactive.eai.message.parser.FlatReader
reader.FLAT=com.eactive.eai.message.parser.FlatReader
encode.flat=euc-kr
encode.xml=utf-8
version.layout.name=KAKAOBANK
version.layout.filter.FLAT=com.eactive.eai.custom.message.FlatMessageFilterKAKAOCARD
version.mapper=com.eactive.eai.message.mapper.DefaultMessageMapper
version.mapper.definition=version-message-mapping-config.properties
@@ -1,22 +0,0 @@
# layout : StandardMessage layout definition
layout.file.type=DB:SBI
layout.file.path=standard-layout-sbi.csv
layout.filter.FLAT=com.eactive.eai.custom.message.FlatMessageFilterSBI
# mapper : StandardMessage's fields getter/setter interface
mapper.class=com.eactive.eai.custom.message.InterfaceMapperSBI
mapper.definition=standard-message-mapping-config-sbi.properties
# StandardMessage Coordinator implementation
message.coordinator.class=com.eactive.eai.custom.message.StandardMessageCoordinatorSBI
# RequestProcessor implementation
#requestProcessor.class=com.eactive.eai.inbound.processor.RequestProcessor
# reader : parsing input data to StandardMessage
reader.JSON=com.eactive.eai.message.parser.JsonReader
reader.JSN=com.eactive.eai.message.parser.JsonReader
reader.UJN=com.eactive.eai.message.parser.JsonReader
reader.XML=com.eactive.eai.message.parser.XmlReader
reader.UXL=com.eactive.eai.message.parser.XmlReader
reader.ASC=com.eactive.eai.message.parser.FlatReader
reader.FLAT=com.eactive.eai.message.parser.FlatReader
encode.flat=euc-kr
encode.xml=utf-8
encode.json=utf-8
@@ -1,11 +0,0 @@
layout.file.type=CSV
layout.file.path=./resources/standard-layout-sample.csv
mapper.class=com.eactive.eai.message.test.TestInterfaceMapper
mapper.definition=./resources/standard-message-mapping-config.properties
reader.JSON=com.eactive.eai.message.parser.JsonReader
reader.JSN=com.eactive.eai.message.parser.JsonReader
reader.UJN=com.eactive.eai.message.parser.JsonReader
reader.XML=com.eactive.eai.message.parser.XmlReader
reader.UXL=com.eactive.eai.message.parser.XmlReader
reader.ASC=com.eactive.eai.message.parser.FlatReader
reader.FLAT=com.eactive.eai.message.parser.FlatReader
@@ -24,3 +24,4 @@ ERROR_MSG=MSG.MAIN_MSG.outp_msg_ctnt
RESPONSE_TYPE=HEAD.procs_rslt_dvcd
RETURN_VALUE=
RETURN_SERVICE_ID=
BIZ_DATA=DATA[0].BIZ_DATA
@@ -1,26 +0,0 @@
REQ_SYS_CODE=commonHeader.firstReqSystemCode
CHANNEL_TYPE_CD=
CHANNEL_DETAIL_CD=
SEND_TIME=
GUID=commonHeader.globalId
SYSTEM_TYPE=
RECV_TIME=
RETURN_VALUE=
GUID_ORG=commonHeader.globalId
GUID_SEQ=commonHeader.traceSeqNo
SERVICE_ID=commonHeader.serviceCode
RETURN_SERVICE_ID=
INTERFACE_ID=commonHeader.serviceCode
SESSION_ID=
SEND_RECV_DIVISION=commonHeader.reqResTypeCode
IN_EX_DIVISION=commonHeader.inExTypeCode
OPERATION_ENV=
FIRST_REQ_IP=commonHeader.firstReqSystemIp
RECOVER_YN=
INST_CODE=
TIMEOUT=
ERROR_CODE=commonHeader.resultCode
ERROR_MSG=commonHeader.resultMsg
USER_ID=
RESPONSE_TYPE=
SYNC_ASYNC_TYPE=
@@ -1,52 +0,0 @@
#C2R에서만 사용
REQ_SYS_CODE=
#채널유형코드
CHANNEL_TYPE_CD=
#채널세부분류코드
CHANNEL_DETAIL_CD=HEADER.CHNL_CLCD
#전송시간-400응답시에 셋팅
SEND_TIME=
#GUID
GUID=HEADER.GUID
#시스템타입-MCI/EAI/FEP-사용하는데 없어보임
SYSTEM_TYPE=
#수신시각
RECV_TIME=
#사용하는데 없어보임
RETURN_VALUE=
#원거래GUID
GUID_ORG=HEADER.GUID
#GUID의 진행일련번호-카카오에서는 합쳐저 있어서 코딩으로 변경
GUID_SEQ=
#계정계서비스ID-카카오에서는 URL이 들어감
SERVICE_ID=INTERFACE_COMMON.API_PATH
#계정계응답서비스ID-카카오에서는 URL이 들어감
RETURN_SERVICE_ID=INTERFACE_COMMON.PROCS_RSLT_RCV_API_PATH
#인터페이스ID
INTERFACE_ID=INTERFACE_COMMON.IF_ID
#세션ID-MCI/EAI/FEP별로 mapper에서 셋팅해야될껄로 변경
SESSION_ID=
#요청응답구분코드
SEND_RECV_DIVISION=HEADER.FMSG_REQ_RES_DSTCD
#내외구분코드
IN_EX_DIVISION=INTERFACE_COMMON.IOSD_DSTCD
#운영환경구분코드
OPERATION_ENV=HEADER.SYS_ENV_DSTCD
#최초요청IP
FIRST_REQ_IP=HEADER.FRST_TRNM_IPAD
#복원여부
RECOVER_YN=INTERFACE_COMMON.OTX_RSTR_YN
#인스턴스ID-MCI/EAI/FEP별로 mapper에서 셋팅해야될껄로 변경
INST_CODE=
#타임아웃
TIMEOUT=HEADER.GNRZ_TMOT_TM
#에러코드
ERROR_CODE=MESSAGE.OUT_MSG_CD
#에러메시지
ERROR_MSG=MESSAGE.OUT_MSG_CTNT
#사용자ID
USER_ID=COMMON.TLRNO
#응답타입-정상여부
RESPONSE_TYPE=COMMON.PROCS_RSLT_DSTCD
#거래동기화구분코드-S/A
SYNC_ASYNC_TYPE=
@@ -1,52 +0,0 @@
#C2R\uC5D0\uC11C\uB9CC \uC0AC\uC6A9
REQ_SYS_CODE=
#\uCC44\uB110\uC720\uD615\uCF54\uB4DC
CHANNEL_TYPE_CD=
#\uCC44\uB110\uC138\uBD80\uBD84\uB958\uCF54\uB4DC
CHANNEL_DETAIL_CD=
#\uC804\uC1A1\uC2DC\uAC04-400\uC751\uB2F5\uC2DC\uC5D0 \uC14B\uD305
SEND_TIME=
#GUID - K
GUID=Header.Sys_Info.GUID
#\uC2DC\uC2A4\uD15C\uD0C0\uC785-MCI/EAI/FEP-\uC0AC\uC6A9
SYSTEM_TYPE=Header.Src_System.FRST_TRNM_SYS_CD
#\uC218\uC2E0\uC2DC\uAC01
RECV_TIME=Common.BizProc_Info.MESG_DMAN_TKTM
# \uBBF8\uC0AC\uC6A9
RETURN_VALUE=
#\uC6D0\uAC70\uB798GUID - K
GUID_ORG=
#GUID\uC758 \uC9C4\uD589\uC77C\uB828\uBC88\uD638 - K
GUID_SEQ=
#\uACC4\uC815\uACC4\uC11C\uBE44\uC2A4ID - K
SERVICE_ID=Common.Service_info.SRVC_ID
#\uACC4\uC815\uACC4\uC751\uB2F5\uC11C\uBE44\uC2A4ID
RETURN_SERVICE_ID=
#\uC778\uD130\uD398\uC774\uC2A4ID - K
INTERFACE_ID=Common.Service_info.IF_ID
#\uC138\uC158ID-MCI/EAI/FEP\uBCC4\uB85C map
SESSION_ID=Header.Src_System.MCI_SESN_ID
#\uC694\uCCAD\uC751\uB2F5\uAD6C\uBD84\uCF54\uB4DC(S|R)
SEND_RECV_DIVISION=Header.Sys_Info.MESG_DMAN_DVCD
#\uB0B4\uC678\uAD6C\uBD84\uCF54\uB4DC(1|2)
IN_EX_DIVISION=Common.Service_info.HMAB_DVCD
#\uC6B4\uC601\uD658\uACBD\uAD6C\uBD84\uCF54\uB4DC
OPERATION_ENV=Common.Service_info.SYS_OPRT_ENV_DVCD
#\uCD5C\uCD08\uC694\uCCADIP
FIRST_REQ_IP=Header.Src_System.FRST_TRNM_IPAD
#\uBCF5\uC6D0\uC5EC\uBD80(0|1)
RECOVER_YN=Common.Service_info.ORTR_RESTR_YN
#\uC778\uC2A4\uD134\uC2A4ID
INST_CODE=
#\uD0C0\uC784\uC544\uC6C3
TIMEOUT=
#\uC5D0\uB7EC\uCF54\uB4DC
ERROR_CODE=Common.Error_Info.ERR_CD
#\uC5D0\uB7EC\uBA54\uC2DC\uC9C0
ERROR_MSG=Message.Msg_Body.OUTPUT_MSG_CTNT
#\uC0AC\uC6A9\uC790ID
USER_ID=
#\uC751\uB2F5\uD0C0\uC785-\uC815\uC0C1\uC5EC\uBD80(0=\uC815\uC0C1|1=\uC5D0\uB7EC)
RESPONSE_TYPE=Common.BizProc_Info.PROCS_RSLT_DVCD
#\uAC70\uB798\uB3D9\uAE30\uD654\uAD6C\uBD84\uCF54\uB4DC(S|A)
SYNC_ASYNC_TYPE=Common.Service_info.TX_SYNZ_DVCD
@@ -1,28 +0,0 @@
REQ_SYS_CODE=systemHeader.DMND_SYS_CD
CHANNEL_TYPE_CD=stdcommon.chnlTycd
CHANNEL_DETAIL_CD=stdcommon.chnlDtlsClcd
SEND_TIME=stdheader.send_tm
GUID=stdheader.global_id
SYSTEM_TYPE=stdheader.Inter_chn
RECV_TIME=stdheader.recv_tm
RETURN_VALUE=stdheader.return_value
GUID_ORG=stdcommon.ortrGuid
GUID_SEQ=stdheader.global_id
#SERVICE_ID=stdheader.service_id
SERVICE_ID=service_id
RETURN_SERVICE_ID=stdcommon.procsRsltRcmsSrvcId
INTERFACE_ID=stdheader.service_id
SESSION_ID=stdheader.Session_id
#SEND_RECV_DIVISION=stdheader.return_gubun
SEND_RECV_DIVISION=service_tn
IN_EX_DIVISION=stdcommon.hmabDvcd
OPERATION_ENV=stdcommon.sysOprtEnvDvcd
FIRST_REQ_IP=stdheader.ip_addr
RECOVER_YN=stdcommon.ortrRestrYn
INST_CODE=stdheader.com_code
TIMEOUT=stdheader.gnrzTmotTktm
ERROR_CODE=stdheader.msg_id
ERROR_MSG=stdheader.msg_nm
USER_ID=stdheader.usr_id
RESPONSE_TYPE=stdcommon.procsRsltDvcd
SYNC_ASYNC_TYPE=stdcommon.txSynzDvcd
@@ -1,26 +0,0 @@
REQ_SYS_CODE=STD_HEADER.trnmChnlCd
CHANNEL_TYPE_CD=STD_HEADER.trnmChnlCd
CHANNEL_DETAIL_CD=STD_HEADER.trnmNodeNo
SEND_TIME=STD_HEADER.mesgDmndDttm
GUID=STD_HEADER.globId
SYSTEM_TYPE=
RECV_TIME=STD_HEADER.mesgRespDttm
RETURN_VALUE=
GUID_ORG=STD_HEADER.globId
GUID_SEQ=STD_HEADER.prgsSrno
SERVICE_ID=STD_HEADER.trnCd
RETURN_SERVICE_ID=STD_HEADER.otsdRespTrnCd
INTERFACE_ID=STD_HEADER.trnCd
SESSION_ID=STD_HEADER.ssoSesnKey
SEND_RECV_DIVISION=STD_HEADER.mesgDvcd
IN_EX_DIVISION=
OPERATION_ENV=STD_HEADER.envDvcd
FIRST_REQ_IP=STD_HEADER.ipAd
RECOVER_YN=
INST_CODE=STD_HEADER.xtisCd
TIMEOUT=
ERROR_CODE=STDMsg.STDMsgError.msgCd
ERROR_MSG=STDMsg.STDMsgError.msgCntn
USER_ID=STD_HEADER.userNo
RESPONSE_TYPE=STD_HEADER.trtmRsltCd
SYNC_ASYNC_TYPE=
@@ -1,52 +0,0 @@
#C2R에서만 사용
REQ_SYS_CODE=
#채널유형코드
CHANNEL_TYPE_CD=
#채널세부분류코드
CHANNEL_DETAIL_CD=
#전송시간-400응답시에 셋팅
SEND_TIME=
#GUID - K
GUID=
#시스템타입-MCI/EAI/FEP-사용
SYSTEM_TYPE=
#수신시각
RECV_TIME=header_part.tlgrRspnsDttm
# 미사용
RETURN_VALUE=
#원거래GUID - K
GUID_ORG=header_part.orgnlTx
#GUID의 진행일련번호 - K
GUID_SEQ=header_part.tlgrPrgrsNo
#계정계서비스ID - K
SERVICE_ID=header_part.eaiIntfId
#계정계응답서비스ID
RETURN_SERVICE_ID=
#인터페이스ID - K
INTERFACE_ID=header_part.eaiIntfId
#세션ID-MCI/EAI/FEP별로 map
SESSION_ID=
#요청응답구분코드(S|R)
SEND_RECV_DIVISION=header_part.reqRspnsDscd
#내외구분코드(1|2)
IN_EX_DIVISION=
#운영환경구분코드
OPERATION_ENV=header_part.exctnModeDscd
#최초요청IP
FIRST_REQ_IP=header_part.ipAddr
#복원여부(0|1)
RECOVER_YN=
#인스턴스ID
INST_CODE=
#타임아웃
TIMEOUT=
#에러코드
ERROR_CODE=message_part.msgCtntCd
#에러메시지
ERROR_MSG=message_part.msgCtnt
#사용자ID
USER_ID=
#응답타입-정상여부(0=정상|1=에러)
RESPONSE_TYPE=header_part.prcsRsltDscd
#거래동기화구분코드(S|A)
SYNC_ASYNC_TYPE=header_part.syncDscd
@@ -1,60 +0,0 @@
#표준(KAKAOBANK_CARD)=비표준(KAKAOBANK)
########HEADER##################################
#표준전문길이 STND_MESG_LEN : Flat에서 설정필요
#암호화압축구분코드 ENCD_CMPI_DVCD : default값 활용(0)
#GUID GUID
HEADER.GUID=Header.GUID
#전문요청구분코드 MESG_DMAN_DVCD ######INTERFACE KEY(2)
HEADER.FMSG_REQ_RES_DSTCD=Header.MESG_DMAN_DVCD
#전문버전번호 MESG_VER_NO : default값 활용(R10)
#최초전송IP주소 FRST_TRNM_IPAD
HEADER.FRST_TRNM_IPAD=Header.FRST_TRNM_IPAD
#최초전송시스템코드 FRST_TRNM_SYS_CD
HEADER.FRST_TRNM_SYS_CD=
#총괄타임아웃시간 GNRZ_TMOT_TKTM : default값 활용(050)
HEADER.GNRZ_TMOT_TM=Header.GNRZ_TMOT_TKTM
#거래타임아웃시간 TX_TMOT_TKTM : default값 활용(050)
########COMMON##################################
#그룹회사코드 GROUP_CMP_CD : default값 활용(090)
#서비스ID SRVC_ID : 카드 인터페이스에 등록된 값을 셋팅한다.
#처리결과수신서비스ID PROCS_RSLT_RCMS_SRVC_ID : 확인필요
#인터페이스ID IF_ID : 카드 인터페이스에 등록된 값을 셋팅한다. ######INTERFACE KEY(1)
#거래동기화구분코드 TX_SYNZ_DVCD : default값 활용(S)
#내외구분코드 HMAB_DVCD ######INTERFACE KEY(3)
INTERFACE_COMMON.IOSD_DSTCD=Common.HMAB_DVCD
#시스템운영환경구분코드 SYS_OPRT_ENV_DVCD
HEADER.SYS_ENV_DSTCD=Common.SYS_OPRT_ENV_DVCD
#거래유형구분코드 TX_TYP_DVCD : default값 활용(O)
#원거래복원여부 ORTR_RESTR_YN : default값 활용(N)
#은행코드 BANK_CD : default값 활용(090)
#거래부점코드 TX_BRCD
COMMON.TX_BRCD=Common.TX_BRCD
#실거래부점코드 RLTR_BRCD
COMMON.RLTR_BRCD=Common.RLTR_BRCD
#채널유형코드 CHNL_TYCD : default값 활용(U)
#채널공통부문존재여부 CHNL_COM_SCTN_EXIS_YN : default값 활용(N)
#텔러번호 TLRNO
COMMON.TLRNO=Common.TLRNO
###계정계셋팅-시작
#거래일자 TX_DT
#거래시각 TX_TIME
#시스템일자 SYS_DT
#시스템시각 SYS_TIME
###계정계셋팅-끝 ???
#전문요청일자 MESG_DMAN_DT
COMMON.TX_DT=Common.MESG_DMAN_DT
#전문요청시간 MESG_DMAN_TKTM
COMMON.TX_TM=Common.MESG_DMAN_TKTM
#처리결과구분코드 PROCS_RSLT_DSTCD
COMMON.PROCS_RSLT_DSTCD=Common.PROCS_RSLT_DVCD
########################메시지부#####################
#MESSAGE.MSG_HEDR_KNCD=MESSAGE.MSG_HEDR_KNCD
MESSAGE.OUT_ATRB_CD=MSG.OUTPUT_ATRB_CD
MESSAGE.OUT_MSG_CD=MSG.OUTPUT_MSG_CD
MESSAGE.OUT_MSG_CTNT=MSG.OUTPUT_MSG_CTNT
MESSAGE.OUT_MSG_DESC=MSG.OUTPUT_MSG_DESC
#MESSAGE.OUTPUT_MSG_CD=MESSAGE.OUTPUT_MSG_GROUP[0].OUTPUT_MSG_CD
#MESSAGE.OUTPUT_MSG_CTNT=MESSAGE.OUTPUT_MSG_GROUP[0].OUTPUT_MSG_CTNT
#MESSAGE.OUTPUT_MSG_DESC=MESSAGE.OUTPUT_MSG_GROUP[0].OUTPUT_MSG_DESC
########################업무데이터####################
DATA=DataPart.DataBody
@@ -1,5 +0,0 @@
service_id=header.if_id
global_id=header.guid
service_tn=header.req_type
return_value=header.inex_type
bizData=bizData
@@ -0,0 +1,108 @@
package com.eactive.eai.agent.inflow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import com.eactive.eai.agent.command.CommandException;
import com.eactive.eai.agent.inflow.ReloadInflowClientControlCommand;
import com.eactive.eai.common.inflow.InflowControlManager;
import com.eactive.eai.common.inflow.InflowControlUtil;
import com.eactive.eai.custom.inflow.ClientDualInflowControlManager;
/**
* ReloadInflowClientControlCommand 단위 테스트.
*
* <p>InflowControlUtil의 cachedInflowControlManager 필드에 mock을 직접 주입하여
* PropManager/ApplicationContext 없이 동작을 검증한다.
*/
class ReloadInflowClientControlCommandTest {
private ClientDualInflowControlManager mockDualManager;
@BeforeEach
void setUp() {
mockDualManager = mock(ClientDualInflowControlManager.class);
ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", null);
}
@AfterEach
void tearDown() {
ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", null);
}
private ReloadInflowClientControlCommand commandWith(Object args) {
ReloadInflowClientControlCommand cmd = new ReloadInflowClientControlCommand();
cmd.setArgs(args);
return cmd;
}
// =========================================================================
// args 타입 검증 실패
// =========================================================================
@Test
void execute_argsIsInteger_throwsCommandException() {
// args 검증이 getInflowControlManager() 호출 이전에 발생하므로 캐시 설정 불필요
assertThrows(CommandException.class, commandWith(Integer.valueOf(1))::execute);
}
// =========================================================================
// ClientDualInflowControlManager 비활성
// =========================================================================
@Test
void execute_notClientDualManager_throwsCommandException() {
InflowControlManager baseMgr = mock(InflowControlManager.class);
ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", baseMgr);
assertThrows(CommandException.class, commandWith("CLIENT_A")::execute);
}
// =========================================================================
// 전체 재로드 (ALL)
// =========================================================================
@Test
void execute_argsIsALL_callsReloadClientNoArgs() throws Exception {
ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", mockDualManager);
Object result = commandWith("ALL").execute();
assertEquals("success", result);
verify(mockDualManager).reloadClient();
verify(mockDualManager, never()).reloadClient(anyString());
}
// =========================================================================
// 개별 재로드 (ClientId)
// =========================================================================
@Test
void execute_argsIsClientId_callsReloadClientWithId() throws Exception {
ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", mockDualManager);
Object result = commandWith("CLIENT_A").execute();
assertEquals("success", result);
verify(mockDualManager).reloadClient("CLIENT_A");
verify(mockDualManager, never()).reloadClient();
}
@Test
void execute_differentClientId_callsReloadClientWithThatId() throws Exception {
ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", mockDualManager);
commandWith("CLIENT_B").execute();
verify(mockDualManager).reloadClient("CLIENT_B");
}
}
@@ -0,0 +1,101 @@
package com.eactive.eai.agent.inflow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import com.eactive.eai.agent.command.CommandException;
import com.eactive.eai.agent.inflow.RemoveInflowClientControlCommand;
import com.eactive.eai.common.inflow.InflowControlManager;
import com.eactive.eai.common.inflow.InflowControlUtil;
import com.eactive.eai.custom.inflow.ClientDualInflowControlManager;
/**
* RemoveInflowClientControlCommand 단위 테스트.
*
* <p>InflowControlUtil의 cachedInflowControlManager 필드에 mock을 직접 주입하여
* PropManager/ApplicationContext 없이 동작을 검증한다.
*/
class RemoveInflowClientControlCommandTest {
private ClientDualInflowControlManager mockDualManager;
@BeforeEach
void setUp() {
mockDualManager = mock(ClientDualInflowControlManager.class);
ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", null);
}
@AfterEach
void tearDown() {
ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", null);
}
private RemoveInflowClientControlCommand commandWith(Object args) {
RemoveInflowClientControlCommand cmd = new RemoveInflowClientControlCommand();
cmd.setArgs(args);
return cmd;
}
// =========================================================================
// args 타입 검증 실패
// =========================================================================
@Test
void execute_argsIsInteger_throwsCommandException() {
assertThrows(CommandException.class, commandWith(Integer.valueOf(1))::execute);
}
// =========================================================================
// ClientDualInflowControlManager 비활성
// =========================================================================
@Test
void execute_notClientDualManager_throwsCommandException() {
InflowControlManager baseMgr = mock(InflowControlManager.class);
ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", baseMgr);
assertThrows(CommandException.class, commandWith("CLIENT_A")::execute);
}
// =========================================================================
// 정상 제거
// =========================================================================
@Test
void execute_validClientId_callsRemoveClient() throws CommandException {
ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", mockDualManager);
Object result = commandWith("CLIENT_A").execute();
assertEquals("success", result);
verify(mockDualManager).removeClient("CLIENT_A");
}
@Test
void execute_differentClientId_callsRemoveClientWithThatId() throws Exception {
ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", mockDualManager);
commandWith("CLIENT_B").execute();
verify(mockDualManager).removeClient("CLIENT_B");
}
@Test
void execute_validClientId_doesNotCallReload() throws Exception {
ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", mockDualManager);
commandWith("CLIENT_A").execute();
verify(mockDualManager, never()).reloadClient();
verify(mockDualManager, never()).reloadClient(anyString());
}
}
@@ -1,317 +0,0 @@
package com.eactive.eai.custom.adapter.http.dynamic.filter;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
import java.util.Properties;
import org.mockito.ArgumentCaptor;
import javax.servlet.http.HttpServletRequest;
import org.json.simple.JSONObject;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.support.GenericApplicationContext;
import com.eactive.eai.common.security.CryptoModuleService;
import com.eactive.eai.common.util.ApplicationContextProvider;
@TestMethodOrder(MethodOrderer.DisplayName.class)
class DJBErpCryptoFilterTest {
private static final String MODULE_NAME = "TEST_MODULE";
// 복호화 후 평문 (JSON 문자열)
private static final String PLAIN_TEXT = "{\"userId\":\"U001\",\"name\":\"test\"}";
private static final byte[] PLAIN_BYTES = PLAIN_TEXT.getBytes(StandardCharsets.UTF_8);
// 더미 암호문 bytes + Base64 표현
private static final byte[] CIPHER_BYTES = new byte[]{0x10, 0x20, 0x30, 0x40};
private static final String ENC_BASE64 = Base64.getEncoder().encodeToString(CIPHER_BYTES);
// 기본 httpHeaderGroup 헤더 JSON (groupSeq|empNo 형태)
private static final String HEADER_JSON_WITH_PIPE = "{\"x-emp-nm\":\"G001|E001\"}";
private static final String HEADER_JSON_WITHOUT_PIPE = "{\"x-emp-nm\":\"G001\"}";
private static GenericApplicationContext ctx;
private static CryptoModuleService mockCryptoService;
private DJBErpCryptoFilter filter;
private HttpServletRequest mockRequest;
private Properties prop;
// =========================================================================
// 클래스 초기화 — Spring ApplicationContext + Mock CryptoModuleService
// =========================================================================
@BeforeAll
static void setUpClass() throws Exception {
mockCryptoService = mock(CryptoModuleService.class);
ctx = new GenericApplicationContext();
ctx.getBeanFactory().registerSingleton("cryptoModuleService", mockCryptoService);
ctx.registerBeanDefinition("applicationContextProvider",
BeanDefinitionBuilder.genericBeanDefinition(ApplicationContextProvider.class)
.getBeanDefinition());
ctx.refresh();
when(mockCryptoService.decrypt(anyString(), anyMap(), any(byte[].class)))
.thenReturn(PLAIN_BYTES);
when(mockCryptoService.encrypt(anyString(), anyMap(), any(byte[].class)))
.thenReturn(CIPHER_BYTES);
}
@AfterAll
static void tearDownClass() {
if (ctx != null) ctx.close();
}
@BeforeEach
void setUp() {
clearInvocations(mockCryptoService); // 이전 테스트의 호출 이력 초기화 (stubbing은 유지)
filter = new DJBErpCryptoFilter();
mockRequest = mock(HttpServletRequest.class);
prop = new Properties();
prop.setProperty(DJBErpCryptoFilter.PROP_MODULE_NAME, MODULE_NAME);
}
// =========================================================================
// 1. buildRuntimeContext
// =========================================================================
@Test
@DisplayName("1-1. x-emp-nm이 'groupSeq|empNo' 형태이면 '|' 앞부분만 groupSeq로 추출")
void buildRuntimeContext_pipeFormat_extractsGroupSeqOnly() {
when(mockRequest.getHeader("httpHeaderGroup")).thenReturn(HEADER_JSON_WITH_PIPE);
Map<String, String> runtimeCtx = filter.buildRuntimeContext(prop, mockRequest);
assertEquals("G001", runtimeCtx.get("groupSeq"));
assertEquals(1, runtimeCtx.size());
}
@Test
@DisplayName("1-2. x-emp-nm에 '|'가 없으면 전체 값을 groupSeq로 사용")
void buildRuntimeContext_noPipe_usesFullValue() {
when(mockRequest.getHeader("httpHeaderGroup")).thenReturn(HEADER_JSON_WITHOUT_PIPE);
Map<String, String> runtimeCtx = filter.buildRuntimeContext(prop, mockRequest);
assertEquals("G001", runtimeCtx.get("groupSeq"));
}
@Test
@DisplayName("1-3. httpHeaderGroup 헤더가 없으면 빈 Map 반환")
void buildRuntimeContext_headerMissing_returnsEmptyMap() {
when(mockRequest.getHeader("httpHeaderGroup")).thenReturn(null);
Map<String, String> runtimeCtx = filter.buildRuntimeContext(prop, mockRequest);
assertTrue(runtimeCtx.isEmpty());
}
@Test
@DisplayName("1-4. 헤더 JSON에 x-emp-nm 필드가 없으면 빈 Map 반환")
void buildRuntimeContext_fieldMissingInJson_returnsEmptyMap() {
when(mockRequest.getHeader("httpHeaderGroup")).thenReturn("{\"other-field\":\"value\"}");
Map<String, String> runtimeCtx = filter.buildRuntimeContext(prop, mockRequest);
assertTrue(runtimeCtx.isEmpty());
}
@Test
@DisplayName("1-5. 프로퍼티로 헤더명/필드명/컨텍스트키를 커스터마이징할 수 있다")
void buildRuntimeContext_customProps_overrideDefaults() {
prop.setProperty(DJBErpCryptoFilter.PROP_CONTEXT_HEADER, "X-Custom-Header");
prop.setProperty(DJBErpCryptoFilter.PROP_CONTEXT_HEADER_FIELD, "emp-id");
prop.setProperty(DJBErpCryptoFilter.PROP_CONTEXT_KEY, "empGroup");
when(mockRequest.getHeader("X-Custom-Header")).thenReturn("{\"emp-id\":\"GRP99|EMP99\"}");
Map<String, String> runtimeCtx = filter.buildRuntimeContext(prop, mockRequest);
assertEquals("GRP99", runtimeCtx.get("empGroup"));
}
// =========================================================================
// 2. doPreFilter — 복호화
// =========================================================================
@Test
@DisplayName("2-1. crypto.dec.enabled=N 이면 message를 그대로 반환하고 복호화하지 않는다")
void doPreFilter_decDisabled_returnsOriginalWithoutDecrypt() throws Exception {
prop.setProperty("crypto.dec.enabled", "N");
String original = "{\"encryptedData\":\"" + ENC_BASE64 + "\"}";
Object result = filter.doPreFilter(null, null, original, prop, mockRequest, null);
assertSame(original, result);
verifyNoInteractions(mockCryptoService);
}
@Test
@DisplayName("2-2. FIELD scope: /encryptedData 복호화 후 dec.to.path=/ 이면 body 전체를 평문으로 교체")
void doPreFilter_fieldScope_toRoot_replacesEntireBody() throws Exception {
setFieldDecryptProps("/encryptedData", "/");
when(mockRequest.getHeader("httpHeaderGroup")).thenReturn(HEADER_JSON_WITH_PIPE);
String body = "{\"encryptedData\":\"" + ENC_BASE64 + "\"}";
Object result = filter.doPreFilter(null, null, body, prop, mockRequest, null);
assertEquals(PLAIN_TEXT, result);
}
@Test
@DisplayName("2-3. FIELD scope: dec.to.path가 특정 경로이면 해당 필드에 복호화 결과를 설정")
void doPreFilter_fieldScope_toSpecificPath_setsFieldInBody() throws Exception {
setFieldDecryptProps("/encryptedData", "/plainData");
when(mockRequest.getHeader("httpHeaderGroup")).thenReturn(HEADER_JSON_WITH_PIPE);
String body = "{\"encryptedData\":\"" + ENC_BASE64 + "\"}";
String result = (String) filter.doPreFilter(null, null, body, prop, mockRequest, null);
assertTrue(result.contains("\"encryptedData\""), "원본 필드가 유지되어야 한다");
assertTrue(result.contains("\"plainData\""), "복호화 결과 필드가 추가되어야 한다");
}
@Test
@DisplayName("2-4. FIELD scope: 복호화 대상 필드가 JSON에 없으면 원본 body를 그대로 반환")
void doPreFilter_fieldScope_missingEncryptedField_returnsOriginalBody() throws Exception {
setFieldDecryptProps("/encryptedData", "/");
when(mockRequest.getHeader("httpHeaderGroup")).thenReturn(HEADER_JSON_WITH_PIPE);
String body = "{\"otherField\":\"value\"}";
Object result = filter.doPreFilter(null, null, body, prop, mockRequest, null);
assertEquals(body, result);
}
@Test
@DisplayName("2-5. BODY scope: message가 Base64 String이면 전체 복호화")
void doPreFilter_bodyScope_stringMessage_decryptsWholeBody() throws Exception {
prop.setProperty("crypto.scope", "BODY");
Object result = filter.doPreFilter(null, null, ENC_BASE64, prop, mockRequest, null);
assertEquals(PLAIN_TEXT, result);
}
@Test
@DisplayName("2-6. message가 byte[]이면 UTF-8 변환 후 FIELD 복호화 처리")
void doPreFilter_fieldScope_byteArrayMessage_convertsAndDecrypts() throws Exception {
setFieldDecryptProps("/encryptedData", "/");
when(mockRequest.getHeader("httpHeaderGroup")).thenReturn(HEADER_JSON_WITH_PIPE);
byte[] bodyBytes = ("{\"encryptedData\":\"" + ENC_BASE64 + "\"}").getBytes(StandardCharsets.UTF_8);
Object result = filter.doPreFilter(null, null, bodyBytes, prop, mockRequest, null);
assertEquals(PLAIN_TEXT, result);
}
@SuppressWarnings("unchecked")
@Test
@DisplayName("2-7. message가 JSONObject이면 toString() 변환 후 FIELD 복호화 처리")
void doPreFilter_fieldScope_jsonObjectMessage_convertsAndDecrypts() throws Exception {
setFieldDecryptProps("/encryptedData", "/");
when(mockRequest.getHeader("httpHeaderGroup")).thenReturn(HEADER_JSON_WITH_PIPE);
JSONObject jsonMsg = new JSONObject();
jsonMsg.put("encryptedData", ENC_BASE64);
Object result = filter.doPreFilter(null, null, jsonMsg, prop, mockRequest, null);
assertEquals(PLAIN_TEXT, result);
}
@SuppressWarnings("unchecked")
@Test
@DisplayName("2-8. FIELD scope: runtimeContext에 groupSeq가 올바르게 전달된다")
void doPreFilter_fieldScope_runtimeContextPassedToDecrypt() throws Exception {
setFieldDecryptProps("/encryptedData", "/");
when(mockRequest.getHeader("httpHeaderGroup")).thenReturn(HEADER_JSON_WITH_PIPE);
String body = "{\"encryptedData\":\"" + ENC_BASE64 + "\"}";
filter.doPreFilter(null, null, body, prop, mockRequest, null);
ArgumentCaptor<Map> ctxCaptor = ArgumentCaptor.forClass(Map.class);
verify(mockCryptoService).decrypt(eq(MODULE_NAME), ctxCaptor.capture(), any(byte[].class));
assertEquals("G001", ctxCaptor.getValue().get("groupSeq"));
}
// =========================================================================
// 3. doPostFilter — 암호화
// =========================================================================
@Test
@DisplayName("3-1. crypto.enc.enabled 기본값(N) — resultMessage를 그대로 반환하고 암호화하지 않는다")
void doPostFilter_encDisabledByDefault_returnsOriginalWithoutEncrypt() throws Exception {
String original = "{\"result\":\"ok\"}";
Object result = filter.doPostFilter(null, null, original, prop, mockRequest, null);
assertSame(original, result);
verifyNoInteractions(mockCryptoService);
}
@Test
@DisplayName("3-2. BODY scope, enc.enabled=Y — body 전체를 암호화하여 Base64 반환")
void doPostFilter_bodyScope_encEnabled_returnsBase64() throws Exception {
prop.setProperty("crypto.scope", "BODY");
prop.setProperty("crypto.enc.enabled", "Y");
Object result = filter.doPostFilter(null, null, PLAIN_TEXT, prop, mockRequest, null);
assertEquals(ENC_BASE64, result);
}
@Test
@DisplayName("3-3. FIELD scope, enc.from.path=/ — body 전체 암호화 후 enc.to.path 필드로 래핑")
void doPostFilter_fieldScope_fromRoot_wrapsEncryptedInJson() throws Exception {
prop.setProperty("crypto.scope", "FIELD");
prop.setProperty("crypto.enc.enabled", "Y");
prop.setProperty("crypto.enc.from.path", "/");
prop.setProperty("crypto.enc.to.path", "/encryptedData");
Object result = filter.doPostFilter(null, null, PLAIN_TEXT, prop, mockRequest, null);
assertEquals("{\"encryptedData\":\"" + ENC_BASE64 + "\"}", result);
}
@SuppressWarnings("unchecked")
@Test
@DisplayName("3-4. FIELD scope: runtimeContext에 groupSeq가 올바르게 전달된다")
void doPostFilter_fieldScope_runtimeContextPassedToEncrypt() throws Exception {
prop.setProperty("crypto.scope", "FIELD");
prop.setProperty("crypto.enc.enabled", "Y");
prop.setProperty("crypto.enc.from.path", "/");
prop.setProperty("crypto.enc.to.path", "/encryptedData");
when(mockRequest.getHeader("httpHeaderGroup")).thenReturn(HEADER_JSON_WITH_PIPE);
filter.doPostFilter(null, null, PLAIN_TEXT, prop, mockRequest, null);
ArgumentCaptor<Map> ctxCaptor = ArgumentCaptor.forClass(Map.class);
verify(mockCryptoService).encrypt(eq(MODULE_NAME), ctxCaptor.capture(), any(byte[].class));
assertEquals("G001", ctxCaptor.getValue().get("groupSeq"));
}
// =========================================================================
// 헬퍼
// =========================================================================
private void setFieldDecryptProps(String fromPath, String toPath) {
prop.setProperty("crypto.scope", "FIELD");
prop.setProperty("crypto.dec.from.path", fromPath);
prop.setProperty("crypto.dec.to.path", toPath);
}
}
@@ -0,0 +1,175 @@
package com.eactive.eai.custom.common.security.keyderiv;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.support.GenericApplicationContext;
import com.eactive.eai.common.hsm.HsmCryptoService;
import com.eactive.eai.common.security.keyderiv.DerivedKey;
import com.eactive.eai.common.util.ApplicationContextProvider;
/**
* HsmKeyAndIvSliceDerivationStrategy 단위 테스트
*/
@TestMethodOrder(MethodOrderer.DisplayName.class)
class HsmKeyAndIvSliceDerivationStrategyTest {
private static final String HSM_KEY_ALIAS = "MASTER_KEY_AES";
private static final String HSM_IV_ALIAS = "MASTER_IV_AES";
/** 32바이트 암호화 키 (AES-256) */
private static final byte[] MASTER_KEY = new byte[32];
/** 32바이트 IV 원본 → hex 64자 → substring(32,64) → 16바이트 IV */
private static final byte[] MASTER_IV = new byte[32];
static {
for (int i = 0; i < MASTER_KEY.length; i++) MASTER_KEY[i] = (byte) (i + 1);
for (int i = 0; i < MASTER_IV.length; i++) MASTER_IV[i] = (byte) (i + 0x10);
}
private static GenericApplicationContext ctx;
private static HsmCryptoService mockHsmCryptoService;
private static HsmKeyAndIvSliceDerivationStrategy strategy;
private Map<String, String> params;
private Map<String, String> runtimeContext;
@BeforeAll
static void setUpClass() throws Exception {
mockHsmCryptoService = mock(HsmCryptoService.class);
when(mockHsmCryptoService.getSecretKey(HSM_KEY_ALIAS))
.thenReturn(new SecretKeySpec(MASTER_KEY, "AES"));
when(mockHsmCryptoService.getSecretKey(HSM_IV_ALIAS))
.thenReturn(new SecretKeySpec(MASTER_IV, "AES"));
ctx = new GenericApplicationContext();
ctx.getBeanFactory().registerSingleton("hsmCryptoService", mockHsmCryptoService);
ctx.registerBeanDefinition("applicationContextProvider",
BeanDefinitionBuilder.genericBeanDefinition(ApplicationContextProvider.class)
.getBeanDefinition());
ctx.refresh();
strategy = new HsmKeyAndIvSliceDerivationStrategy();
}
@BeforeEach
void setUpParams() {
params = new HashMap<>();
params.put("hsmKeyAlias", HSM_KEY_ALIAS);
params.put("hsmIvAlias", HSM_IV_ALIAS);
runtimeContext = new HashMap<>();
}
// =========================================================================
// 1. deriveKey
// =========================================================================
@Test
@DisplayName("1-1. 정상 파라미터 — DerivedKey 반환, encKey/iv 모두 non-null")
void testDeriveKey_validParams_returnsKeyAndIv() throws Exception {
DerivedKey dk = strategy.deriveKey(params, runtimeContext);
assertNotNull(dk);
assertNotNull(dk.getEncKey());
assertNotNull(dk.getIv());
}
@Test
@DisplayName("1-2. encKey는 hsmKeyAlias에 해당하는 HSM 키")
void testDeriveKey_encKeyMatchesMasterKey() throws Exception {
DerivedKey dk = strategy.deriveKey(params, runtimeContext);
assertArrayEquals(MASTER_KEY, dk.getEncKey());
}
@Test
@DisplayName("1-3. encKey == decKey (대칭 방식)")
void testDeriveKey_encKeyEqualsDecKey() throws Exception {
DerivedKey dk = strategy.deriveKey(params, runtimeContext);
assertArrayEquals(dk.getEncKey(), dk.getDecKey());
}
@Test
@DisplayName("1-4. iv는 HSM IV hex 문자열의 substring(32,64)와 일치")
void testDeriveKey_ivIsHexSubstring32To64() throws Exception {
DerivedKey dk = strategy.deriveKey(params, runtimeContext);
String ivHex = DatatypeConverter.printHexBinary(MASTER_IV);
byte[] expected = DatatypeConverter.parseHexBinary(ivHex.substring(32, 64));
assertArrayEquals(expected, dk.getIv(), "iv는 HSM IV hex substring(32,64) 파싱 결과여야 한다");
}
@Test
@DisplayName("1-5. iv 길이 == 16바이트 (hex 32자 = 16바이트)")
void testDeriveKey_ivLength16() throws Exception {
DerivedKey dk = strategy.deriveKey(params, runtimeContext);
assertEquals(16, dk.getIv().length);
}
@Test
@DisplayName("1-6. hsmIvAlias hex 길이가 64자 미만 — IllegalArgumentException")
void testDeriveKey_ivTooShort_throwsException() throws Exception {
byte[] shortIv = new byte[15]; // hex 30자 → 64자 미만
when(mockHsmCryptoService.getSecretKey("SHORT_IV"))
.thenReturn(new SecretKeySpec(shortIv, "AES"));
params.put("hsmIvAlias", "SHORT_IV");
assertThrows(IllegalArgumentException.class,
() -> strategy.deriveKey(params, runtimeContext),
"IV hex 길이 부족 시 IllegalArgumentException이 발생해야 한다");
}
@Test
@DisplayName("1-7. 필수 파라미터 누락(hsmKeyAlias) — IllegalArgumentException")
void testDeriveKey_missingHsmKeyAlias_throwsException() {
params.remove("hsmKeyAlias");
assertThrows(IllegalArgumentException.class,
() -> strategy.deriveKey(params, runtimeContext));
}
@Test
@DisplayName("1-8. 필수 파라미터 누락(hsmIvAlias) — IllegalArgumentException")
void testDeriveKey_missingHsmIvAlias_throwsException() {
params.remove("hsmIvAlias");
assertThrows(IllegalArgumentException.class,
() -> strategy.deriveKey(params, runtimeContext));
}
// =========================================================================
// 2. buildCacheKey
// =========================================================================
@Test
@DisplayName("2-1. buildCacheKey — cryptoName 단독 반환")
void testBuildCacheKey_returnsCryptoName() {
assertEquals("CRYPTO_A", strategy.buildCacheKey("CRYPTO_A", params, runtimeContext));
}
@Test
@DisplayName("2-2. buildCacheKey — 다른 cryptoName은 다른 캐시 키")
void testBuildCacheKey_differentCryptoName_differentKey() {
assertNotEquals(
strategy.buildCacheKey("CRYPTO_A", params, runtimeContext),
strategy.buildCacheKey("CRYPTO_B", params, runtimeContext));
}
}
@@ -0,0 +1,196 @@
package com.eactive.eai.custom.inbound.processor;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import com.eactive.eai.common.inflow.InflowTargetVO;
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
import com.eactive.eai.common.inflow.dual.DualInflowControlManager;
import com.eactive.eai.custom.inflow.ClientDualInflowControlManager;
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket4j;
import io.github.bucket4j.local.LocalBucket;
/**
* ClientDualInflowControlManager 클라이언트 메트릭 단위 테스트.
*/
class ClientDualInflowControlManagerMetricsTest {
private ClientDualInflowControlManager manager;
@BeforeEach
void setUp() {
manager = new ClientDualInflowControlManager();
}
// -------------------------------------------------------------------------
// Helpers
// -------------------------------------------------------------------------
private InflowTargetVO makeTargetVO(String name) {
InflowTargetVO vo = new InflowTargetVO();
vo.setName(name);
vo.setThresholdPerSecond(100);
vo.setThreshold(10000);
vo.setThresholdTimeUnit("DAY");
vo.setActivate(true);
return vo;
}
private LocalBucket stableBucket(long capacity) {
return Bucket4j.builder()
.addLimit(Bandwidth.simple(capacity, Duration.ofHours(1)))
.build();
}
private LocalBucket exhaustedBucket(long capacity) {
LocalBucket b = stableBucket(capacity);
b.tryConsume(capacity);
return b;
}
private DualCustomBucket passDualBucket(String name) {
return new DualCustomBucket(stableBucket(100), null, makeTargetVO(name));
}
private DualCustomBucket blockedPerSecondDualBucket(String name) {
return new DualCustomBucket(exhaustedBucket(1), null, makeTargetVO(name));
}
private DualCustomBucket blockedThresholdDualBucket(String name) {
return new DualCustomBucket(stableBucket(100), exhaustedBucket(1), makeTargetVO(name));
}
private void injectClientMap(Map<String, DualCustomBucket> map) {
ReflectionTestUtils.setField(manager, "clientBucketMap", map);
}
// =========================================================================
// isClientPassDetail() — 카운터 증가
// =========================================================================
@Test
void isClientPassDetail_bucketNotRegistered_noMetricsCreated() {
manager.isClientPassDetail("UNKNOWN");
assertNull(manager.getClientMetrics("UNKNOWN"));
}
@Test
void isClientPassDetail_pass_incrementsAllowed() {
Map<String, DualCustomBucket> map = new ConcurrentHashMap<>();
map.put("C1", passDualBucket("C1"));
injectClientMap(map);
manager.isClientPassDetail("C1");
assertEquals(1, manager.getClientMetrics("C1").allowed.get());
}
@Test
void isClientPassDetail_blockedThreshold_incrementsRejectedThreshold() {
Map<String, DualCustomBucket> map = new ConcurrentHashMap<>();
map.put("C1", blockedThresholdDualBucket("C1"));
injectClientMap(map);
manager.isClientPassDetail("C1");
assertEquals(1, manager.getClientMetrics("C1").rejectedThreshold.get());
}
@Test
void isClientPassDetail_blockedPerSecond_incrementsRejectedPerSecond() {
Map<String, DualCustomBucket> map = new ConcurrentHashMap<>();
map.put("C1", blockedPerSecondDualBucket("C1"));
injectClientMap(map);
manager.isClientPassDetail("C1");
assertEquals(1, manager.getClientMetrics("C1").rejectedPerSecond.get());
}
// =========================================================================
// getAllClientMetrics — 조회 및 불변성
// =========================================================================
@Test
void getAllClientMetrics_empty_returnsEmptyMap() {
assertTrue(manager.getAllClientMetrics().isEmpty());
}
@Test
void getAllClientMetrics_afterCalls_containsEntries() {
Map<String, DualCustomBucket> map = new ConcurrentHashMap<>();
map.put("C1", passDualBucket("C1"));
map.put("C2", passDualBucket("C2"));
injectClientMap(map);
manager.isClientPassDetail("C1");
manager.isClientPassDetail("C2");
Map<String, DualInflowControlManager.TargetMetrics> all = manager.getAllClientMetrics();
assertEquals(2, all.size());
assertTrue(all.containsKey("C1"));
assertTrue(all.containsKey("C2"));
}
// =========================================================================
// resetClientMetrics / resetAllClientMetrics
// =========================================================================
@Test
void resetClientMetrics_resetsTargetClient() {
Map<String, DualCustomBucket> map = new ConcurrentHashMap<>();
map.put("C1", passDualBucket("C1"));
injectClientMap(map);
manager.isClientPassDetail("C1");
manager.resetClientMetrics("C1");
assertEquals(0, manager.getClientMetrics("C1").allowed.get());
}
@Test
void resetAllClientMetrics_resetsAll() {
Map<String, DualCustomBucket> map = new ConcurrentHashMap<>();
map.put("C1", passDualBucket("C1"));
map.put("C2", passDualBucket("C2"));
injectClientMap(map);
manager.isClientPassDetail("C1");
manager.isClientPassDetail("C2");
manager.resetAllClientMetrics();
assertEquals(0, manager.getClientMetrics("C1").allowed.get());
assertEquals(0, manager.getClientMetrics("C2").allowed.get());
}
// =========================================================================
// removeClient — 메트릭 자동 삭제
// =========================================================================
@Test
void removeClient_cleansUpMetrics() {
Map<String, DualCustomBucket> map = new ConcurrentHashMap<>();
map.put("C1", passDualBucket("C1"));
injectClientMap(map);
manager.isClientPassDetail("C1");
assertNotNull(manager.getClientMetrics("C1"));
manager.removeClient("C1");
assertNull(manager.getClientMetrics("C1"));
}
}
@@ -1,7 +1,14 @@
package com.eactive.eai.custom.inbound.processor;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Properties;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -10,11 +17,12 @@ import org.springframework.test.util.ReflectionTestUtils;
import com.eactive.eai.common.inflow.Bucket;
import com.eactive.eai.common.inflow.InflowTargetVO;
import com.eactive.eai.common.inflow.dual.ClientDualBucket;
import com.eactive.eai.common.inflow.dual.DualBucket;
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.custom.inflow.ClientDualBucket;
/**
* DJBRequestProcessor 단위 테스트.
@@ -48,6 +56,12 @@ class DJBRequestProcessorTest {
return vo;
}
private EAIMessage mockEaiMsg(String clientId) {
EAIMessage msg = mock(EAIMessage.class);
when(msg.getClientId()).thenReturn(clientId);
return msg;
}
// -------------------------------------------------------------------------
// checkAdapterInflow
// -------------------------------------------------------------------------
@@ -143,43 +157,43 @@ class DJBRequestProcessorTest {
}
// -------------------------------------------------------------------------
// checkClientInflow — ClientDualBucket 기반
// checkCustomInflow — ClientDualBucket 기반
// -------------------------------------------------------------------------
@Test
void checkClientInflow_clientDualBucket_pass_returnsNull() {
void checkCustomInflow_clientDualBucket_pass_returnsNull() {
DJBRequestProcessor processor = new DJBRequestProcessor();
ClientDualBucket mockBucket = mock(ClientDualBucket.class);
when(mockBucket.isClientPassDetail("CLIENT_A")).thenReturn(null);
assertNull(processor.checkClientInflow(mockBucket, "CLIENT_A"));
assertNull(processor.checkCustomInflow(mockBucket, mockEaiMsg("CLIENT_A"), new Properties()));
verify(mockBucket).isClientPassDetail("CLIENT_A");
}
@Test
void checkClientInflow_clientDualBucket_blocked() {
void checkCustomInflow_clientDualBucket_blocked() {
DJBRequestProcessor processor = new DJBRequestProcessor();
ClientDualBucket mockBucket = mock(ClientDualBucket.class);
when(mockBucket.isClientPassDetail("CLIENT_A")).thenReturn(DualCustomBucket.RESULT_BLOCKED_THRESHOLD);
assertEquals(DualCustomBucket.RESULT_BLOCKED_THRESHOLD,
processor.checkClientInflow(mockBucket, "CLIENT_A"));
processor.checkCustomInflow(mockBucket, mockEaiMsg("CLIENT_A"), new Properties()));
}
@Test
void checkClientInflow_nonClientDualBucket_returnsNull() {
void checkCustomInflow_nonClientDualBucket_returnsNull() {
DJBRequestProcessor processor = new DJBRequestProcessor();
Bucket mockBucket = mock(Bucket.class);
assertNull(processor.checkClientInflow(mockBucket, "CLIENT_A"));
assertNull(processor.checkCustomInflow(mockBucket, mockEaiMsg("CLIENT_A"), new Properties()));
}
@Test
void checkClientInflow_blankClientId_returnsNull() {
void checkCustomInflow_blankClientId_returnsNull() {
DJBRequestProcessor processor = new DJBRequestProcessor();
ClientDualBucket mockBucket = mock(ClientDualBucket.class);
assertNull(processor.checkClientInflow(mockBucket, ""));
assertNull(processor.checkCustomInflow(mockBucket, mockEaiMsg(""), new Properties()));
verify(mockBucket, never()).isClientPassDetail(any());
}
@@ -1,7 +1,11 @@
package com.eactive.eai.custom.inflow;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.time.Duration;
import java.util.List;
@@ -11,7 +15,6 @@ import java.util.concurrent.ConcurrentHashMap;
import org.junit.jupiter.api.Test;
import com.eactive.eai.common.inflow.InflowTargetVO;
import com.eactive.eai.common.inflow.dual.ClientDualInflowControlManager;
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
import com.eactive.eai.manage.inflow.GroupBucketStatusDTO;
import com.eactive.eai.manage.inflow.TargetBucketStatusDTO;
@@ -1,14 +1,22 @@
package com.eactive.eai.custom.inflow;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.List;
import org.junit.jupiter.api.Test;
import com.eactive.eai.common.inflow.InflowTargetVO;
import com.eactive.eai.common.inflow.dual.ClientDualInflowControlManager;
import com.eactive.eai.common.inflow.dual.DualInflowControlManager;
import com.eactive.eai.manage.inflow.TargetMetricDTO;
@@ -6,6 +6,9 @@ import static org.mockito.ArgumentMatchers.anyString;
import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
@@ -20,6 +23,7 @@ import com.eactive.eai.common.monitor.EAIServiceMonitor;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.message.StandardItem;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.manager.StandardMessageManager;
import com.eactive.eai.message.service.InterfaceMapper;
@@ -354,4 +358,142 @@ class StandardMessageCoordinatorDJBTest {
assertNotNull(scopLen, "msg_scop_len이 null");
assertTrue(Integer.parseInt(scopLen.trim()) >= 0, "msg_scop_len은 0 이상이어야 함: " + scopLen);
}
// ================================================================
// resolveCallPropRefValues — ${callProp.키} 치환
// ================================================================
@Test
void callProp_refValue_단순키_값_주입() throws Exception {
// chnl_dtls_clcd: CSV 기본값 없음, refValue를 ${callProp.CHNL_CD}로 주입
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.CHNL_CD}");
Properties prop = new Properties();
prop.setProperty("CHNL_CD", "MOB");
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
assertEquals("MOB", message.findItemValue("HEAD.chnl_dtls_clcd"));
}
@Test
void callProp_refValue_기본값_키_없을때_기본값_사용() throws Exception {
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.MISSING:IB1}");
coordinator.coordinateAfterCreateMessageByRule(message, null, new Properties());
assertEquals("IB1", message.findItemValue("HEAD.chnl_dtls_clcd"));
}
@Test
void callProp_refValue_기본값_키_있을때_prop값으로_덮어씀() throws Exception {
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.CHNL_CD:IB1}");
Properties prop = new Properties();
prop.setProperty("CHNL_CD", "ATM");
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
assertEquals("ATM", message.findItemValue("HEAD.chnl_dtls_clcd"));
}
@Test
void callProp_refValue_prop_null이면_setValue_호출_안함() throws Exception {
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.CHNL_CD}");
coordinator.coordinateAfterCreateMessageByRule(message, null, null);
String val = message.findItemValue("HEAD.chnl_dtls_clcd");
assertTrue(val == null || val.trim().isEmpty(),
"prop=null이면 callProp refValue 치환하지 않아야 함: " + val);
}
@Test
void callProp_refValue_패턴_불일치_필드는_skip() throws Exception {
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "PLAIN");
Properties prop = new Properties();
prop.setProperty("chnl_dtls_clcd", "SHOULD_NOT_SET");
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
assertNotEquals("SHOULD_NOT_SET", message.findItemValue("HEAD.chnl_dtls_clcd"),
"패턴 불일치 refValue는 치환하지 않아야 함");
}
@Test
void callProp_refValue_여러_필드_동시_주입() throws Exception {
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.CHNL_CD}");
setRefValue(message.findItem("HEAD.xtis_cd"), "${callProp.XTIS_CD}");
Properties prop = new Properties();
prop.setProperty("CHNL_CD", "IB1");
prop.setProperty("XTIS_CD", "OBK");
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
assertEquals("IB1", message.findItemValue("HEAD.chnl_dtls_clcd"));
assertEquals("OBK", message.findItemValue("HEAD.xtis_cd"));
}
@Test
void callProp_중첩_Properties_점경로_조회() throws Exception {
// prop.get("OUTBOUND") = subProps, subProps.getProperty("IF_ID") = "SVC001"
// → ${callProp.OUTBOUND.IF_ID} → "SVC001"
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.OUTBOUND.IF_CD}");
Properties subProps = new Properties();
subProps.setProperty("IF_CD", "IB1");
Properties prop = new Properties();
prop.put("OUTBOUND", subProps);
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
assertEquals("IB1", message.findItemValue("HEAD.chnl_dtls_clcd"));
}
@Test
void callProp_중첩_Map_점경로_조회() throws Exception {
// prop.get("CTX") = Map{"CHNL":"MOB"}
// → ${callProp.CTX.CHNL} → "MOB"
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.CTX.CHNL}");
Map<String, Object> ctxMap = new HashMap<>();
ctxMap.put("CHNL", "MOB");
Properties prop = new Properties();
prop.put("CTX", ctxMap);
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
assertEquals("MOB", message.findItemValue("HEAD.chnl_dtls_clcd"));
}
@Test
void callProp_중간값_비Properties_폴백_전체키_조회() throws Exception {
// prop.get("aaa") = "plain" (Properties가 아님) → 전체 키 "aaa.bbb" 폴백
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.aaa.bbb}");
Properties prop = new Properties();
prop.setProperty("aaa", "plain");
prop.setProperty("aaa.bbb", "ATM");
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
assertEquals("ATM", message.findItemValue("HEAD.chnl_dtls_clcd"));
}
@Test
void callProp_중첩_키_없을때_기본값_사용() throws Exception {
setRefValue(message.findItem("HEAD.chnl_dtls_clcd"), "${callProp.OUTBOUND.MISSING:IB1}");
Properties subProps = new Properties(); // MISSING 키 없음
Properties prop = new Properties();
prop.put("OUTBOUND", subProps);
coordinator.coordinateAfterCreateMessageByRule(message, null, prop);
assertEquals("IB1", message.findItemValue("HEAD.chnl_dtls_clcd"));
}
// ----------------------------------------------------------------
// 헬퍼
// ----------------------------------------------------------------
private static void setRefValue(StandardItem item, String refValue) throws Exception {
Field f = StandardItem.class.getDeclaredField("refValue");
f.setAccessible(true);
f.set(item, refValue);
}
}
@@ -0,0 +1,242 @@
package com.eactive.eai.custom.transformer.function;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.support.GenericApplicationContext;
import com.eactive.eai.common.security.CryptoModuleService;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.transformer.engine.Parser;
/**
* DJBEncrypt / DJBDecrypt — Parser 표현식 통합 테스트.
*
* DJBCryptoFunctionTest 는 Stack 직접 호출 방식으로 run() 을 검증하고,
* 이 클래스는 Parser 를 통해 JEP 수식으로 함수를 호출하는 통합 경로를 검증한다.
*/
@TestMethodOrder(MethodOrderer.DisplayName.class)
@DisplayName("DJBEncrypt / DJBDecrypt — Parser 변수/상수 혼합 테스트")
class DJBCryptoFunctionParserTest {
private static final String MODULE = "AES_MODULE";
private static final String PLAIN_TEXT = "hello-djb";
private static final byte[] PLAIN_BYTES = PLAIN_TEXT.getBytes(StandardCharsets.UTF_8);
private static final byte[] CIPHER_BYTES = {0x01, 0x02, 0x03, 0x04};
private static final String ENC_BASE64 = Base64.getEncoder().encodeToString(CIPHER_BYTES);
private static GenericApplicationContext ctx;
private static CryptoModuleService mockService;
private Parser parser;
// =========================================================================
// 클래스 초기화 — mock CryptoModuleService 를 Spring 컨텍스트에 등록
// =========================================================================
@BeforeAll
static void setUpClass() throws Exception {
mockService = mock(CryptoModuleService.class);
ctx = new GenericApplicationContext();
ctx.getBeanFactory().registerSingleton("cryptoModuleService", mockService);
ctx.registerBeanDefinition("applicationContextProvider",
BeanDefinitionBuilder.genericBeanDefinition(ApplicationContextProvider.class)
.getBeanDefinition());
ctx.refresh();
}
@AfterAll
static void tearDownClass() {
if (ctx != null) ctx.close();
}
@BeforeEach
void setUp() throws Exception {
reset(mockService);
when(mockService.encrypt(any(), anyMap(), isNull(), any(byte[].class))).thenReturn(CIPHER_BYTES);
when(mockService.decrypt(any(), anyMap(), isNull(), any(byte[].class))).thenReturn(PLAIN_BYTES);
parser = new Parser();
parser.getJep().addFunction("DJBEncrypt", new DJBEncrypt());
parser.getJep().addFunction("DJBDecrypt", new DJBDecrypt());
}
// =========================================================================
// 1. DJBEncrypt
// =========================================================================
@Test
@DisplayName("1-1. 암호화 — 평문 변수 + 상수 모듈명 → Base64 반환")
void encrypt_variablePlain_constantModule() throws Exception {
parser.parse("DJBEncrypt(plain, \"" + MODULE + "\")");
parser.addVariable("plain", PLAIN_TEXT);
assertEquals(ENC_BASE64, parser.getValueAsObject());
}
@Test
@DisplayName("1-2. 암호화 — 평문·모듈명 모두 변수")
void encrypt_bothVariables() throws Exception {
parser.parse("DJBEncrypt(plain, moduleName)");
parser.addVariable("plain", PLAIN_TEXT);
parser.addVariable("moduleName", MODULE);
assertEquals(ENC_BASE64, parser.getValueAsObject());
}
@Test
@DisplayName("1-3. 암호화 — parse 1회, 변수값 교체 반복 평가")
void encrypt_reuseParser_multipleEvaluations() throws Exception {
// identity: plainBytes 그대로 반환 → Base64 encoding 경로 검증에 집중
when(mockService.encrypt(any(), anyMap(), isNull(), any(byte[].class)))
.thenAnswer(inv -> (byte[]) inv.getArgument(3));
parser.parse("DJBEncrypt(plain, \"" + MODULE + "\")");
parser.addVariable("plain", "first");
String r1 = (String) parser.getValueAsObject();
parser.addVariable("plain", "second");
String r2 = (String) parser.getValueAsObject();
assertEquals(Base64.getEncoder().encodeToString("first".getBytes(StandardCharsets.UTF_8)), r1);
assertEquals(Base64.getEncoder().encodeToString("second".getBytes(StandardCharsets.UTF_8)), r2);
}
@Test
@DisplayName("1-4. 암호화 — 한글 평문이 UTF-8 인코딩되어 서비스에 전달된다")
void encrypt_koreanPlainText_utf8Encoded() throws Exception {
String korean = "한글평문";
parser.parse("DJBEncrypt(plain, \"" + MODULE + "\")");
parser.addVariable("plain", korean);
parser.getValueAsObject();
verify(mockService).encrypt(eq(MODULE), anyMap(), isNull(),
eq(korean.getBytes(StandardCharsets.UTF_8)));
}
// =========================================================================
// 2. DJBDecrypt
// =========================================================================
@Test
@DisplayName("2-1. 복호화 — Base64 변수 + 상수 모듈명 → 평문 반환")
void decrypt_variableEnc_constantModule() throws Exception {
parser.parse("DJBDecrypt(enc, \"" + MODULE + "\")");
parser.addVariable("enc", ENC_BASE64);
assertEquals(PLAIN_TEXT, parser.getValueAsObject());
}
@Test
@DisplayName("2-2. 복호화 — Base64·모듈명 모두 변수")
void decrypt_bothVariables() throws Exception {
parser.parse("DJBDecrypt(enc, moduleName)");
parser.addVariable("enc", ENC_BASE64);
parser.addVariable("moduleName", MODULE);
assertEquals(PLAIN_TEXT, parser.getValueAsObject());
}
@Test
@DisplayName("2-3. 복호화 — parse 1회, 변수값 교체 반복 평가")
void decrypt_reuseParser_multipleEvaluations() throws Exception {
// identity: cipherBytes 그대로 반환 → Base64 decoding 경로 검증에 집중
when(mockService.decrypt(any(), anyMap(), isNull(), any(byte[].class)))
.thenAnswer(inv -> (byte[]) inv.getArgument(3));
parser.parse("DJBDecrypt(enc, \"" + MODULE + "\")");
String firstEnc = Base64.getEncoder().encodeToString("first".getBytes(StandardCharsets.UTF_8));
String secondEnc = Base64.getEncoder().encodeToString("second".getBytes(StandardCharsets.UTF_8));
parser.addVariable("enc", firstEnc);
assertEquals("first", parser.getValueAsObject());
parser.addVariable("enc", secondEnc);
assertEquals("second", parser.getValueAsObject());
}
// =========================================================================
// 3. 라운드트립
// =========================================================================
@Test
@DisplayName("3-1. 라운드트립 — 암호화 결과를 복호화하면 원문과 일치")
void roundTrip_encryptThenDecrypt_returnsOriginal() throws Exception {
// 암호화
parser.parse("DJBEncrypt(plain, \"" + MODULE + "\")");
parser.addVariable("plain", PLAIN_TEXT);
String encryptedBase64 = (String) parser.getValueAsObject();
// 복호화
parser.parse("DJBDecrypt(enc, \"" + MODULE + "\")");
parser.addVariable("enc", encryptedBase64);
assertEquals(PLAIN_TEXT, parser.getValueAsObject());
}
@Test
@DisplayName("3-2. 라운드트립 — 한글 평문")
void roundTrip_koreanPlainText() throws Exception {
String korean = "한글평문테스트";
when(mockService.encrypt(any(), anyMap(), isNull(), any(byte[].class)))
.thenReturn(korean.getBytes(StandardCharsets.UTF_8));
when(mockService.decrypt(any(), anyMap(), isNull(), any(byte[].class)))
.thenReturn(korean.getBytes(StandardCharsets.UTF_8));
parser.parse("DJBEncrypt(plain, \"" + MODULE + "\")");
parser.addVariable("plain", korean);
String enc = (String) parser.getValueAsObject();
parser.parse("DJBDecrypt(enc, \"" + MODULE + "\")");
parser.addVariable("enc", enc);
assertEquals(korean, parser.getValueAsObject());
}
// =========================================================================
// 4. 오류 처리
// =========================================================================
@Test
@DisplayName("4-1. 암호화 — 파라미터 1개이면 예외")
void encrypt_singleParam_throwsException() {
assertThrows(Exception.class, () -> {
parser.parse("DJBEncrypt(plain)");
parser.addVariable("plain", PLAIN_TEXT);
parser.getValueAsObject();
});
}
@Test
@DisplayName("4-2. 복호화 — 파라미터 1개이면 예외")
void decrypt_singleParam_throwsException() {
assertThrows(Exception.class, () -> {
parser.parse("DJBDecrypt(enc)");
parser.addVariable("enc", ENC_BASE64);
parser.getValueAsObject();
});
}
@Test
@DisplayName("4-3. 복호화 — 유효하지 않은 Base64 상수이면 예외")
void decrypt_invalidBase64Constant_throwsException() {
assertThrows(Exception.class, () -> {
parser.parse("DJBDecrypt(\"!!invalid!!\", \"" + MODULE + "\")");
parser.getValueAsObject();
});
}
}
@@ -0,0 +1,220 @@
package com.eactive.eai.custom.transformer.function;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Stack;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.nfunk.jep.ParseException;
import org.nfunk.jep.function.PostfixMathCommand;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.support.GenericApplicationContext;
import com.eactive.eai.common.security.CryptoModuleService;
import com.eactive.eai.common.util.ApplicationContextProvider;
@TestMethodOrder(MethodOrderer.DisplayName.class)
class DJBCryptoFunctionTest {
private static final String MODULE_NAME = "TEST_MODULE";
private static final String PLAIN_TEXT = "plaintext-value";
private static final byte[] PLAIN_BYTES = PLAIN_TEXT.getBytes(StandardCharsets.UTF_8);
private static final byte[] CIPHER_BYTES = new byte[]{0x10, 0x20, 0x30, 0x40};
private static final String ENC_BASE64 = Base64.getEncoder().encodeToString(CIPHER_BYTES);
private static GenericApplicationContext ctx;
private static CryptoModuleService mockService;
private DJBDecrypt decryt;
private DJBEncrypt encryt;
// =========================================================================
// 클래스 초기화
// =========================================================================
@BeforeAll
static void setUpClass() throws Exception {
mockService = mock(CryptoModuleService.class);
ctx = new GenericApplicationContext();
ctx.getBeanFactory().registerSingleton("cryptoModuleService", mockService);
ctx.registerBeanDefinition("applicationContextProvider",
BeanDefinitionBuilder.genericBeanDefinition(ApplicationContextProvider.class)
.getBeanDefinition());
ctx.refresh();
}
@AfterAll
static void tearDownClass() {
if (ctx != null) ctx.close();
}
@BeforeEach
void setUp() throws Exception {
reset(mockService);
when(mockService.decrypt(any(), anyMap(), isNull(), any(byte[].class))).thenReturn(PLAIN_BYTES);
when(mockService.encrypt(any(), anyMap(), isNull(), any(byte[].class))).thenReturn(CIPHER_BYTES);
decryt = new DJBDecrypt();
encryt = new DJBEncrypt();
}
// =========================================================================
// 1. DJBErpDecryt
// =========================================================================
@Test
@DisplayName("1-1. 정상 복호화: (encBase64, moduleName) → 평문이 스택에 push된다")
void decryt_normalCase_pushesPlainText() throws Exception {
Stack<Object> stack = buildStack(ENC_BASE64, MODULE_NAME);
setParamCount(decryt, 2);
decryt.run(stack);
assertEquals(PLAIN_TEXT, stack.pop());
assertTrue(stack.isEmpty(), "결과 push 후 스택에 잔여 항목이 없어야 한다");
verify(mockService).decrypt(eq(MODULE_NAME), anyMap(), isNull(), any(byte[].class));
}
@Test
@DisplayName("1-2. 파라미터 수가 2가 아니면 ParseException")
void decryt_wrongParamCount_throwsParseException() throws Exception {
Stack<Object> stack = buildStack(ENC_BASE64, MODULE_NAME);
setParamCount(decryt, 3);
assertThrows(ParseException.class, () -> decryt.run(stack));
}
@Test
@DisplayName("1-3. 유효하지 않은 Base64 입력 → ParseException")
void decryt_invalidBase64_throwsParseException() throws Exception {
Stack<Object> stack = buildStack("not-valid-base64!!!", MODULE_NAME);
setParamCount(decryt, 2);
assertThrows(ParseException.class, () -> decryt.run(stack));
}
@Test
@DisplayName("1-4. 암호화 서비스 예외 → 'DJBErpDecryt 복호화 실패' ParseException으로 래핑")
void decryt_serviceThrows_wrapsInParseException() throws Exception {
when(mockService.decrypt(any(), anyMap(), isNull(), any(byte[].class)))
.thenThrow(new RuntimeException("모듈 오류"));
Stack<Object> stack = buildStack(ENC_BASE64, MODULE_NAME);
setParamCount(decryt, 2);
ParseException ex = assertThrows(ParseException.class, () -> decryt.run(stack));
assertTrue(ex.getMessage().contains("DJBErpDecryt 복호화 실패"));
}
@Test
@DisplayName("1-5. moduleName이 CryptoModuleService에 그대로 전달된다")
void decryt_moduleNamePassedToService() throws Exception {
String customModule = "CUSTOM_AES_MODULE";
Stack<Object> stack = buildStack(ENC_BASE64, customModule);
setParamCount(decryt, 2);
decryt.run(stack);
verify(mockService).decrypt(eq(customModule), anyMap(), isNull(), any(byte[].class));
}
// =========================================================================
// 2. DJBErpEncryt
// =========================================================================
@Test
@DisplayName("2-1. 정상 암호화: (plainText, moduleName) → Base64가 스택에 push된다")
void encryt_normalCase_pushesBase64() throws Exception {
Stack<Object> stack = buildStack(PLAIN_TEXT, MODULE_NAME);
setParamCount(encryt, 2);
encryt.run(stack);
assertEquals(ENC_BASE64, stack.pop());
assertTrue(stack.isEmpty(), "결과 push 후 스택에 잔여 항목이 없어야 한다");
verify(mockService).encrypt(eq(MODULE_NAME), anyMap(), isNull(), any(byte[].class));
}
@Test
@DisplayName("2-2. 파라미터 수가 2가 아니면 ParseException")
void encryt_wrongParamCount_throwsParseException() throws Exception {
Stack<Object> stack = buildStack(PLAIN_TEXT, MODULE_NAME);
setParamCount(encryt, 3);
assertThrows(ParseException.class, () -> encryt.run(stack));
}
@Test
@DisplayName("2-3. 암호화 서비스 예외 → 'DJBErpEncryt 암호화 실패' ParseException으로 래핑")
void encryt_serviceThrows_wrapsInParseException() throws Exception {
when(mockService.encrypt(any(), anyMap(), isNull(), any(byte[].class)))
.thenThrow(new RuntimeException("모듈 오류"));
Stack<Object> stack = buildStack(PLAIN_TEXT, MODULE_NAME);
setParamCount(encryt, 2);
ParseException ex = assertThrows(ParseException.class, () -> encryt.run(stack));
assertTrue(ex.getMessage().contains("DJBErpEncryt 암호화 실패"));
}
@Test
@DisplayName("2-4. moduleName이 CryptoModuleService에 그대로 전달된다")
void encryt_moduleNamePassedToService() throws Exception {
String customModule = "CUSTOM_AES_MODULE";
Stack<Object> stack = buildStack(PLAIN_TEXT, customModule);
setParamCount(encryt, 2);
encryt.run(stack);
verify(mockService).encrypt(eq(customModule), anyMap(), isNull(), any(byte[].class));
}
@Test
@DisplayName("2-5. plainText가 UTF-8 바이트로 변환되어 서비스에 전달된다")
void encryt_plainTextEncodedAsUtf8() throws Exception {
String korean = "한글평문";
Stack<Object> stack = buildStack(korean, MODULE_NAME);
setParamCount(encryt, 2);
encryt.run(stack);
verify(mockService).encrypt(eq(MODULE_NAME), anyMap(), isNull(),
eq(korean.getBytes(StandardCharsets.UTF_8)));
}
// =========================================================================
// 헬퍼
// =========================================================================
@SuppressWarnings({"rawtypes", "unchecked"})
private Stack<Object> buildStack(Object... params) {
Stack stack = new Stack();
for (Object p : params) {
stack.push(p);
}
return stack;
}
private void setParamCount(PostfixMathCommand cmd, int count) throws Exception {
Field field = PostfixMathCommand.class.getDeclaredField("curNumberOfParameters");
field.setAccessible(true);
field.set(cmd, count);
}
}