diff --git a/build.gradle b/build.gradle index 7acaa39..f1d0b88 100644 --- a/build.gradle +++ b/build.gradle @@ -65,6 +65,8 @@ dependencies { api 'io.github.resilience4j:resilience4j-micrometer:1.7.1' api 'io.micrometer:micrometer-core:1.5.17' api 'io.micrometer:micrometer-registry-prometheus:1.5.17' + + implementation "com.google.code.gson:gson:2.3.1" //api "com.eactive:mina-core-1.0.10-custom:1.0:custom@jar" api ("org.apache.mina:mina-filter-ssl:1.0.10") { diff --git a/settings.gradle b/settings.gradle index 0791851..082155b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,7 +3,9 @@ rootProject.name = 'elink-online-common' include 'elink-online-core-jpa' include 'elink-online-core' include 'elink-online-transformer' +include 'elink-online-alarm' project (':elink-online-core-jpa').projectDir = new File(settingsDir, "../elink-online-core-jpa") project (':elink-online-core').projectDir = new File(settingsDir, "../elink-online-core") -project (':elink-online-transformer').projectDir = new File(settingsDir, "../elink-online-transformer") \ No newline at end of file +project (':elink-online-transformer').projectDir = new File(settingsDir, "../elink-online-transformer") +project (':elink-online-alarm').projectDir = new File(settingsDir, "../elink-online-alarm") \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/adapter/db/sql/AdapterUtils.java b/src/main/java/com/eactive/eai/adapter/db/sql/AdapterUtils.java index 28279ec..2da8689 100644 --- a/src/main/java/com/eactive/eai/adapter/db/sql/AdapterUtils.java +++ b/src/main/java/com/eactive/eai/adapter/db/sql/AdapterUtils.java @@ -14,8 +14,8 @@ public class AdapterUtils { map.put("Unid", "ID00000001"); String prefix = "%", surfix = "%"; - System.out.println(updateSql); - System.out.println(getUpdateQuery(updateSql, map, prefix, surfix)); + // System.out.println(updateSql); + // System.out.println(getUpdateQuery(updateSql, map, prefix, surfix)); } public static Properties getAdapterProerties(String propGroupName) { diff --git a/src/main/java/com/eactive/eai/adapter/db/sql/DBInboudSqlAdapter.java b/src/main/java/com/eactive/eai/adapter/db/sql/DBInboudSqlAdapter.java index 7a4797b..050c3ac 100644 --- a/src/main/java/com/eactive/eai/adapter/db/sql/DBInboudSqlAdapter.java +++ b/src/main/java/com/eactive/eai/adapter/db/sql/DBInboudSqlAdapter.java @@ -56,7 +56,7 @@ public class DBInboudSqlAdapter { if(isLocal != null && "true".equalsIgnoreCase(isLocal)) { isLocalTest = true; } - System.out.println("$$$ DBInboudSqlAdapter] isLocalTest = " + isLocalTest); + // System.out.println("$$$ DBInboudSqlAdapter] isLocalTest = " + isLocalTest); } public boolean execute() { diff --git a/src/main/java/com/eactive/eai/adapter/http/HttpMethodType.java b/src/main/java/com/eactive/eai/adapter/http/HttpMethodType.java index 5631af6..8d14662 100644 --- a/src/main/java/com/eactive/eai/adapter/http/HttpMethodType.java +++ b/src/main/java/com/eactive/eai/adapter/http/HttpMethodType.java @@ -5,6 +5,7 @@ public enum HttpMethodType { PUT, DELETE, GET, + PATCH, UNKNOWN; public static HttpMethodType getValue(String value) { try { diff --git a/src/main/java/com/eactive/eai/adapter/http/client/HttpClient5AdapterServiceSupport.java b/src/main/java/com/eactive/eai/adapter/http/client/HttpClient5AdapterServiceSupport.java index 80655b5..64e0e6d 100644 --- a/src/main/java/com/eactive/eai/adapter/http/client/HttpClient5AdapterServiceSupport.java +++ b/src/main/java/com/eactive/eai/adapter/http/client/HttpClient5AdapterServiceSupport.java @@ -40,6 +40,7 @@ import com.eactive.eai.adapter.AdapterManager; import com.eactive.eai.adapter.Keys; import com.eactive.eai.adapter.http.secure.HttpClient5SSLContextFactory; import com.eactive.eai.common.TransactionContextKeys; +import com.eactive.eai.common.property.PropManager; import com.eactive.eai.common.util.HttpAdapterExtraLogUtil; import com.eactive.eai.common.util.Logger; import com.eactive.eai.httpouttlsinfo.HttpOutTlsInfoVO; @@ -78,7 +79,7 @@ public abstract class HttpClient5AdapterServiceSupport implements HttpClientAdap String trustStorePassword = null; int connectionTimeout = 0; - int timeout = -1; + int timeout = 10000; // 기존값 -1 인데, 의미가 없음, -1로 설정될경우 client에서 에러남. int traceLevel = 0; long slowTranTime = 2000L; @@ -88,6 +89,13 @@ public abstract class HttpClient5AdapterServiceSupport implements HttpClientAdap if (!StringUtils.isEmpty(url2grp)) { url = url2grp; } + + boolean isDrMode = Boolean.valueOf(PropManager.getInstance().getProperty(DR_PROP_GROUP, DR_PROP_KEY, "false")); + + if (isDrMode) { + url = prop.getProperty(DR_URL); + } + method = prop.getProperty(METHOD); parameterName = prop.getProperty(PARAMETER_NAME, PARAMETER_MESSAGE); contentType = prop.getProperty(CONTENT_TYPE, ""); @@ -99,7 +107,7 @@ public abstract class HttpClient5AdapterServiceSupport implements HttpClientAdap adapterHeader = prop.getProperty(ADAPTER_HEADER, ""); String traceLevelTemp = prop.getProperty(TRACE_LEVEL, "0"); - String timeoutTemp = prop.getProperty(HTTP_TIME_OUT, "0"); + String timeoutTemp = "10000"; // 타임아웃 기준이 불명확해 운영 혼란 발생 → 인터페이스 TIMEOUT으로 단일화 useMtls = StringUtils.equalsIgnoreCase(prop.getProperty(HttpClientAdapterServiceKey.USE_MTLS),"Y"); keyStorePath = prop.getProperty(HttpClientAdapterServiceKey.KEYSTORE_PATH); @@ -418,6 +426,8 @@ public abstract class HttpClient5AdapterServiceSupport implements HttpClientAdap }; this.client = HttpClients.custom() + .disableDefaultUserAgent() + .disableContentCompression() .addRequestInterceptorLast(requestLogInterceptor) .addResponseInterceptorFirst(responseLogInterceptor) .setConnectionManager(connectionManager) @@ -507,12 +517,6 @@ public abstract class HttpClient5AdapterServiceSupport implements HttpClientAdap requestConfigBuilder.setResponseTimeout(vo.getTimeout(), TimeUnit.MILLISECONDS); } - /* - if (HTTP_VERSION_1_1.equals(vo.getHttpVersion())) { - method.addHeader("Connection", "close"); - } - */ - org.apache.hc.core5.http.HttpVersion httpVersion ; if (HTTP_VERSION_1_0.equals(vo.getHttpVersion())) { httpVersion = org.apache.hc.core5.http.HttpVersion.HTTP_1_0; diff --git a/src/main/java/com/eactive/eai/adapter/http/client/HttpClientAdapterServiceKey.java b/src/main/java/com/eactive/eai/adapter/http/client/HttpClientAdapterServiceKey.java index 0238cbc..4de44f4 100644 --- a/src/main/java/com/eactive/eai/adapter/http/client/HttpClientAdapterServiceKey.java +++ b/src/main/java/com/eactive/eai/adapter/http/client/HttpClientAdapterServiceKey.java @@ -8,6 +8,9 @@ public interface HttpClientAdapterServiceKey { public static final String HTTP_TYPE = "HTTP_TYPE"; public static final String URL = "URL"; + public static final String DR_PROP_GROUP = "DR"; + public static final String DR_PROP_KEY = "dr.enable"; + public static final String DR_URL = "URL_DR"; public static final String URL_2GRP = "URL_2GRP"; public static final String METHOD = "METHOD"; @@ -66,6 +69,7 @@ public interface HttpClientAdapterServiceKey { public static final String INBOUND_METHOD = "INBOUND_METHOD"; public static final String INBOUND_URI = "INBOUND_URI"; public static final String INBOUND_EXTURI = "INBOUND_EXTURI"; + public static final String INBOUND_EXTPARAMS = "INBOUND_EXTPARAMS"; public static final String INBOUND_HEADER = "INBOUND_HEADER"; public static final String HTTP_VERSION = "HTTP_VERSION"; diff --git a/src/main/java/com/eactive/eai/adapter/http/client/HttpClientAdapterServiceSupport.java b/src/main/java/com/eactive/eai/adapter/http/client/HttpClientAdapterServiceSupport.java index 941a92b..f72bfc9 100644 --- a/src/main/java/com/eactive/eai/adapter/http/client/HttpClientAdapterServiceSupport.java +++ b/src/main/java/com/eactive/eai/adapter/http/client/HttpClientAdapterServiceSupport.java @@ -27,6 +27,7 @@ import com.eactive.eai.adapter.http.secure.CustomHttpsSocketFactory; import com.eactive.eai.adapter.http.secure.CustomSSLProtocolSocketFactory; import com.eactive.eai.adapter.http.secure.EasySSLProtocolSocketFactory; import com.eactive.eai.adapter.http.secure.SSLContextFactory; +import com.eactive.eai.common.property.PropManager; import com.eactive.eai.common.util.Logger; import com.eactive.eai.httpouttlsinfo.HttpOutTlsInfoManager; import com.eactive.eai.httpouttlsinfo.HttpOutTlsInfoVO; @@ -83,7 +84,7 @@ public abstract class HttpClientAdapterServiceSupport implements HttpClientAdapt adapterHeader = prop.getProperty(ADAPTER_HEADER, ""); String traceLevelTemp = prop.getProperty(TRACE_LEVEL, "0"); - String timeoutTemp = prop.getProperty(HTTP_TIME_OUT); + String timeoutTemp = "10000";// 타임아웃 기준이 불명확해 운영 혼란 발생 → 인터페이스 TIMEOUT으로 단일화 useMtls = StringUtils.equalsIgnoreCase(prop.getProperty(HttpClientAdapterServiceKey.USE_MTLS), "Y"); keyStorePath = prop.getProperty(HttpClientAdapterServiceKey.KEYSTORE_PATH); @@ -100,6 +101,12 @@ public abstract class HttpClientAdapterServiceSupport implements HttpClientAdapt if (StringUtils.isNotBlank(interfaceTimeout) && NumberUtils.toInt(interfaceTimeout) > 0) { timeoutTemp = interfaceTimeout; } + + boolean isDrMode = Boolean.valueOf(PropManager.getInstance().getProperty(DR_PROP_GROUP, DR_PROP_KEY, "false")); + + if (isDrMode) { + url = prop.getProperty(DR_URL); + } url = StringUtils.trim(url); parameterName = StringUtils.trim(parameterName); @@ -116,6 +123,7 @@ public abstract class HttpClientAdapterServiceSupport implements HttpClientAdapt try { connectionTimeout = Integer.parseInt(connectionTimeoutTemp); } catch (Exception e) { + connectionTimeout = 3000; logger.debug("HttpClientAdapterSupport] connectionTimeoutTemp not int"); } try { diff --git a/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClient5AdapterServiceBody.java b/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClient5AdapterServiceBody.java index 5bfc866..2468b2f 100644 --- a/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClient5AdapterServiceBody.java +++ b/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClient5AdapterServiceBody.java @@ -5,6 +5,7 @@ import com.eactive.eai.adapter.http.client.HttpClient5AdapterServiceSupport; import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey; import com.eactive.eai.adapter.http.client.HttpClientAdapterVO; import com.eactive.eai.common.TransactionContextKeys; +import com.eactive.eai.common.message.MessageType; import com.eactive.eai.common.util.CommonLib; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.lang3.StringUtils; @@ -57,14 +58,16 @@ public class HttpClient5AdapterServiceBody extends HttpClient5AdapterServiceSupp } else if (data instanceof byte[]) { sendData = new String((byte[]) data, vo.getEncode()); } - - ObjectMapper mapper = new ObjectMapper(); - ObjectNode jsonNode = (ObjectNode) mapper.readTree(sendData); - ObjectNode headerPart = (ObjectNode) jsonNode.get("header_part"); - - if( headerPart.get("mciIntfId") != null && headerPart.get("mciIntfId").asText().trim().length() > 0 ) { - headerPart.put("eaiIntfId", ""); - sendData = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode); + + if(MessageType.JSON.equals(prop.getProperty("messageType"))) { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode jsonNode = (ObjectNode) mapper.readTree(sendData); + ObjectNode headerPart = (ObjectNode) jsonNode.get("header_part"); + + if( headerPart.get("mciIntfId") != null && headerPart.get("mciIntfId").asText().trim().length() > 0 ) { + headerPart.put("eaiIntfId", ""); + sendData = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode); + } } if ("Y".equals(vo.getUrlEncodeYn())) { diff --git a/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClient5AdapterServiceRest.java b/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClient5AdapterServiceRest.java index db918b9..2b699de 100644 --- a/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClient5AdapterServiceRest.java +++ b/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClient5AdapterServiceRest.java @@ -7,15 +7,24 @@ import java.net.ConnectException; import java.net.SocketTimeoutException; import java.net.URI; import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Base64; +import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Properties; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.eactive.eai.common.property.PropManager; +// encrypt test by jwhong +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; + import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.StopWatch; @@ -24,6 +33,7 @@ import org.apache.hc.client5.http.classic.methods.HttpDelete; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.classic.methods.HttpPut; +import org.apache.hc.client5.http.classic.methods.HttpPatch; import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase; import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; @@ -51,8 +61,6 @@ import org.springframework.security.oauth2.provider.ClientDetails; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; -import com.eactive.eai.adapter.AdapterGroupVO; -import com.eactive.eai.adapter.AdapterManager; import com.eactive.eai.adapter.AdapterPropManager; import com.eactive.eai.adapter.http.HttpMemoryLogger; import com.eactive.eai.adapter.http.HttpMethodType; @@ -60,50 +68,39 @@ import com.eactive.eai.adapter.http.client.HttpClient5AdapterServiceSupport; import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey; import com.eactive.eai.adapter.http.client.HttpClientAdapterVO; import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey; -import com.eactive.eai.adapter.http.dynamic.filter.AdapterAllowIPListFilter; -import com.eactive.eai.adapter.http.dynamic.filter.ApiAuthFilter; -import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilter; -import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilterType; -import com.eactive.eai.adapter.http.dynamic.filter.IpWhiteListFilter; -import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthFilter; +import com.eactive.eai.authserver.service.OAuth2Manager; import com.eactive.eai.common.TransactionContextKeys; import com.eactive.eai.common.authoutbound.AccessTokenManagerByDB; import com.eactive.eai.common.exception.ExceptionUtil; import com.eactive.eai.common.message.MessageType; +import com.eactive.eai.common.property.PropManager; import com.eactive.eai.common.util.CommonLib; import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; +import com.kjbank.encrypt.exchange.crypto.AES256Cipher; +import com.kjbank.encrypt.exchange.crypto.AES256GCMCipher; +import com.kjbank.encrypt.exchange.crypto.AESCipher; +import com.kjbank.encrypt.exchange.crypto.ECDHESA256Cipher; +import com.nimbusds.jwt.SignedJWT; import com.openbanking.eai.common.token.AccessTokenManager; import com.openbanking.eai.common.token.AccessTokenVO; import com.openbanking.eai.common.token.OAuth2AccessTokenVO; import edu.emory.mathcs.backport.java.util.Arrays; -// encrypt test by jwhong -import javax.crypto.Cipher; -import javax.crypto.spec.SecretKeySpec; -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import com.kjbank.encrypt.exchange.crypto.AES256Cipher; -import com.kjbank.encrypt.exchange.crypto.AESCipher; -import com.nimbusds.jwt.SignedJWT; -import com.kjbank.encrypt.exchange.crypto.AES256GCMCipher; -import com.eactive.eai.authserver.service.OAuth2Manager; - - /** * 1. 기능 : EAI HTTP OutBound 용 어댑터로 수동 시스템의 HTTP 웹 컴포넌트를 GET/POST 방식으로 호출할 수 있는 * 기능을 제공한다.
* 2. 처리 개요 :
* * - 2020-09-25: Http Header 받아서 처리할 수 있게 기능 추가
- * 3. 주의사항
+ * 3. 주의사항
* * @author : * @version : v 1.0.0 * @see : HttpClientAdapterServiceFactory.java, * HttpClientAdapterServiceSupport.java * @since : - * + * */ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupport implements HttpClientAdapterServiceKey { @@ -115,11 +112,15 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp public static final String HTTP_STATUS = "HTTP_STATUS"; public static final String HEADER_KEYS = "HEADER_KEYS"; public static final String AUTH_TOKEN = "AUTH_TOKEN"; - + public static final String HTTP_HEADER_SETTING = "HTTP_HEADER_SETTING"; + public static final String PAYLOAD_PARAM_NAME_CLIENT_ID = "client_id"; // jwhong + static final String KJB_ROOTLESS_ARRAY = "{ \"KJB_ROOTLESS_ARRAY\" : "; + private boolean useAdapterToken; private boolean encryptResponseApply; + private String httpHeaderSettingByAdapter = "{}"; /** * 1. 기능 : REST API 통신에 사용
@@ -163,9 +164,13 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp // 레이아웃 메시지 타입 REST URL 추출 시 활용. Default JSON String messageType = prop.getProperty("MESSAGE_TYPE", MessageType.JSON); String inboundMethod = tempProp.getProperty(HttpAdapterServiceKey.INBOUND_METHOD, "POST"); - - //Outbound 요청에 대한 응답 메시지의 복호화 여부 결정위해 + //String inboundToken = tempProp.getProperty(HttpAdapterServiceKey.INBOUND_TOKEN, ""); + + //Outbound 요청에 대한 응답 메시지의 복호화 여부 결정위해 jwhong encryptResponseApply = StringUtils.equalsIgnoreCase(prop.getProperty("ENCRYPT_RESPONSE_APPLY", "N"), "Y"); + + //업체 300응답시 특정 http status code 경우 에러 아닌걸로 처리. 광주은행 + String errIgnore = prop.getProperty("ERROR_IGNORE_CODE", ""); /** * @formatter:off @@ -237,12 +242,14 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp logger.debug("HttpClientAdapterServiceRest] dataObject1 = [" + dataObject + "]"); + // Path Variable 처리를 위해 Inbound에서 전달한 Variable Map + Map inboundPathVariables = (Map) tempProp.get(HttpAdapterServiceKey.INBOUND_PATH_VARIABLES); // interface 에 설정된게 우선한다. String uri = null; if (dataObject == null) { - uri = changeUrl(messageType, vo.getUrl(), restOptionData, sendData); + uri = changeUrl(messageType, vo.getUrl(), restOptionData, sendData, inboundPathVariables); } else { - uri = changeUrl(messageType, vo.getUrl(), restOptionData, dataObject); + uri = changeUrl(messageType, vo.getUrl(), restOptionData, dataObject, inboundPathVariables); } logger.debug("HttpClientAdapterServiceRest] dataObject2 = [" + dataObject + "]"); @@ -278,6 +285,9 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp case PUT: method = new HttpPut(uri); break; + case PATCH: + method = new HttpPatch(uri); + break; default: method = new HttpGet(uri); break; @@ -299,12 +309,14 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp // OAuth2AccessToken check 부분을 뒤에서 여기로 위치를 옮김, 나이스지키미 암호화 KEY를 얻기 위해서. JWHONG OAuth2AccessTokenVO accessToken = null; String auth =""; + Date currentDate = new Date(); if (useAdapterToken) { AccessTokenManagerByDB tokenManager = AccessTokenManagerByDB.getInstance(); accessToken = (OAuth2AccessTokenVO) tokenManager.getAccessTokenVO(vo.getAdapterGroupName()); // 토큰이 없거나 만료 됐으면 재발급 - if (accessToken == null || accessToken.isExpired()) { + //if (accessToken == null || accessToken.isExpired()) { + if (accessToken == null || accessToken.isExpired() || accessToken.getAccessToken() == null ) { // jwhong String oldToken = accessToken == null ? null : accessToken.getAccessToken(); accessToken = (OAuth2AccessTokenVO) tokenManager.retryAccessTokenVO(vo.getAdapterGroupName(), prop, oldToken); @@ -317,31 +329,37 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp Properties properties = AdapterPropManager.getInstance().getProperties(vo.getAdapterName()); // jwhong String encryptAlgorithm = properties.getProperty("ENCRYPT_ALGORITHM"); // jwhong - if (useAdapterToken && "AES256-NICEON".equals(encryptAlgorithm)) { - String niceToken = accessToken.getAccessToken(); - String clientId = JwtClientIdExtractor(niceToken); - long currentTime = System.currentTimeMillis(); - auth = niceToken + ":" + currentTime + ":" + clientId ; - auth = Base64.getEncoder().encodeToString(auth.getBytes("UTF-8")); - - setNiceOnAuthHeaders(method, auth); - } else { + if (useAdapterToken && "AES256-NICEON".equals(encryptAlgorithm)) { + String niceToken = accessToken.getAccessToken(); + if ( niceToken == null || niceToken == "") { + throw new Exception("NiceOn Token is empty, TOKEN failed to be issued, TOKEN = [" + niceToken + "]"); + } + String clientId = accessToken.getClientId(); // HttpClientAccessTokenServiceWithBase64NiceOn 서 넣어줌 + long currentTime = currentDate.getTime() / 1000; + auth = niceToken + ":" + currentTime + ":" + clientId ; + logger.debug("HttpClientAdapterServiceRest] NiceOn auth = [" + auth + "]"); + auth = Base64.getEncoder().encodeToString(auth.getBytes("UTF-8")); + logger.debug("HttpClientAdapterServiceRest] NiceOn Base64 encoded auth = [" + auth + "]"); + + setNiceOnAuthHeaders(method, auth); + } else { setAuthHeaders(method, accessToken); // 원래 있던 logic - } + } if (logger.isDebug()) { logger.debug("HttpClientAdapterServiceRest] SEND (" + vo.getAdapterGroupName() - + ") RequestHeader [Authorization=" + method.getHeader("Authorization") + "]"); + + ") RequestHeader [" + method.getHeader("Authorization").getName() + ": " + method.getHeader("Authorization").getValue() + "]"); } } if(!StringUtils.isBlank(authToken)) { setAuthHeaders(method, authToken); } - // 여기 까지 - + // 여기 까지 + configureHttpClient(requestConfigBuilder, vo, method); + assignFilterHeaders(method, tempProp); // OutBound PreFilter에서 설정한 Header내용 설정. switch (HttpMethodType.getValue(rmethod)) { case GET: @@ -363,9 +381,12 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp break; case PUT: case POST: + case PATCH: // assignPostBody(dataObject, contentType, vo.getEncode(), method); //assignPostBody(dataContent, contentType, vo.getEncode(), method); // jwhong commnet - assignPostBody(dataContent, contentType, vo.getEncode(), method, vo.getAdapterName(), auth); + // KJBank API 추적정보를 Header에 제공. jwhong + String inboundToken= assignRequestKJHeaders(method, prop, tempProp ); + assignPostBody(dataContent, contentType, vo.getEncode(), method, vo.getAdapterName(), auth, inboundToken, currentDate); break; default: break; @@ -376,12 +397,12 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp + method.getEntity() + "] "); } - // OAuth2AccessToken 원래 있던 위치 JWHONG + // OAuth2AccessToken 원래 있던 위치 JWHONG // 전달 header 셋팅 // Adapter 레벨 header 보다 data로 넘어온 httpHeader를 우선 적용(header명이 같다면 덮어씀) - assignRequestHeaders(method, httpHeader); - + assignRequestHeaders(method, httpHeader, prop); + int status = -1; try { @@ -423,7 +444,7 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp // encrypt algorithm type 추출 from adapter property jwhong Properties properties = AdapterPropManager.getInstance().getProperties(vo.getAdapterName()); // jwhong String encryptAlgorithm = properties.getProperty("ENCRYPT_ALGORITHM"); // jwhong - + try { if (logger.isDebug()) { logger.debug("[method getName]" + method.getMethod()); @@ -436,14 +457,14 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp //responseMessage = EntityUtils.toByteArray(response.getEntity()); // 역기서 responseMessage를 decryption 해야 하나 by jwhong - + responseMessageOri = EntityUtils.toByteArray(response.getEntity()); - System.out.println("responseMessageOri 바이트 배열 길이: " + responseMessageOri.length); - - responseMessage = doOutboundPostFilter(responseMessageOri, encryptAlgorithm, vo.getAdapterName(), accessToken); // jwhong + logger.debug("[responseMessageOri 바이트 배열 길이 ]" + responseMessageOri.length); + + responseMessage = doOutboundPostFilter(responseMessageOri, encryptAlgorithm, vo.getAdapterName(), accessToken); // jwhong // 여기까지 - - responseHeaders = response.getHeaders(); + + responseHeaders = response.getHeaders(); if (logger.isDebug()) { logger.debug("[received status]" + status); @@ -464,7 +485,7 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp * OAuth 토큰 응답 체크(Adapter properties로 설정) * 응답코드에 따라 유효한 토큰 확인(토큰 재발급 여부 확인) * API 서비스 마다 정책이 다름(보통 400대에서 체크하나 200에서도 체크할 수 있음) - * + * * TOKEN_ERROR_CODE_KEY: 응답 json error code key * __ex) $.dataHeader.resultCode * TOKEN_ERROR_CODE_VALUES: 토큰 재발급이 필요한 응답 error codes(ex: O0001,O0002,O0003) @@ -473,17 +494,20 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp * @formatter:on */ boolean needReissue = false; - + Properties responseHeaderProp = assignRelayDataToInbound(tempProp, responseHeaders); String responseString = new String(responseMessage, vo.getEncode()); - + Map map = new HashMap(); tempProp.put(HttpAdapterServiceKey.OUTBOUND_PROPERTY_MAP, map); map.put(HttpAdapterServiceKey.OUTBOUND_RESPONSE_HEADERS, responseHeaderProp); map.put(HttpAdapterServiceKey.OUTBOUND_RESPONSE_MESSAGE, responseString); map.put(HttpAdapterServiceKey.OUTBOUND_RESPONSE_STATUS, status); - if (status >= 200 && status <= 207) { + + if (isStatusInIgnore(status,errIgnore )) { + // 이경우 정상으로 처리함 + } else if (status >= 200 && status <= 207) { if (useAdapterToken && StringUtils.equals(tokenErrorHttpStatusCode, "200")) { needReissue = checkTokenRetry(responseMessage, tokenErrorCodeKey, tokenErrorCodeValues, vo.getEncode()); @@ -497,7 +521,7 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp "http receive status fail value=%d adapterName=%s.%s uri=%s method=%s response Data=%s", status, vo.getAdapterGroupName(), vo.getAdapterName(), uri, rmethod, responseString); // logger.error(errMsg); - + if (status >= 400 && status < 500) { if (useAdapterToken) { needReissue = checkTokenRetry(responseMessage, tokenErrorCodeKey, tokenErrorCodeValues, @@ -508,7 +532,7 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp throw new Exception(errMsg); } } else { - + throw new Exception(errMsg); } } @@ -592,6 +616,13 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp "RECV [" + new String(responseMessage, vo.getEncode()) + "]" + CommonLib.getDumpMessage(responseMessage)); } + + String jsonStr = new String(responseMessage, vo.getEncode()); + + if ( jsonStr.trim().startsWith("[") ) { + jsonStr = KJB_ROOTLESS_ARRAY + jsonStr + "}"; + responseMessage = jsonStr.getBytes(vo.getEncode()); + } return assignResponseHeaders(method, responseMessage, headerGroupName, vo.getEncode(), messageType, @@ -640,7 +671,7 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp if (responseHeaders == null || responseHeaders.length == 0) { return headerProp; } - + for (Header header : responseHeaders) { headerProp.put(header.getName(), header.getValue()); } @@ -650,7 +681,7 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp /** * 현재 1단계 레이아웃에만 적용되도록 구현됨. - * + * * @param method * @param responseMessage * @param headerGroupName @@ -662,7 +693,7 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp */ @SuppressWarnings("unchecked") private String assignResponseHeaders(HttpUriRequestBase method, byte[] responseMessage, String headerGroupName, - String encode, String messageType, String relayHeaderKeys, int status, Properties responseHeaderProp) throws Exception { + String encode, String messageType, String relayHeaderKeys, int status, Properties responseHeaderProp) throws Exception { if (!MessageType.JSON.equals(messageType) || StringUtils.isBlank(headerGroupName) || StringUtils.isBlank(relayHeaderKeys)) { return new String(responseMessage, encode); @@ -708,40 +739,41 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp method.setHeader("Authorization", String.format("%s %s", AccessTokenVO.BEARER_TYPE, accessToken.getAccessToken())); } - - /* nice on 나이스 지키미 용으로 생성함 + + /* nice on 나이스 지키미 용으로 생성함 * jwhong 2015-11-04 */ private void setNiceOnAuthHeaders(HttpUriRequestBase method, String auth) throws Exception { - method.setHeader("Authorization", - String.format("%s %s", AccessTokenVO.BEARER_TYPE, auth)); // 나이스지키미 format임 - method.setHeader("ProductID", "2303345072"); + method.setHeader("Authorization", + String.format("%s %s", "bearer", auth)); // 나이스지키미 format임, bearer을 소문자로 보내야함 + String productId = PropManager.getInstance().getProperty("NiceOnProperty","productId.value"); + method.setHeader("ProductID", productId); //method.setHeader("Authorization", // String.format("%s %s", AccessTokenVO.BEARER_TYPE, accessToken.getAccessToken())); } - /* nice clientid 추출을 위하여 추가한 내용임. jwhong - * - */ - private String JwtClientIdExtractor(String inboundToken) { + /* nice clientid 추출을 위하여 추가한 내용임. jwhong + * + */ + private String JwtClientIdExtractor(String inboundToken) { - String tokenClientId =""; - try { - SignedJWT signedJWT = SignedJWT.parse(inboundToken); - tokenClientId = (String) signedJWT.getJWTClaimsSet().getClaim(PAYLOAD_PARAM_NAME_CLIENT_ID); + 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 = ""; } - - System.out.println("Token Client ID: " + tokenClientId); - return tokenClientId; - } - + logger.debug("[ NICE Token Client ID ]" + tokenClientId); + return tokenClientId; + + } + private boolean checkTokenRetry(byte[] responseMessage, String tokenErrorCodeKey, String tokenErrorCodeValues, - String encode) { + String encode) { if (responseMessage == null) { return false; } @@ -770,43 +802,177 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp return false; } - private void assignRequestHeaders(HttpUriRequestBase method, Object httpHeader) { - if (httpHeader == null) { + private void assignRequestHeaders(HttpUriRequestBase method, Object httpHeader, Properties prop) { + if (httpHeader != null) { + if (httpHeader instanceof JSONObject) { + JSONObject jsonObject = (JSONObject) httpHeader; + for (Object key : jsonObject.keySet()) { + Object obj = jsonObject.get(key); + if ((obj instanceof JSONObject) || (obj instanceof JSONArray)) { + continue; + } + + method.setHeader((String) key, (String) obj); + + if (logger.isDebugEnabled()) { + logger.debug("Request Header :" + (String) key + "=[" + (String) obj + "]"); + } + + } + } + } + //전문에서 추출한 httpHeader값 외 어댑터에서 최종적으로 적용되도록, + String httpSettingJsonStr = prop.getProperty( HTTP_HEADER_SETTING ); + + if( StringUtils.isBlank(httpSettingJsonStr) ) + { + if( logger.isInfoEnabled() ) { + logger.info("HTTP_HEADER_SETTING value is not JSONObject Type, skip."); + } + return; } - - if (httpHeader instanceof JSONObject) { - JSONObject jsonObject = (JSONObject) httpHeader; - for (Object key : jsonObject.keySet()) { - Object obj = jsonObject.get(key); + + try { + JSONObject httpValues = (JSONObject) JSONValue.parse(httpSettingJsonStr); + + for (Object key : httpValues.keySet()) { + Object obj = httpValues.get(key); if ((obj instanceof JSONObject) || (obj instanceof JSONArray)) { continue; } - - method.setHeader((String) key, (String) obj); - + + method.setHeader((String) key, obj); + if (logger.isDebugEnabled()) { logger.debug("Request Header :" + (String) key + "=[" + (String) obj + "]"); } } + + }catch (Exception e) { + logger.error("HTTP_HEADER_SETTING value is not JSONObject Type, skip.", e); + } + + } + + private void assignFilterHeaders(HttpUriRequestBase method, Properties tempProp) { + try { + Properties filterHeaders = (Properties)tempProp.get("FILTERHEADER"); + if (filterHeaders != null){ + for (Entry e : filterHeaders.entrySet()) { + String key = (String) e.getKey(); + String value = (String) e.getValue(); + method.setHeader(key, value); + + if (logger.isDebugEnabled()) { + logger.debug("OutBound Filter] Request Header :" + key + "=[" + value + "]"); + } + } + } + } catch (Exception e) { + logger.error(e.getMessage()); } } + /* + * KJBank Target System으로 요청 보낼때 header에 clientId(업체정보), APIM거래추적자(UUID), 최초 요청시간, guid 추가해서 보낸다. jwhong + * token 만 return 하는것으로 수정함 + */ + private String assignRequestKJHeaders(HttpUriRequestBase method, Properties prop, Properties tempProp){ + + //weblogic 에서는 tempProp.get 이 property로 return 해어 아래처럼 수정함. ClassCastException 발생함. + //Properties inboundHeaders = (Properties) tempProp.get(HttpAdapterServiceKey.INBOUND_HEADER); + Properties inboundHeaders = null; + String authorization =""; + try { + Object headerObj = tempProp.get(HttpAdapterServiceKey.INBOUND_HEADER); + if (headerObj instanceof Properties) { //tomcat + inboundHeaders = (Properties) headerObj; + for ( String k : inboundHeaders.stringPropertyNames()) { + if(k.equalsIgnoreCase("authorization")) { + authorization = inboundHeaders.getProperty(k); + break; + } + } + } else if (headerObj instanceof String) { //weblogic + String str = (String) headerObj; + str = str.substring(1, str.length() - 1); + // 2. key=value 쌍 분리 + String[] entries = str.split(","); + // map에 담기 + Map map = new HashMap<>(); + for (String entry : entries) { + String[] kv = entry.split("=", 2); + if (kv.length == 2) { + map.put(kv[0].trim(), kv[1].trim()); + } + } + for (String k : map.keySet()) { + if (k.equalsIgnoreCase("authorization")) { + authorization = map.get(k); + break; + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + String jwtToken = ""; + + if (authorization != null && authorization.startsWith("Bearer ")) { + jwtToken = authorization.substring(7); // "Bearer " 이후의 JWT만 추출 + } + + return jwtToken; + } + + private static Map parseInboundHeader(String str) { + java.util.HashMap map = new java.util.HashMap<>(); + if (str == null || str.isEmpty()) return map; + + // 중괄호 제거 + str = str.trim(); + if (str.startsWith("{") && str.endsWith("}")) { + str = str.substring(1, str.length() - 1); + } + + // key=value 쌍 분리 + String[] pairs = str.split(","); + for (String pair : pairs) { + String[] kv = pair.split("=", 2); + if (kv.length == 2) { + map.put(kv[0].trim(), kv[1].trim()); + } + } + return map; + } + @SuppressWarnings("deprecation") - private void assignPostBody(Object eaiBody, String contentType, String charset, HttpUriRequestBase method, String adapterName, String niceAuth) { + private void assignPostBody(Object eaiBody, String contentType, String charset, HttpUriRequestBase method, String adapterName, String niceAuth, String inboundToken, Date currentDate) throws Exception { if (eaiBody == null) { return; } + + if (eaiBody instanceof JSONObject) { + JSONObject jsonObject = (JSONObject) eaiBody; + if( jsonObject.containsKey("KJB_ROOTLESS_ARRAY") ) { + eaiBody = jsonObject.get("KJB_ROOTLESS_ARRAY"); + } + } if (StringUtils.contains(contentType, "application/x-www-form-urlencoded")) { if (eaiBody instanceof JSONObject) { List params = new ArrayList<>(); JSONObject jsonObject = (JSONObject) eaiBody; + for (Object key : jsonObject.keySet()) { - //String encryptedValue = encrypt((String) jsonObject.get(key)); // encrypt by jwhong - //params.add(new BasicNameValuePair((String) key, encryptedValue )); + + if( jsonObject.get(key) instanceof String ) { params.add(new BasicNameValuePair((String) key, (String) jsonObject.get(key))); + } + } UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, StandardCharsets.UTF_8); @@ -815,8 +981,8 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp } else { ContentType contentTypeObj = ContentType.create(contentType, charset); - String eaiBodyMessage = doOutboundPreFilter(eaiBody, adapterName, niceAuth); // jwhong - StringEntity entity = new StringEntity(eaiBodyMessage, contentTypeObj); + String eaiBodyMessage = doOutboundPreFilter(eaiBody, adapterName, niceAuth, inboundToken, currentDate); // jwhong + StringEntity entity = new StringEntity(eaiBodyMessage, contentTypeObj); // 요청 본문을 StringEntity 객체로 생성 //StringEntity entity = new StringEntity(eaiBody.toString(), contentTypeObj); @@ -824,365 +990,430 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp method.setEntity(entity); } } - + // from here by jwhong - private String doOutboundPreFilter(Object eaiBody, String adapterName, String niceAuth) { - + private String doOutboundPreFilter(Object eaiBody, String adapterName, String niceAuth, String inboundToken, Date currentDate) throws Exception { + Properties properties = AdapterPropManager.getInstance().getProperties(adapterName); // jwhong - String encryptAlgorithm = properties.getProperty("ENCRYPT_ALGORITHM"); // jwhong - //String encryptBaseKeyType = properties.getProperty("ENCRYPT_BASE_TYPE"); - String encryptClientId = properties.getProperty("ENCRYPT_CLIENT_ID"); - String encryptAES256Iv = properties.getProperty("ENCRYPT_AES256_IV"); - String encryptAES256Key = properties.getProperty("ENCRYPT_AES256_KEY"); - + String encryptAlgorithm = properties.getProperty("ENCRYPT_ALGORITHM",""); // jwhong + String encryptBaseKeyType = properties.getProperty("ENCRYPT_BASE_TYPE"); + String encryptClientId = properties.getProperty("ENCRYPT_CLIENT_ID"); + String encryptAES256Iv = properties.getProperty("ENCRYPT_AES256_IV"); + String encryptAES256Key = properties.getProperty("ENCRYPT_AES256_KEY"); + String certPath = properties.getProperty("ENCRYPT_CERT_PATH"); + // outbound encrypt 는 SecretKey 또는 NICE-auth 가 암호화 key로 사용된다. + // outbound 알림결과는 SecretKey, NICE-auth, Token을 사용한다. // 참고로 inbound encrypt 에는 Token 또는 SecretKey 가 암호화 key로 사용된다. - // 여기에 NICE-auth 뭔지 파악하여 logic 추가해야 한다. - OAuth2Manager manager = OAuth2Manager.getInstance(); - ClientDetails clientDetail = manager.getClientDeatilsStore().get(encryptClientId); - String clientSecret = ""; - if ( clientDetail != null ) { // not null 이라는 것은 APIM Oauth Server에 등록된 client ID 이다. - // 이건 KJBank로 Outbound 나가는 것임 - clientSecret = clientDetail.getClientSecret(); - } else { // 그럼 업체로 Outbound 나가는것은, 업체에서 사용하는 secretkey를 사용한다. - clientSecret = encryptClientId; - } - - // Nice-auth , token 값을 substring 해서 사용한다. 나이스 지키미는 adapter token에서 추출된 token을 사용한다. - if (useAdapterToken && "AES256-NICEON".equals(encryptAlgorithm)) { - clientSecret = niceAuth; - } - - // 여기서 SECRETY인지 nice-auth 인지 check 하여 clientSecret 값을 정하는 logic 추가하여 넘겨야한다. - - String responseMessage = doOutboundPreEncrypt(eaiBody, encryptAlgorithm, clientSecret, encryptAES256Iv, encryptAES256Key); + // 여기에 NICE-auth logic 추가함 . + String clientSecret = ""; + if ("TOKEN".equalsIgnoreCase(encryptBaseKeyType)) { + clientSecret = inboundToken; + } else if ( "SECRETKEY".equalsIgnoreCase(encryptBaseKeyType)) { + OAuth2Manager manager = OAuth2Manager.getInstance(); + ClientDetails clientDetail = manager.getClientDeatilsStore().get(encryptClientId); + if ( clientDetail != null ) { // not null 이라는 것은 APIM Oauth Server에 등록된 client ID 이다. + // 업체가 우리 OAuth 를 사용하는 경우임 + clientSecret = clientDetail.getClientSecret(); + } else { // 이경우는 우리 OAuth를 사용안하는 경우임, 업체에서 사용하는 secretkey를 사용한다. + clientSecret = encryptClientId; + } + } + + // Nice-auth , token 값을 substring 해서 사용한다. 나이스 지키미는 adapter token에서 추출된 token을 사용한다. + if (useAdapterToken && "AES256-NICEON".equals(encryptAlgorithm)) { + clientSecret = niceAuth; + } + + // 여기서 SECRETY인지 nice-auth 인지 check 하여 clientSecret 값을 정하는 logic 추가하여 넘겨야한다. + + String responseMessage = doOutboundPreEncrypt(eaiBody, encryptAlgorithm, clientSecret, encryptAES256Iv, encryptAES256Key, certPath, currentDate); + logger.info("outbound pre encrypte value is :"+responseMessage); return responseMessage; - + } - private String doOutboundPreEncrypt(Object eaiBody, String encryptAlgorithm, String clientSecretKey, String encryptAES256Iv, String encryptAES256Key ) { - + private String doOutboundPreEncrypt(Object eaiBody, String encryptAlgorithm, String clientSecretKey, String encryptAES256Iv, String encryptAES256Key, String certPath, Date currentDate) throws Exception { + String encryptedMessage = ""; String encryptedJsonKey = ""; - + encryptedJsonKey = getJsonKey(encryptAlgorithm); - + switch (encryptAlgorithm) { - case "AES": - encryptedMessage = encrypt(eaiBody.toString()); // encrypt by jwhong - break; - case "AES128-TOSS": - try { - String key = clientSecretKey.substring(22,38); - encryptedMessage = AESCipher.encrypt(eaiBody.toString(), key); - } catch (Exception e) { - e.printStackTrace(); - logger.error("HttpClientAdapterServiceRest] AES128 Encryption error=" + e.getMessage()); - } - break; - case "AES128-TOGETHER": - try { - String key = clientSecretKey.substring(44,60); - encryptedMessage = AESCipher.encrypt(eaiBody.toString(), key); - } catch (Exception e) { - e.printStackTrace(); - logger.error("HttpClientAdapterServiceRest] AES128 Encryption error=" + e.getMessage()); - } - break; - case "AES256": - try { - String key = clientSecretKey.substring(10,42); - encryptedMessage = AES256Cipher.encrypt(eaiBody.toString(), key); - } catch (Exception e) { - e.printStackTrace(); - logger.error("HttpClientAdapterServiceRest] AES256 Encryption error=" + e.getMessage()); - } - break; - case "AES256-KAKAO": - try { - encryptedMessage = AES256Cipher.encrypt(eaiBody.toString(), encryptAES256Iv, encryptAES256Key); - } catch (Exception e) { - e.printStackTrace(); - logger.error("HttpClientAdapterServiceRest] AES256 Encryption error=" + e.getMessage()); - } - break; - case "AES256-TOSS": - try { - encryptedMessage = AES256Cipher.encrypt(eaiBody.toString(), encryptAES256Iv, encryptAES256Key); - } catch (Exception e) { - e.printStackTrace(); - logger.error("HttpClientAdapterServiceRest] AES256 Encryption error=" + e.getMessage()); - } - break; - case "AES256-NICEON": - try { - String key = clientSecretKey.substring(10,42); - encryptedMessage = AES256Cipher.encrypt(eaiBody.toString(), key); - } 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(); - - encryptedMessage = cipher.encrypt(eaiBody.toString(), aad); - } catch (Exception e) { - e.printStackTrace(); - logger.error("HttpClientAdapterServiceRest] AES256GCM Encryption error=" + e.getMessage()); - } - break; - default: - encryptedMessage = eaiBody.toString(); - return encryptedMessage; + case "AES": + encryptedMessage = encrypt(eaiBody.toString()); // encrypt by jwhong + break; + case "AES128": + case "AES128-TOSS": + try { + String key = clientSecretKey.substring(22,38); + encryptedMessage = AESCipher.encrypt(eaiBody.toString(), key); + } catch (Exception e) { + e.printStackTrace(); + logger.error("HttpClientAdapterServiceRest] AES128 Encryption error=" + e.getMessage()); + throw new Exception("[HttpClient5AdapterServiceRest] Pre Encrypt Error : Encrypted Error, AES128 Key Invalid"); + } + break; + case "AES128-TOGETHER": + try { + String key = clientSecretKey.substring(44,60); + encryptedMessage = AESCipher.encrypt(eaiBody.toString(), key); + } catch (Exception e) { + e.printStackTrace(); + logger.error("HttpClientAdapterServiceRest] AES128 Encryption error=" + e.getMessage()); + throw new Exception("[HttpClient5AdapterServiceRest] Pre Encrypt Error : Encrypted Error, AES128 Key Invalid"); + } + break; + case "AES256": + try { + String key = clientSecretKey.substring(10,42); + encryptedMessage = AES256Cipher.encrypt(eaiBody.toString(), key); + } catch (Exception e) { + e.printStackTrace(); + logger.error("HttpClientAdapterServiceRest] AES256 Encryption error=" + e.getMessage()); + throw new Exception("[HttpClient5AdapterServiceRest] Pre Encrypt Error : Encrypted Error, AES256 Key Invalid"); + } + break; + case "AES256-KAKAO": + try { + encryptedMessage = AES256Cipher.encrypt(eaiBody.toString(), encryptAES256Iv, encryptAES256Key); + } catch (Exception e) { + e.printStackTrace(); + logger.error("HttpClientAdapterServiceRest] AES256 Encryption error=" + e.getMessage()); + throw new Exception("[HttpClient5AdapterServiceRest] Pre Encrypt Error : Encrypted Error, AES256 Key Invalid"); + } + break; + case "AES256-TOSS": + try { + encryptedMessage = AES256Cipher.encrypt(eaiBody.toString(), encryptAES256Iv, encryptAES256Key); + } catch (Exception e) { + e.printStackTrace(); + logger.error("HttpClientAdapterServiceRest] AES256 Encryption error=" + e.getMessage()); + throw new Exception("[HttpClient5AdapterServiceRest] Pre Encrypt Error : Encrypted Error, AES256 Key Invalid"); + } + break; + case "AES256-NICEON": + try { + String key = clientSecretKey.substring(10,42); + logger.debug("HttpClientAdapterServiceRest] NICE ON AES256 Encryption key is :+="+key); + encryptedMessage = AES256Cipher.encrypt(eaiBody.toString(), key); + //encryptedMessage = ExchangeCrypto.encodedData(eaiStringBody, clientSecretKey); + } catch (Exception e) { + e.printStackTrace(); + logger.error("HttpClientAdapterServiceRest] AES256 Encryption error=" + e.getMessage()); + throw new Exception("[HttpClient5AdapterServiceRest] Pre Encrypt Error : Encrypted Error, AES256 Key Invalid"); + } + break; + case "AES256GCM": + try { + byte[] key = AES256GCMCipher.generateKey(); + AES256GCMCipher cipher = new AES256GCMCipher(key); + byte[] aad = "metadata".getBytes(); + + encryptedMessage = cipher.encrypt(eaiBody.toString(), aad); + } catch (Exception e) { + e.printStackTrace(); + logger.error("HttpClientAdapterServiceRest] AES256GCM Encryption error=" + e.getMessage()); + throw new Exception("[HttpClient5AdapterServiceRest] Pre Encrypt Error : Encrypted Error, AES256GCM Key Invalid"); + } + break; + case "ECDHESA256": + try { + ECDHESA256Cipher cipher = new ECDHESA256Cipher(); + + encryptedMessage = cipher.encrypt(eaiBody.toString()); + // System.out.println("Encrypted JWE: " + encryptedMessage); + + String decrypted = cipher.decrypt(encryptedMessage); + // System.out.println("Decrypted Payload: " + decrypted); + + //아래 인증서로 테스트 + ECDHESA256Cipher cipherCert = new ECDHESA256Cipher(certPath); + encryptedMessage = cipherCert.encrypt(eaiBody.toString()); + + decrypted = cipherCert.decrypt(encryptedMessage); + + } catch (Exception e) { + e.printStackTrace(); + logger.error("HttpClientAdapterServiceRest] AES256GCM Encryption error=" + e.getMessage()); + throw new Exception("[HttpClient5AdapterServiceRest] Pre Encrypt Error : Encrypted Error, ECDHESA256 Key Invalid"); + } + break; + default: + encryptedMessage = eaiBody.toString(); + return encryptedMessage; //break; } - - Map map = new HashMap<>(); - map.put(encryptedJsonKey, encryptedMessage); - JSONObject json = new JSONObject(); - json.putAll(map); - return json.toJSONString(); + + if (encryptAlgorithm.equals("AES256-NICEON")) { + String goodsCls = PropManager.getInstance().getProperty("NiceOnProperty","goods.cls.value"); + Map map = new HashMap<>(); + SimpleDateFormat sdfDateTime =new SimpleDateFormat("yyyyMMddHHmmss"); + map.put("req_dtm", sdfDateTime.format(currentDate)); + map.put("goods_cls", goodsCls); + map.put(encryptedJsonKey, encryptedMessage); + JSONObject dataBody = new JSONObject(); + dataBody.putAll(map); + + JSONObject json = new JSONObject(); + json.put("dataBody", dataBody); + return json.toJSONString(); + } else { + Map map = new HashMap<>(); + map.put(encryptedJsonKey, encryptedMessage); + JSONObject json = new JSONObject(); + json.putAll(map); + return json.toJSONString(); + } + //return encryptedMessage; } - - + + private byte[] doOutboundPostFilter(byte[] eaiBody, String decryptAlgorithm, String adapterName, OAuth2AccessTokenVO niceAccessToken ) { - + if ( !encryptResponseApply) { return eaiBody; } - + Properties properties = AdapterPropManager.getInstance().getProperties(adapterName); // jwhong //String encryptAlgorithm = properties.getProperty("ENCRYPT_ALGORITHM"); // jwhong - //String encryptBaseKeyType = properties.getProperty("ENCRYPT_BASE_TYPE"); - String encryptClientId = properties.getProperty("ENCRYPT_CLIENT_ID"); - String encryptAES256Iv = properties.getProperty("ENCRYPT_AES256_IV"); - String encryptAES256Key = properties.getProperty("ENCRYPT_AES256_KEY"); - + //String encryptBaseKeyType = properties.getProperty("ENCRYPT_BASE_TYPE"); + String encryptClientId = properties.getProperty("ENCRYPT_CLIENT_ID"); + String encryptAES256Iv = properties.getProperty("ENCRYPT_AES256_IV"); + String encryptAES256Key = properties.getProperty("ENCRYPT_AES256_KEY"); + // outbound encrypt 는 SecretKey 또는 NICE-auth 가 암호화 key로 사용된다. - OAuth2Manager manager = OAuth2Manager.getInstance(); - ClientDetails clientDetail = manager.getClientDeatilsStore().get(encryptClientId); - String clientSecret = ""; - if ( clientDetail != null ) { - clientSecret = clientDetail.getClientSecret(); - } else { - clientSecret = encryptClientId; - } - - // Nice-auth , token 값을 substring 해서 사용한다. 나이스 지키미는 adapter token에서 추출된 token을 사용한다. - if (useAdapterToken && "AES256-NICEON".equals(decryptAlgorithm)) { - clientSecret = niceAccessToken.getAccessToken(); - } - + OAuth2Manager manager = OAuth2Manager.getInstance(); + ClientDetails clientDetail = manager.getClientDeatilsStore().get(encryptClientId); + String clientSecret = ""; + if ( clientDetail != null ) { + clientSecret = clientDetail.getClientSecret(); + } else { + clientSecret = encryptClientId; + } + + // Nice-auth , token 값을 substring 해서 사용한다. 나이스 지키미는 adapter token에서 추출된 token을 사용한다. + if (useAdapterToken && "AES256-NICEON".equals(decryptAlgorithm)) { + clientSecret = niceAccessToken.getAccessToken(); + } + byte[] resPostMessage = doOutboundPostDecrypt(eaiBody, decryptAlgorithm, clientSecret, encryptAES256Iv, encryptAES256Key); return resPostMessage; } - + private byte[] doOutboundPostDecrypt(byte[] eaiBody, String decryptAlgorithm, String clientSecretKey, String encryptAES256Iv, String encryptAES256Key ) { - + byte[] decryptedMessage = null; String eaiStringBody = new String(eaiBody, StandardCharsets.UTF_8); - - eaiStringBody = extractBodyMsg(decryptAlgorithm, eaiStringBody); - + + try { + eaiStringBody = extractBodyMsg(decryptAlgorithm, eaiStringBody); + } catch (ParseException e) { + logger.debug("[JSON 파싱 오류 발생 : ]" +e.getMessage()); + return eaiBody; + } + //test source - System.out.println("eaiBody 바이트 배열 길이: " + eaiBody.length); - System.out.println("Base64 문자열: " + eaiStringBody); - System.out.println("Base64 문자열 길이: " + eaiStringBody.length()); - System.out.println("Base64 문자열 끝: " + eaiStringBody.substring(eaiStringBody.length() - 10)); + /* + logger.debug("eaiBody 바이트 배열 길이: " + eaiBody.length); + 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); - System.out.println("디코딩 성공, 길이: " + decoded.length); + byte[] decoded = Base64.getDecoder().decode(eaiStringBody); + logger.debug("[디코딩 성공, 길이: ]" + decoded.length); } catch (IllegalArgumentException e) { - System.out.println("Base64 디코딩 실패: " + e.getMessage()); + logger.debug("[Base64 디코딩 실패: ]" + e.getMessage()); } - // end test source - + // end test source + switch (decryptAlgorithm) { - case "AES": - decryptedMessage = decrypt(eaiBody); // encrypt by jwhong - break; - case "AES128-TOSS": - try { - String key128 = clientSecretKey.substring(22,38); - 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); - 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, encryptAES256Iv, encryptAES256Key); - decryptedMessage = decryptedStrMessage.getBytes(StandardCharsets.UTF_8); - } catch (Exception e) { - e.printStackTrace(); - logger.error("HttpClientAdapterServiceRest] AES256 Encryption error=" + e.getMessage()); - } - break; - case "AES256-TOSS": - try { - String decryptedStrMessage = AES256Cipher.decrypt(eaiStringBody, encryptAES256Iv, encryptAES256Key); - decryptedMessage = decryptedStrMessage.getBytes(StandardCharsets.UTF_8); - } catch (Exception e) { - e.printStackTrace(); - logger.error("HttpClientAdapterServiceRest] AES256 Encryption error=" + e.getMessage()); - } - break; - case "AES256-NICEON": - 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 "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] AES256 Decryption error=" + e.getMessage()); - } - break; - default: - try { - decryptedMessage = Arrays.copyOf(eaiBody, eaiBody.length); - } catch (Exception e) { - e.printStackTrace(); - logger.error("HttpClientAdapterServiceRest] doOutboundPostFilter Array copy error=" + e.getMessage()); - } - break; + case "AES": + decryptedMessage = decrypt(eaiBody); // encrypt by jwhong + break; + case "AES128": + case "AES128-TOSS": + try { + String key128 = clientSecretKey.substring(22,38); + 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); + 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, encryptAES256Iv, encryptAES256Key); + decryptedMessage = decryptedStrMessage.getBytes(StandardCharsets.UTF_8); + } catch (Exception e) { + e.printStackTrace(); + logger.error("HttpClientAdapterServiceRest] AES256 Encryption error=" + e.getMessage()); + } + break; + case "AES256-TOSS": + try { + String decryptedStrMessage = AES256Cipher.decrypt(eaiStringBody, encryptAES256Iv, encryptAES256Key); + decryptedMessage = decryptedStrMessage.getBytes(StandardCharsets.UTF_8); + } catch (Exception e) { + e.printStackTrace(); + logger.error("HttpClientAdapterServiceRest] AES256 Encryption error=" + e.getMessage()); + } + break; + case "AES256-NICEON": + 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 "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] AES256 Decryption error=" + e.getMessage()); + } + break; + default: + try { + decryptedMessage = Arrays.copyOf(eaiBody, eaiBody.length); + } catch (Exception e) { + e.printStackTrace(); + logger.error("HttpClientAdapterServiceRest] doOutboundPostFilter Array copy error=" + e.getMessage()); + } + break; } - - return decryptedMessage; + + return decryptedMessage; } - - - private String extractBodyMsg(String decryptAlgorithm, String eaiStringBody) { + + + private String extractBodyMsg(String decryptAlgorithm, String eaiStringBody) throws ParseException { 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()); + decryptedBodyMessage = (String) jsonObject.get(decryptedJsonKey); + } catch (ParseException e) { + e.printStackTrace(); + logger.error("HttpClient5AdapterServiceRest] extractBodyMsg error : " + e.getMessage()); + throw e; } return decryptedBodyMessage; - + } - + private String getJsonKey(String Algorithm) { - + String jsonKey = ""; - + switch (Algorithm) { - 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 = "preScreeningRequest"; - break; - case "AES256GCM": - break; - default: - break; + 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; } // by jwhong private String encrypt(String plainText) { - try { - SecretKeySpec key = new SecretKeySpec("1234567890123456".getBytes(), "AES"); - Cipher cipher = Cipher.getInstance("AES"); - cipher.init(Cipher.ENCRYPT_MODE, key); - byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); - return Base64.getEncoder().encodeToString(encrypted); - } catch (Exception e) { - // 예외 로그 출력 또는 사용자 정의 처리 - e.printStackTrace(); - return null; // 또는 에러 메시지 반환 - } + try { + SecretKeySpec key = new SecretKeySpec("1234567890123456".getBytes(), "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.ENCRYPT_MODE, key); + byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(encrypted); + } catch (Exception e) { + // 예외 로그 출력 또는 사용자 정의 처리 + e.printStackTrace(); + return null; // 또는 에러 메시지 반환 + } } - - - public static byte[] decrypt(byte[] encryptedBytes) { - try { - // byte[] --> Base64 문자열로 변환 - String encryptedText = new String(encryptedBytes, StandardCharsets.UTF_8).trim(); - // 암호화에 사용한 키와 동일한 키 사용 - SecretKeySpec key = new SecretKeySpec("1234567890123456".getBytes(), "AES"); - // 암호화와 동일한 알고리즘 설정 - Cipher cipher = Cipher.getInstance("AES"); - cipher.init(Cipher.DECRYPT_MODE, key); - // Base64로 인코딩된 문자열을 디코딩 - byte[] decodedBytes = Base64.getDecoder().decode(encryptedText); + public static byte[] decrypt(byte[] encryptedBytes) { + try { + // byte[] --> Base64 문자열로 변환 + String encryptedText = new String(encryptedBytes, StandardCharsets.UTF_8).trim(); + // 암호화에 사용한 키와 동일한 키 사용 + SecretKeySpec key = new SecretKeySpec("1234567890123456".getBytes(), "AES"); - // 복호화 수행 - byte[] decryptedBytes = cipher.doFinal(decodedBytes); + // 암호화와 동일한 알고리즘 설정 + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.DECRYPT_MODE, key); - // UTF-8 문자열로 변환하여 반환 - //return new String(decryptedBytes, StandardCharsets.UTF_8); - //복호화된 바이트 배열 반환 - return decryptedBytes; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } + // Base64로 인코딩된 문자열을 디코딩 + byte[] decodedBytes = Base64.getDecoder().decode(encryptedText); + + // 복호화 수행 + byte[] decryptedBytes = cipher.doFinal(decodedBytes); + + // UTF-8 문자열로 변환하여 반환 + //return new String(decryptedBytes, StandardCharsets.UTF_8); + //복호화된 바이트 배열 반환 + return decryptedBytes; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } private HashMap getParameters(Object message) throws Exception { @@ -1214,7 +1445,7 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp return result; } - + public String getStringValue(Object obj) { if (obj == null) { return null; @@ -1262,7 +1493,7 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp } @SuppressWarnings("deprecation") - private String changeUrl(String messageType, String url, String restOption, Object sendData) { + private String changeUrl(String messageType, String url, String restOption, Object sendData, Map inboundPathVariables) { if ((MessageType.JSON.equals(messageType) || MessageType.XML.equals(messageType))) { try { if (StringUtils.isBlank(restOption)) { @@ -1294,9 +1525,17 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp } for (Object tempObject : uriVariables) { String urlVaribleId = (String) tempObject; - String uriVariable = (String) jsonObject.get(urlVaribleId); + String uriVariable = null; + if( jsonObject != null ) { + uriVariable = (String) jsonObject.get(urlVaribleId); + jsonObject.remove(urlVaribleId); + } + + if (StringUtils.isBlank(uriVariable) && inboundPathVariables.containsKey(urlVaribleId)) { + uriVariable = inboundPathVariables.get(urlVaribleId); + } urlVariableList.add(uriVariable); - jsonObject.remove(urlVaribleId); + } } else if (MessageType.XML.equals(messageType)) { Document doc; @@ -1352,4 +1591,31 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp logger.debug("HttpClientAdapterServiceRest] after concatenate url=[" + targetUrl + "] "); return targetUrl; } + + + private boolean isStatusInIgnore(int status, String errIgnore) { + if (errIgnore == null || errIgnore.isEmpty()) return false; + + String[] tokens = errIgnore.split(","); + for (String token : tokens) { + token = token.trim(); + if (token.contains("-")) { + // 범위 처리 + String[] range = token.split("-"); + int start = Integer.parseInt(range[0].trim()); + int end = Integer.parseInt(range[1].trim()); + if (status >= start && status <= end) { + return true; + } + } else { + // 단일 숫자 처리 + int code = Integer.parseInt(token); + if (status == code) { + return true; + } + } + } + return false; + } + } diff --git a/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClientAdapterServiceNoop.java b/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClientAdapterServiceNoop.java new file mode 100644 index 0000000..73ac941 --- /dev/null +++ b/src/main/java/com/eactive/eai/adapter/http/client/impl/HttpClientAdapterServiceNoop.java @@ -0,0 +1,21 @@ +package com.eactive.eai.adapter.http.client.impl; + +import com.eactive.eai.adapter.http.client.HttpClientAdapterService; +import com.eactive.eai.httpouttlsinfo.HttpOutTlsInfoVO; + +import java.util.Properties; + +public class HttpClientAdapterServiceNoop implements HttpClientAdapterService { + public Object execute(Properties prop, Object data, Properties tempProp) throws Exception { + return null; + } + + @Override + public void close() { + } + + @Override + public void init(String adapterName, boolean useMtls, HttpOutTlsInfoVO mtlsInfo, int maxTotalConnections, int maxHostConnections) { + } +} + diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpAdapterServiceKey.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpAdapterServiceKey.java index a989dfd..b662e26 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpAdapterServiceKey.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpAdapterServiceKey.java @@ -1,7 +1,7 @@ package com.eactive.eai.adapter.http.dynamic; public interface HttpAdapterServiceKey { - // URL 파리미터 DEFAULT 이름 + // URL 파리미터 DEFAULT 이름 static final String PARAMETER_MESSAGE = "_message_"; // URL 파리미터 이름 @@ -43,6 +43,7 @@ public interface HttpAdapterServiceKey { static final String INBOUND_METHOD = "INBOUND_METHOD"; static final String INBOUND_URI = "INBOUND_URI"; static final String INBOUND_EXTURI = "INBOUND_EXTURI"; + static final String INBOUND_EXTPARAMS = "INBOUND_EXTPARAMS"; static final String INBOUND_HEADER = "INBOUND_HEADER"; static final String INBOUND_QUERY_STRING = "INBOUND_QUERY_STRING"; static final String INBOUND_REWRITE_PATH = "INBOUND_REWRITE_PATH"; @@ -73,10 +74,14 @@ public interface HttpAdapterServiceKey { static final String ENC_PATHS = "ENC_PATHS"; static final String ENCRYPT_ALGORITHM = "ENCRYPT_ALGORITHM"; //jwhong - static final String INBOUND_TOKEN = "authorization"; // jwhong + static final String INBOUND_TOKEN = "AUTHORIZATION"; // jwhong static final String ENCRYPT_BASE_TYPE = "ENCRYPT_BASE_TYPE"; // jwhong static final String ENCRYPT_AES256_IV = "ENCRYPT_AES256_IV"; // jwhong static final String ENCRYPT_AES256_KEY = "ENCRYPT_AES256_KEY"; // jwhong + static final String INBOUND_REQUESTED_TIME = "INBOUND_REQUESTED_TIME"; // jwhong + static final String GUID = "GUID"; // jwhong + static final String API_SERVICE_CODE = "API_SERVICE_CODE"; // jwhong + static final String OUT_ADAPTER_GROUP_NAME = "OUT_ADAPTER_GROUP_NAME"; // jwhong //응답 처리 용 표준 전문 오브젝트 static final String STANDARD_MESSAGE_OBJECT = "STANDARD_MESSAGE_OBJECT"; diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpAdapterServiceSupport.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpAdapterServiceSupport.java index 0077de4..8be66b3 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpAdapterServiceSupport.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpAdapterServiceSupport.java @@ -9,14 +9,11 @@ import org.apache.commons.lang3.StringUtils; 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.RequestDispatcher; import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey; 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.HttpAdapterFilterFactoryKjb; import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilterType; -import com.eactive.eai.data.entity.onl.adapter.AdapterProp; public abstract class HttpAdapterServiceSupport implements HttpAdapterService, HttpAdapterServiceKey { protected long slowTranTime = 2000L; @@ -65,7 +62,7 @@ public abstract class HttpAdapterServiceSupport implements HttpAdapterService, H if (!"HTC".equals(group.getType())) { String allowIp = prop.getProperty(ALLOW_IP,""); if (StringUtils.isNotBlank(allowIp)) { - HttpAdapterFilter adapterFilter = HttpAdapterFilterFactory.createFilter(HttpAdapterFilterType.ADAPTERALLOWIPLISTFILTER.toString()); + HttpAdapterFilter adapterFilter = HttpAdapterFilterFactoryKjb.createFilter(HttpAdapterFilterType.ADAPTERALLOWIPLISTFILTER.toString()); if (adapterFilter != null) { message = adapterFilter.doPreFilter(adptGrpName, adptName, message, prop, request, response); } @@ -83,7 +80,7 @@ public abstract class HttpAdapterServiceSupport implements HttpAdapterService, H continue; } - HttpAdapterFilter adapterFilter = HttpAdapterFilterFactory.createFilter(filterName.trim()); + HttpAdapterFilter adapterFilter = HttpAdapterFilterFactoryKjb.createFilter(filterName.trim()); if (adapterFilter != null) { message = adapterFilter.doPreFilter(adptGrpName, adptName, message, prop, request, response); } else { @@ -106,7 +103,7 @@ public abstract class HttpAdapterServiceSupport implements HttpAdapterService, H continue; } - HttpAdapterFilter adapterFilter = HttpAdapterFilterFactory.createFilter(filterName.trim()); + HttpAdapterFilter adapterFilter = HttpAdapterFilterFactoryKjb.createFilter(filterName.trim()); if (adapterFilter != null) { resultMessage = adapterFilter.doPostFilter(adptGrpName, adptName, resultMessage, prop, request, response); diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpDynamicInAdapterManager.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpDynamicInAdapterManager.java index cba7002..979052a 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpDynamicInAdapterManager.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpDynamicInAdapterManager.java @@ -24,8 +24,10 @@ public class HttpDynamicInAdapterManager implements Lifecycle { private static HttpDynamicInAdapterManager instance = new HttpDynamicInAdapterManager(); - private ConcurrentHashMap adptUriMap = new ConcurrentHashMap(); + //private ConcurrentHashMap adptUriMap = new ConcurrentHashMap(); + public ConcurrentHashMap adptUriMap = new ConcurrentHashMap(); + public static HttpDynamicInAdapterManager getInstance() { return instance; } diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpDynamicInAdapterUri.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpDynamicInAdapterUri.java index 91af6ce..2beda78 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpDynamicInAdapterUri.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/HttpDynamicInAdapterUri.java @@ -28,7 +28,7 @@ public class HttpDynamicInAdapterUri { return isEqualsAdpt(other.getAdptGrpName(), other.getAdptName()); } - public boolean isEqualsAdpt(String adptGrpName, String adptNamer) { + public boolean isEqualsAdpt(String adptGrpName, String adptName) { if ( adptGrpName != null && adptGrpName.equals(this.adptGrpName) && adptName != null && adptName.equals(this.adptName) ) { return true; diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/ApiAuthFilter.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/ApiAuthFilter.java index c3458e6..c41ee8a 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/ApiAuthFilter.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/ApiAuthFilter.java @@ -1,14 +1,19 @@ package com.eactive.eai.adapter.http.dynamic.filter; import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceSupport; +import com.eactive.eai.authserver.service.BearerTokenInfo; +//import com.eactive.eai.authserver.vo.BearerTokenInfo; +//import com.eactive.eai.authserver.custom.BearerTokenService; import com.eactive.eai.authserver.service.OAuth2Manager; import com.eactive.eai.authserver.vo.ClientVO; import com.eactive.eai.common.message.EAIMessage; import com.eactive.eai.common.message.EAIMessageManager; import com.eactive.eai.common.property.PropGroupVO; import com.eactive.eai.common.property.PropManager; +import com.eactive.eai.common.session.SessionManager; import com.eactive.eai.common.stdmessage.STDMessageManager; import com.eactive.eai.common.util.Logger; +import com.eactive.eai.common.util.StringUtil; import com.eactive.eai.inbound.action.ActionFactory; import com.eactive.eai.inbound.action.RequestAction; import com.eactive.eai.inbound.processor.Processor; @@ -35,7 +40,9 @@ import java.text.ParseException; import java.util.Base64; import java.util.Date; import java.util.HashSet; +import java.util.Map; import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; public class ApiAuthFilter implements HttpAdapterFilter { static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER); @@ -52,7 +59,10 @@ public class ApiAuthFilter implements HttpAdapterFilter { private JWSVerifier jwsVerifier; - public ApiAuthFilter() { +// // CA 토큰 저장소 +// private final Map CATokenStore = new ConcurrentHashMap<>(); + + public ApiAuthFilter() { super(); PropGroupVO vo = PropManager.getInstance().getPropGroupVO(PROP_GROUP_AUTH_SERVER); @@ -94,32 +104,55 @@ public class ApiAuthFilter implements HttpAdapterFilter { */ StandardMessage standardMessage = STDMessageManager.getInstance().getSTDMessage(apiId); String eaiSvcCd = StandardMessageManager.getInstance().getMapper().getEaiSvcCode(standardMessage); + if(!StringUtils.equals(eaiSvcCd, prop.getProperty("API_SERVICE_CODE"))) eaiSvcCd = prop.getProperty("API_SERVICE_CODE"); EAIMessage eaiMessage = EAIMessageManager.getInstance().getEAIMessage(eaiSvcCd); if(StringUtils.isBlank(eaiMessage.getAuthType())){ return message; } + boolean isPassScope = false; switch (eaiMessage.getAuthType()){ case "oauth": try { - String token = ApiAuthFilter.extractJWTToken(request); + String token = extractBearerToken(request); SignedJWT signedJWT = SignedJWT.parse(token); - if (new Date().after(signedJWT.getJWTClaimsSet().getExpirationTime())) { + if (signedJWT.getJWTClaimsSet().getExpirationTime() == null) { + logger.debug("Static Token"); + } else if (new Date().after(signedJWT.getJWTClaimsSet().getExpirationTime())) { throw new JwtAuthException(ERROR_TOKEN_EXPIRED, "Access token expired"); } - - if (!signedJWT.verify(jwsVerifier)) { - throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Token invalid"); + try { + if (!signedJWT.verify(jwsVerifier)) { + throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Token invalid"); + } + }catch (Exception e) { + throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Token invalid", e); } + OAuth2Manager manager = OAuth2Manager.getInstance(); HashSet scopeSet = manager.getApiScopeMap().get(apiId); - if (!verifyScope(scopeSet, signedJWT)) { + + String[] scopeArr = signedJWT.getJWTClaimsSet().getStringArrayClaim(PAYLOAD_PARAM_NAME_SCOPE); + if (scopeArr == null || scopeArr.length == 0) { throw new JwtAuthException(ERROR_AUTHORIZATION_FAIL, String.format("Insufficient [Scope](Allowed Scope=%s)", scopeSet.toString())); } + + for (String scope : scopeArr) { + if (StringUtils.equals(scope, "oob") || StringUtils.equals(scope, "public")) { + isPassScope = true; + } + } + + if (!isPassScope) { + if (!verifyScope(scopeSet, signedJWT)) { + throw new JwtAuthException(ERROR_AUTHORIZATION_FAIL, + String.format("Insufficient [Scope](Allowed Scope=%s)", scopeSet.toString())); + } + } // header 값으로 전송된 clientId와 토큰 소유 clientId check if (!verifyClientId(prop, signedJWT)) { @@ -130,7 +163,7 @@ public class ApiAuthFilter implements HttpAdapterFilter { throw e; } catch (Exception e) { logger.error(e.getMessage()); - throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Token invalid"); + throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Token unknown Error", e); } break; case "api_key": @@ -140,25 +173,43 @@ public class ApiAuthFilter implements HttpAdapterFilter { throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Invalid or missing API key \""+apiKeyName+"\" in Http Header"); } prop.setProperty(HttpAdapterServiceSupport.PROPERTIES_NAME_CLIENT_ID, apiKey); + isPassScope = true; + break; + case "ca": + String token = extractBearerToken(request); + BearerTokenInfo bearerTokenInfo = SessionManager.getInstance().getCAToken(token); + if ( bearerTokenInfo != null ) { + if( bearerTokenInfo.isExpired() ) { + SessionManager.getInstance().removeCAToken(token); + throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "expried API key \""+token+"\" in Http Authrozation Header"); + } + prop.setProperty(HttpAdapterServiceSupport.PROPERTIES_NAME_CLIENT_ID, bearerTokenInfo.getClientId()); + isPassScope = true; + } + else { + throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Invalid or missing API key \""+token+"\" in Http Authrozation Header"); + } break; case "none": return message; } - String clientId = prop.getProperty(HttpAdapterServiceSupport.PROPERTIES_NAME_CLIENT_ID); - ClientVO clientVO = OAuth2Manager.getInstance().getClientVO(clientId); - if(clientVO == null){ - throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Unregistered APP"); - } + if (isPassScope) { + String clientId = prop.getProperty(HttpAdapterServiceSupport.PROPERTIES_NAME_CLIENT_ID); + ClientVO clientVO = OAuth2Manager.getInstance().getClientVO(clientId); + if(clientVO == null){ + throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Unregistered APP"); + } - if(clientVO.getApiMap().containsKey(eaiSvcCd) == false){ - throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Unregistered API ["+eaiSvcCd+"] in ["+clientVO.getClientName()+"] APP"); + if(clientVO.getApiMap().containsKey(eaiSvcCd) == false){ + throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Unregistered API ["+eaiSvcCd+"] in ["+clientVO.getClientName()+"] APP"); + } } return message; } - private boolean verifyClientId(Properties prop, SignedJWT signedJWT) { + private boolean verifyClientId(Properties prop, SignedJWT signedJWT) throws JwtAuthException { try { // 이전 filter에서 셋팅한 clientId 확보 String headerClientId = prop.getProperty(HttpAdapterServiceSupport.PROPERTIES_NAME_CLIENT_ID); @@ -176,6 +227,7 @@ public class ApiAuthFilter implements HttpAdapterFilter { } } catch (Exception e) { logger.error(e.getMessage()); + throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Token invalid"); } return true; @@ -227,8 +279,16 @@ public class ApiAuthFilter implements HttpAdapterFilter { if (scopeArr == null || scopeArr.length == 0) { return false; } + + String passScope = "oob,public"; + String[] passScopeArr = org.springframework.util.StringUtils.tokenizeToStringArray(passScope, ","); for (String scope : scopeArr) { + for (String pScope : passScopeArr) { + if ( StringUtils.equalsAny(scope, pScope)) { + return true; + } + } if (scopeSet.contains(scope)) { return true; } @@ -237,7 +297,7 @@ public class ApiAuthFilter implements HttpAdapterFilter { return false; } - public static String extractJWTToken(HttpServletRequest request) throws JwtAuthException { + public static String extractBearerToken(HttpServletRequest request) throws JwtAuthException { String authorization = request.getHeader("Authorization"); if (StringUtils.isBlank(authorization)) { throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "No have header info: Authorization"); diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/HmacSha256VerifyFilterKjb.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/HmacSha256VerifyFilterKjb.java new file mode 100644 index 0000000..182e48c --- /dev/null +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/HmacSha256VerifyFilterKjb.java @@ -0,0 +1,183 @@ +package com.eactive.eai.adapter.http.dynamic.filter; + +import java.io.UnsupportedEncodingException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.Properties; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +//import org.apache.commons.net.util.Base64; +import org.springframework.http.HttpStatus; +import org.apache.commons.lang3.StringUtils; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; + +import com.eactive.eai.adapter.http.HttpMethodType; +import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey; +import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceSupport; +import com.eactive.eai.authserver.service.OAuth2Manager; +import com.eactive.eai.authserver.vo.ClientVO; +import com.eactive.eai.common.TransactionContextKeys; +import com.eactive.eai.common.util.Logger; + +public class HmacSha256VerifyFilterKjb implements HttpAdapterFilter { + + static final String KJB_ROOTLESS_ARRAY = "{ \"KJB_ROOTLESS_ARRAY\" : "; + + static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER); + + public HmacSha256VerifyFilterKjb() { + super(); + } + + @Override + public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop, + HttpServletRequest request, HttpServletResponse response) throws Exception { + + String inboundMethod = prop.getProperty(HttpAdapterServiceKey.INBOUND_METHOD); + String inboundUri = prop.getProperty(HttpAdapterServiceKey.INBOUND_URI); + String inboundBody = prop.getProperty(HttpAdapterServiceKey.INBOUND_REQUEST_MESSAGE); + + try { + String xObpPartnercode = request.getHeader("x-obp-partnercode"); + String xObpSignatureUrl = request.getHeader("x-obp-signature-url"); + String xObpSignatureBody = request.getHeader("x-obp-signature-body"); + if (StringUtils.isBlank(xObpPartnercode) + || StringUtils.isBlank(xObpSignatureUrl)) { + throw new JwtAuthException( + String.valueOf(HttpStatus.UNAUTHORIZED.value()), + "Can not find mandatory Http Header"); + } + + if (StringUtils.isNotBlank(prop.getProperty(HttpAdapterServiceKey.INBOUND_QUERY_STRING))) { + inboundUri = inboundUri + "?" + prop.getProperty(HttpAdapterServiceKey.INBOUND_QUERY_STRING); + inboundBody = ""; + } + String chkUrl = inboundMethod + "&" + inboundUri; + String chkBody = inboundBody; + String clientSecret = assignClientSecret(prop, request); + + if (chkBody.startsWith(KJB_ROOTLESS_ARRAY)) { + chkBody = chkBody.substring(KJB_ROOTLESS_ARRAY.length()); + + if (chkBody.endsWith("}")) { + chkBody = chkBody.substring(0, chkBody.length() - 1); + } + } + + String macUrl = calculateHMAC(chkUrl, clientSecret); + String macBody = calculateHMAC(chkBody, clientSecret); + + if (!StringUtils.equals(xObpSignatureUrl, macUrl)) { + throw new JwtAuthException( + String.valueOf(HttpStatus.UNAUTHORIZED.value()), + "Signature verifying failed : x-obp-signature-url"); + } + + switch (HttpMethodType.getValue(request.getMethod())) { + case GET: + case DELETE: + break; + default: + if (StringUtils.isNotBlank(inboundBody) && !StringUtils.equals("{}", inboundBody)) { + if (!StringUtils.equals(xObpSignatureBody, macBody)) { + throw new JwtAuthException( + String.valueOf(HttpStatus.UNAUTHORIZED.value()), + "Signature verifying failed : x-obp-signature-body"); + } + break; + } + } + + } catch (JwtAuthException e) { + logger.debug(e.getMessage()); + throw e; + } catch (Exception e) { + logger.error(e.getMessage()); + throw new JwtAuthException( + String.valueOf(HttpStatus.UNAUTHORIZED.value()), + "Signature verifying failed(unkown)"); + } + + return message; + } + + public static String calculateHMAC(String data, String key) + throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException { + + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(key.getBytes(), "HmacSHA256")); + return Base64.getEncoder().encodeToString(mac.doFinal(data.getBytes("UTF-8"))); + } + + private String assignClientSecret(Properties prop, HttpServletRequest request) throws Exception { + String clientId = assignClientId(prop, request); + if (StringUtils.isBlank(clientId)) { + throw new JwtAuthException( + String.valueOf(HttpStatus.UNAUTHORIZED.value()), + "Can not find clientId info"); + } + + ClientVO client = (ClientVO) OAuth2Manager.getInstance().getClientDeatilsStore().get(clientId); + if (client == null) { + throw new JwtAuthException( + String.valueOf(HttpStatus.UNAUTHORIZED.value()), + "Can not find client info"); + } + + return client.getClientSecret(); + } + + private String assignClientId(Properties prop, HttpServletRequest request) { + String clientId = null; + try { + // 이전 filter에서 셋팅한 clientId 확보 + clientId = prop.getProperty(HttpAdapterServiceSupport.PROPERTIES_NAME_CLIENT_ID); + + // 이전 filter에서 셋팅한 값이 없다면 header 정보에서 확보 + if (StringUtils.isBlank(clientId)) { + clientId = request.getHeader(HttpAdapterServiceSupport.HEADER_NAME_CLIENT_ID); + } + } catch (Exception e) { + logger.error(e.getMessage()); + } + + return clientId; + } + + @Override + public Object doPostFilter(String adptGrpName, String adptName, Object resultMessage, Properties prop, + HttpServletRequest request, HttpServletResponse response) throws Exception { + + String outboundBody = (String) resultMessage; + + try { + + Object root = JSONValue.parse(outboundBody); + + if (root instanceof JSONObject && ((JSONObject) root).containsKey("KJB_ROOTLESS_ARRAY")) { + JSONArray jsonArray = (JSONArray) ((JSONObject) root).get("KJB_ROOTLESS_ARRAY"); + outboundBody = jsonArray.toJSONString(); + } + + String clientSecret = assignClientSecret(prop, request); + String macBody = calculateHMAC(outboundBody, clientSecret); + + response.addHeader("x-obp-signature-body", macBody); + response.addHeader("x-obp-partnercode", request.getHeader("x-obp-partnercode")); + response.addHeader("x-obp-txid", prop.getProperty(TransactionContextKeys.TRANSACTION_UUID,"")); + } catch (Exception e) { + logger.error(e.getMessage()); + } + + return resultMessage; + } + + +} diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/HttpAdapterFilterFactoryKjb.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/HttpAdapterFilterFactoryKjb.java new file mode 100644 index 0000000..1b3f0c1 --- /dev/null +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/HttpAdapterFilterFactoryKjb.java @@ -0,0 +1,67 @@ +package com.eactive.eai.adapter.http.dynamic.filter; + +import java.util.concurrent.ConcurrentHashMap; + +import com.eactive.eai.common.util.Logger; + +public class HttpAdapterFilterFactoryKjb extends HttpAdapterFilterFactory { + static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER); + static String basePackage = "com.eactive.eai.custom.adapter.http.dynamic.filter"; + static private ConcurrentHashMap h = new ConcurrentHashMap(); + + public HttpAdapterFilterFactoryKjb() { + super(); + } + + @SuppressWarnings("rawtypes") + public static HttpAdapterFilter createFilter(String type) { + if (h.containsKey(type)) { + return (HttpAdapterFilter) h.get(type); + } + + HttpAdapterFilter filter = null; + switch (HttpAdapterFilterType.getValue(type)) { + case APIAUTHFILTER: + filter = new ApiAuthFilter(); + break; + case JWTAUTHFILTER: + filter = new JwtAuthFilter(); + break; + case IPWHITELISTFILTER: + filter = new IpWhiteListFilter(); + break; + case ADAPTERALLOWIPLISTFILTER: + filter = new AdapterAllowIPListFilter(); + break; + case HMAC_SHA256: + filter = new HmacSha256VerifyFilterKjb(); + break; + case REFLECTALLHEADER: + filter = new ReflectAllHeaderFilter(); + break; + default: + filter = classForName(type); + if (filter == null) { + filter = classForName(basePackage + "." + type); + } + break; + } + + if (filter != null) { + h.put(type, filter); + return filter; + } else { + return null; + } + } + + private static HttpAdapterFilter classForName(String type) { + try { + Class cl = Class.forName(type); + return (HttpAdapterFilter) cl.newInstance(); + } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { + logger.error("Cannot create a HttpAdapterFilter. - {}", type); + return null; + } + } +} diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/HttpAdapterFilterType.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/HttpAdapterFilterType.java index 6231c74..b22dc60 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/HttpAdapterFilterType.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/HttpAdapterFilterType.java @@ -5,6 +5,8 @@ public enum HttpAdapterFilterType { JWTAUTHFILTER, IPWHITELISTFILTER, ADAPTERALLOWIPLISTFILTER, + HMAC_SHA256, + REFLECTALLHEADER, UNKNOWN; public static HttpAdapterFilterType getValue(String type) { diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/JwtAuthFilter.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/JwtAuthFilter.java index 1de5a38..306f651 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/JwtAuthFilter.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/JwtAuthFilter.java @@ -88,7 +88,9 @@ public class JwtAuthFilter implements HttpAdapterFilter { String token = JwtAuthFilter.extractJWTToken(request); SignedJWT signedJWT = SignedJWT.parse(token); - if (new Date().after(signedJWT.getJWTClaimsSet().getExpirationTime())) { + if (signedJWT.getJWTClaimsSet().getExpirationTime() == null) { + logger.debug("Static Token"); + } else if (new Date().after(signedJWT.getJWTClaimsSet().getExpirationTime())) { throw new JwtAuthException(ERROR_TOKEN_EXPIRED, "Access token expired"); } @@ -118,7 +120,7 @@ public class JwtAuthFilter implements HttpAdapterFilter { return message; } - private boolean verifyClientId(Properties prop, SignedJWT signedJWT) { + private boolean verifyClientId(Properties prop, SignedJWT signedJWT) throws JwtAuthException { try { // 이전 filter에서 셋팅한 clientId 확보 String headerClientId = prop.getProperty(HttpAdapterServiceSupport.PROPERTIES_NAME_CLIENT_ID); @@ -136,6 +138,7 @@ public class JwtAuthFilter implements HttpAdapterFilter { } } catch (Exception e) { logger.error(e.getMessage()); + throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Token invalid"); } return true; diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/ReflectAllHeaderFilter.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/ReflectAllHeaderFilter.java new file mode 100644 index 0000000..ca0633e --- /dev/null +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/filter/ReflectAllHeaderFilter.java @@ -0,0 +1,96 @@ +package com.eactive.eai.adapter.http.dynamic.filter; + +import java.util.Enumeration; +import java.util.Properties; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.StringUtils; +import com.eactive.eai.common.util.Logger; +import com.eactive.eai.common.property.PropManager; + +import java.util.Arrays; +import java.util.stream.Stream; + +public class ReflectAllHeaderFilter implements HttpAdapterFilter { + + public ReflectAllHeaderFilter() { + super(); + } + + protected static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER); + + public static final String PROPERTIES_GROUP_NAME = "HttpHeaderFilter"; + public static final String HEADER_KEY_NAMES = "AllHeaderFilter.blackList"; + + String[] HttpHeaderRelayBlackList = { + "Content-Length", + "Transfer-Encoding", + "Host", + "Authorization", + "Accept", + "Host", + "Cookie", + "Connection", + "Keep-Alive", + "Proxy-Authenticate", + "Proxy-Authorization", + "TE", + "Trailer", + "Transfer-Encoding", + "Upgrade", + "Content-Type", + "Content-Encoding", + "Content-Language", + "Content-Location", + "Content-MD5", + "Expect", + }; + + + @Override + public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop, + HttpServletRequest request, HttpServletResponse response) throws Exception { + return message; + } + + @Override + public Object doPostFilter(String adptGrpName, String adptName, Object resultMessage, Properties prop, + HttpServletRequest request, HttpServletResponse response) throws Exception { + + logger.debug("doPreFilter ReflectAllHeaderFilter Start."); + + String propValue = PropManager.getInstance().getProperty(PROPERTIES_GROUP_NAME, HEADER_KEY_NAMES, "").trim(); + String[] userSettingBlackList = propValue.split(","); + + if( userSettingBlackList.length > 0 ) { + HttpHeaderRelayBlackList = Stream + .concat(Arrays.stream(HttpHeaderRelayBlackList), Arrays.stream(userSettingBlackList)) + .toArray(String[]::new); + } + + try { + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + + String headerName = headerNames.nextElement(); + String headerValue = request.getHeader(headerName); + + if( StringUtils.equalsAnyIgnoreCase( headerName, HttpHeaderRelayBlackList ) ) { + logger.debug("Skip Processing Key ["+headerName+"], value ["+headerValue+"] in HttpHeaderRelayBlackList"); + continue; + } + + response.setHeader(headerName, headerValue); + } + + } catch (Exception e) { + logger.error(e.getMessage()); + } + + logger.debug("doPreFilter ReflectAllHeaderFilter End."); + + return resultMessage; + } +} + diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/impl/HttpAdapterServiceBypass.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/impl/HttpAdapterServiceBypass.java index 0d47483..dd5ab69 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/impl/HttpAdapterServiceBypass.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/impl/HttpAdapterServiceBypass.java @@ -131,6 +131,7 @@ public class HttpAdapterServiceBypass extends HttpAdapterServiceSupport { prop.put(INBOUND_URI, request.getRequestURI()); prop.put(INBOUND_QUERY_STRING, StringUtils.defaultString(request.getQueryString())); prop.put(INBOUND_HEADER, getHeaders(request)); + prop.put(INBOUND_EXTPARAMS, StringUtils.defaultString(request.getQueryString())); if (StringUtils.equals(adptVO.getAdapterGroupVO().getType(), Keys.TYPE_REST) || StringUtils.equals(adptVO.getAdapterGroupVO().getType(), Keys.TYPE_HTTP_CUSTOM)) { // /api/v1/public/getUserInfo.svc @@ -503,6 +504,6 @@ public class HttpAdapterServiceBypass extends HttpAdapterServiceSupport { String orgUri = "/HTT/CbsInNetSys/abcd/123456"; String result = ""; result = getExtUri(orgUri, 3); - System.out.println(result); + // System.out.println(result); } } diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/impl/HttpAdapterServiceRest.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/impl/HttpAdapterServiceRest.java index dfa8bd8..3f3e9af 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/impl/HttpAdapterServiceRest.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/impl/HttpAdapterServiceRest.java @@ -275,6 +275,7 @@ public class HttpAdapterServiceRest extends HttpAdapterServiceSupport { prop = new Properties(); prop.put(INBOUND_METHOD, request.getMethod()); prop.put(INBOUND_URI, request.getRequestURI()); + prop.put(INBOUND_EXTPARAMS, StringUtils.defaultString(request.getQueryString())); prop.put(INBOUND_HEADER, getHeaders(request)); if (StringUtils.equals(adptVO.getAdapterGroupVO().getType(), Keys.TYPE_REST) || StringUtils.equals(adptVO.getAdapterGroupVO().getType(), Keys.TYPE_HTTP_CUSTOM)) { @@ -588,7 +589,13 @@ public class HttpAdapterServiceRest extends HttpAdapterServiceSupport { String adapterGroupName = prop.getProperty(HttpClientAdapterServiceKey.ADAPTER_GROUP_NAME); String adapterName = prop.getProperty(HttpClientAdapterServiceKey.ADAPTER_NAME); int httpStatusCode = response.getStatus(); - HttpAdapterExtraLogUtil.insertHttpAdapterExtraLog(uuid, 400, adapterGroupName, adapterName, new HashMap<>(), url, method, httpStatusCode); + Map headerMap = new HashMap<>(); + // 응답 헤더 로깅 + for (String headerName : response.getHeaderNames()) { + String headerValue = response.getHeader(headerName); + headerMap.put(headerName, headerValue); + } + HttpAdapterExtraLogUtil.insertHttpAdapterExtraLog(uuid, 400, adapterGroupName, adapterName, headerMap, url, method, httpStatusCode); } } diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/impl/HttpAdapterServiceStandard.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/impl/HttpAdapterServiceStandard.java index fc2da76..0dffb4f 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/impl/HttpAdapterServiceStandard.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/impl/HttpAdapterServiceStandard.java @@ -1,14 +1,19 @@ package com.eactive.eai.adapter.http.dynamic.impl; +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.Keys; import com.eactive.eai.adapter.http.HttpMemoryLogger; 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.HttpAdapterServiceSupport; +import com.eactive.eai.common.TransactionContextKeys; import com.eactive.eai.common.exception.ExceptionUtil; import com.eactive.eai.common.util.CommonLib; +import com.eactive.eai.common.util.HttpAdapterExtraLogUtil; import com.eactive.eai.common.util.Logger; import com.eactive.eai.common.util.MessageUtil; import com.eactive.eai.env.ElinkConfig; @@ -17,6 +22,9 @@ import com.eactive.eai.inbound.processor.Processor; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.StopWatch; import org.apache.mina.common.ByteBuffer; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; @@ -26,8 +34,11 @@ import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Properties; +import java.util.TreeMap; public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport { @@ -49,10 +60,14 @@ public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport **/ public void service(String adptGrpName, String adptName, HttpServletRequest request, HttpServletResponse response) { int traceLevel = 0; + + AdapterGroupVO adapterGroupVo = null; + Properties prop = null; + try { AdapterManager adapterManager = AdapterManager.getInstance(); AdapterVO adptVO = adapterManager.getAdapterVO(adptGrpName,adptName); - + adapterGroupVo = adptVO.getAdapterGroupVO(); AdapterPropManager manager = AdapterPropManager.getInstance(); if(adptVO == null) { @@ -153,10 +168,11 @@ public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport logger.debug("HttpAdapter] " + resMsg); } - Properties prop = new Properties(); + prop = new Properties(); prop.put(INBOUND_METHOD, request.getMethod()); prop.put(INBOUND_URI, request.getRequestURI()); prop.put(INBOUND_HEADER, getHeaders(request)); + prop.put(INBOUND_EXTPARAMS, StringUtils.defaultString(request.getQueryString())); if (StringUtils.equals(adptVO.getAdapterGroupVO().getType(), Keys.TYPE_REST) || StringUtils.equals(adptVO.getAdapterGroupVO().getType(), Keys.TYPE_HTTP_CUSTOM)) { // /api/v1/public/getUserInfo.svc @@ -172,6 +188,20 @@ public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport prop.put(PROPERTIES_NAME_HTTP_REQUEST_METHOD, request.getMethod()); prop.put(ALLOW_IP, httpProp.getProperty(ALLOW_IP, "")); + String body = new String ( requestBytes,encode); + + try { + Object root = JSONValue.parse(body); + if( root instanceof JSONArray ) { + JSONObject wrappedObject = new JSONObject(); + wrappedObject.put("KJB_ROOTLESS_ARRAY", root); + requestBytes = wrappedObject.toJSONString().getBytes(encode); + } + + }catch (Exception e) { + // ignore json이 아니기에 해줄것이 없음. + } + // 로컬 서비스 호출 Object result = null; if (MessageUtil.isBytesMessage(messageType)) { @@ -190,14 +220,17 @@ public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport } } - if (result == null) { + if ( result == null) { responseData = ElinkConfig.getAsyncDummyDataForAdapterGroup(adptGrpName); } else if (result instanceof byte[]) { responseData = new String((byte[]) result, encode); } else if (result instanceof String) { responseData = (String) result; + if ( StringUtils.isBlank( responseData ) ) { + responseData = ElinkConfig.getAsyncDummyDataForAdapterGroup(adptGrpName, adptName); + } } - + response.setCharacterEncoding(encode); response.getWriter().print(responseData); if (traceLevel >= 3){ @@ -218,8 +251,32 @@ public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport if (addData.length() > 0){ responseData = addData + responseData; } - // UI와 통신시(UTF-8) 변환오류로 ENCODE 제거 - response.setContentType("text/plain"); + + try { + Object root = JSONValue.parse(responseData); + if( root instanceof JSONObject ) { + JSONObject wrappedObject = (JSONObject) root; + responseData = wrappedObject.get("KJB_ROOTLESS_ARRAY").toString(); + } + + }catch (Exception e) { + // ignore json이 아니기에 해줄것이 없음. + } + + // 300응답에서 받은 Header정보 사용하기 위해 읽어옴. + Map responsePropertyMap = (Map) prop.get(OUTBOUND_PROPERTY_MAP); + if(responsePropertyMap != null){ + Properties responseHeaders = (Properties)responsePropertyMap.get(OUTBOUND_RESPONSE_HEADERS); + Map responseHeaderMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + // Properties 내용을 모두 복사 + for (String name : responseHeaders.stringPropertyNames()) { + responseHeaderMap.put(name, responseHeaders.getProperty(name)); + } + String contentTytpe = responseHeaderMap.get("Content-Type"); + response.setContentType(contentTytpe); // 300응답에서 받은 Content-Type을 그대로 적용. + } + + // UI와 통신시(UTF-8) 변환오류로 ENCODE 제거 response.setCharacterEncoding(encode); response.getWriter().print(responseData); if (logger.isDebug()){ @@ -241,26 +298,64 @@ public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport } logger.warn("HttpAdapter] " + adptGrpName + "-" + adptName + ">>" + e.getMessage()); response.setStatus(e.getStatus()); - try { - String errorMsg = String.format("(%d) %s", e.getStatus(), e.getMessage()); - response.getWriter().println(errorMsg); - } catch (Exception ex) { - // IGNORE + + if( "JSN".equals( adapterGroupVo.getMessageType() ) ) { + try { + String errorMsg = MessageUtil.makeJsonErrorMessage( MessageUtil.ERROR_CODE_AP_ERROR, e.getMessage()); + response.getWriter().println(errorMsg); + } catch (Exception ex) { + // IGNORE + } + }else { + try { + String errorMsg = String.format("(%d) %s", e.getStatus(), e.getMessage()); + response.getWriter().println(errorMsg); + } catch (Exception ex) { + // IGNORE + } } + } catch (Exception e) { if (traceLevel >= 3){ HttpMemoryLogger.error(adptGrpName+adptName, e.toString(),e); } logger.error("HttpAdapter] "+adptGrpName+"-"+adptName, e); response.setStatus(500); - try { - response.getWriter().println(e.getMessage()); - String errCode = ExceptionUtil.getErrorCode(e, "RECEAIAHA003"); - throw new Exception(errCode); - } catch (Exception ex) { - logger.warn("error", ex); + + if( "JSN".equals( adapterGroupVo.getMessageType() ) ) { + try { + String errorMsg = MessageUtil.makeJsonErrorMessage( MessageUtil.ERROR_CODE_AP_ERROR, e.getMessage()); + response.getWriter().println(errorMsg); + throw new Exception(MessageUtil.ERROR_CODE_AP_ERROR); + } catch (Exception ex) { + logger.warn("error", ex); + } + }else { + try { + response.getWriter().println(e.getMessage()); + String errCode = ExceptionUtil.getErrorCode(e, "RECEAIAHA003"); + throw new Exception(errCode); + } catch (Exception ex) { + logger.warn("error", ex); + } } - } + + + }finally { + String uuid = prop.getProperty(TransactionContextKeys.TRANSACTION_UUID); + String url = prop.getProperty(HttpClientAdapterServiceKey.INBOUND_EXTURI); + String method = prop.getProperty(HttpClientAdapterServiceKey.INBOUND_METHOD); + String adapterGroupName = prop.getProperty(HttpClientAdapterServiceKey.ADAPTER_GROUP_NAME); + String adapterName = prop.getProperty(HttpClientAdapterServiceKey.ADAPTER_NAME); + int httpStatusCode = response.getStatus(); + Map headerMap = new HashMap<>(); + // 응답 헤더 로깅 + for (String headerName : response.getHeaderNames()) { + String headerValue = response.getHeader(headerName); + headerMap.put(headerName, headerValue); + } + HttpAdapterExtraLogUtil.insertHttpAdapterExtraLog(uuid, 400, adapterGroupName, adapterName, headerMap, url, method, httpStatusCode); + } } /** diff --git a/src/main/java/com/eactive/eai/adapter/http/dynamic/wrapper/KeepAliveTrueWrapper.java b/src/main/java/com/eactive/eai/adapter/http/dynamic/wrapper/KeepAliveTrueWrapper.java index ae9e4fc..4364ead 100644 --- a/src/main/java/com/eactive/eai/adapter/http/dynamic/wrapper/KeepAliveTrueWrapper.java +++ b/src/main/java/com/eactive/eai/adapter/http/dynamic/wrapper/KeepAliveTrueWrapper.java @@ -54,7 +54,7 @@ public class KeepAliveTrueWrapper implements HandlerWrapper { // 최대 요청 횟수를 초과한 경우 연결을 종료하고 로그를 출력 if (count > maxRequestCount) { exchange.getConnection().close(); - System.out.println("Connection closed due to exceeding max requests limit."); + // System.out.println("Connection closed due to exceeding max requests limit."); return; } handler.handleRequest(exchange); diff --git a/src/main/java/com/eactive/eai/adapter/jtc/JtcBeanSample.java b/src/main/java/com/eactive/eai/adapter/jtc/JtcBeanSample.java index 705afc9..87a1d47 100644 --- a/src/main/java/com/eactive/eai/adapter/jtc/JtcBeanSample.java +++ b/src/main/java/com/eactive/eai/adapter/jtc/JtcBeanSample.java @@ -45,7 +45,7 @@ public class JtcBeanSample implements JtmaxService { String bufferType = tux.getBufferTypeString(); if ("STRING".equals(bufferType)) { TuxStringBuffer tuxbuf = (TuxStringBuffer) tux; - System.out.println("received string value : " + tuxbuf.getString()); + // System.out.println("received string value : " + tuxbuf.getString()); TuxStringBuffer ret = new TuxStringBuffer(WebtSystem.getDefaultCharset()); ret.setString(tuxbuf.getString().toUpperCase()); return ret; @@ -60,8 +60,8 @@ public class JtcBeanSample implements JtmaxService { } String rtnstr = rcvstr.toUpperCase(); - System.out.println("received string value : " + rcvstr); - System.out.println("return string value : " + rtnstr); + // System.out.println("received string value : " + rcvstr); + // System.out.println("return string value : " + rtnstr); TuxCarrayBuffer ret = new TuxCarrayBuffer(WebtSystem.getDefaultCharset()); ret.setBytes(rtnstr.getBytes());; return ret; @@ -73,8 +73,8 @@ public class JtcBeanSample implements JtmaxService { String rcvstr = tuxbuf.getField("SEC100").get().stringValue(); String rtnstr = rcvstr.toUpperCase(); - System.out.println("received string value : " + rcvstr); - System.out.println("return string value : " + rtnstr); + // System.out.println("received string value : " + rcvstr); + // System.out.println("return string value : " + rtnstr); TuxFieldBuffer ret = new TuxFieldBuffer(false); // FML 16임으로 false로 // ret.createField(sample.fml_sec2).add(rtnstr); ret.createField("SEC2").add(rtnstr); diff --git a/src/main/java/com/eactive/eai/adapter/jtc/JtcClientSample.java b/src/main/java/com/eactive/eai/adapter/jtc/JtcClientSample.java index dd90520..cf80d3e 100644 --- a/src/main/java/com/eactive/eai/adapter/jtc/JtcClientSample.java +++ b/src/main/java/com/eactive/eai/adapter/jtc/JtcClientSample.java @@ -73,7 +73,7 @@ public class JtcClientSample { try { // if(cd == null) { - System.out.println("tpconnect failed!"); + // System.out.println("tpconnect failed!"); // } // else { @@ -84,12 +84,12 @@ public class JtcClientSample { sndbuf.setString("conversation service"); TuxBuffer rcvbuf = service.tpcall(sndbuf); - System.out.println(rcvbuf.getString()); + // System.out.println(rcvbuf.getString()); // } } catch (WebtException e) { e.printStackTrace(); - System.out.println("error Occurred"); + // System.out.println("error Occurred"); } finally { diff --git a/src/main/java/com/eactive/eai/adapter/jtc/JtcServerAdapterBean.java b/src/main/java/com/eactive/eai/adapter/jtc/JtcServerAdapterBean.java index 74ccd59..211cf54 100644 --- a/src/main/java/com/eactive/eai/adapter/jtc/JtcServerAdapterBean.java +++ b/src/main/java/com/eactive/eai/adapter/jtc/JtcServerAdapterBean.java @@ -58,7 +58,7 @@ public class JtcServerAdapterBean implements JtmaxService { try { if ("STRING".equals(bufferType)) { TuxStringBuffer tuxbuf = (TuxStringBuffer) tux; - System.out.println("received string value : " + tuxbuf.getString()); + // System.out.println("received string value : " + tuxbuf.getString()); byte[] request = tuxbuf.getString().getBytes(); RequestDispatcher dispatcher = RequestDispatcher.getRequestDispatcher(adapterGroupName); byte[] response = (byte[]) dispatcher.handle(adapterName, request, prop); diff --git a/src/main/java/com/eactive/eai/adapter/jtc/TestMsgListener.java b/src/main/java/com/eactive/eai/adapter/jtc/TestMsgListener.java index 6ed12d0..46fcd28 100644 --- a/src/main/java/com/eactive/eai/adapter/jtc/TestMsgListener.java +++ b/src/main/java/com/eactive/eai/adapter/jtc/TestMsgListener.java @@ -31,12 +31,11 @@ public class TestMsgListener implements TuxAsyncMsgListener { } public void handleError(Exception e) { - System.out.println(e); + // System.out.println(e); } public void handleEvent(TuxBuffer rcvBuffer) { - System.out.println(Thread.currentThread().getName() - +" ] rcv " + rcvBuffer); + // System.out.println(Thread.currentThread().getName()+" ] rcv " + rcvBuffer); try { // TODO : Call Internal service } diff --git a/src/main/java/com/eactive/eai/adapter/socket2/app/dump/DumpServer.java b/src/main/java/com/eactive/eai/adapter/socket2/app/dump/DumpServer.java index 707db00..5004e19 100644 --- a/src/main/java/com/eactive/eai/adapter/socket2/app/dump/DumpServer.java +++ b/src/main/java/com/eactive/eai/adapter/socket2/app/dump/DumpServer.java @@ -9,7 +9,7 @@ import com.eactive.eai.adapter.socket2.protocol.ISocketAdapter; public class DumpServer { static public void main(String[] args) throws Exception { if (args.length != 1) { - System.out.println("Usage : dump "); + // System.out.println("Usage : dump "); return; } int port = Integer.parseInt(args[0]); @@ -53,12 +53,12 @@ public class DumpServer { System.out.print("> "); String cmd = (new java.io.BufferedReader(new java.io.InputStreamReader(System.in))).readLine(); if ("".equals(cmd)) { - System.out.println(SocketAdapterManager.getInstance()); + // System.out.println(SocketAdapterManager.getInstance()); } else if ("exit".equals(cmd)) { System.exit(1); } } catch(Exception e) { - System.out.println(e.toString()); + // System.out.println(e.toString()); } } } diff --git a/src/main/java/com/eactive/eai/adapter/socket2/app/echo/EchoServer.java b/src/main/java/com/eactive/eai/adapter/socket2/app/echo/EchoServer.java index 7f7d510..dba092a 100644 --- a/src/main/java/com/eactive/eai/adapter/socket2/app/echo/EchoServer.java +++ b/src/main/java/com/eactive/eai/adapter/socket2/app/echo/EchoServer.java @@ -46,12 +46,12 @@ public class EchoServer { System.out.print("> "); String cmd = (new java.io.BufferedReader(new java.io.InputStreamReader(System.in))).readLine(); if ("".equals(cmd)) { - System.out.println(SocketAdapterManager.getInstance()); + // System.out.println(SocketAdapterManager.getInstance()); } else if ("exit".equals(cmd)) { System.exit(1); } } catch(Exception e) { - System.out.println("processCommand errpr "+ e.toString()); + // System.out.println("processCommand errpr "+ e.toString()); } } } diff --git a/src/main/java/com/eactive/eai/adapter/socket2/app/muxer/Muxer.java b/src/main/java/com/eactive/eai/adapter/socket2/app/muxer/Muxer.java index d69560e..ca4ccbe 100644 --- a/src/main/java/com/eactive/eai/adapter/socket2/app/muxer/Muxer.java +++ b/src/main/java/com/eactive/eai/adapter/socket2/app/muxer/Muxer.java @@ -49,15 +49,15 @@ public class Muxer { } public synchronized byte[] handle(byte[] message) { - System.out.println("##############################################################"); - System.out.println("CiscoListener | message received : " + new String(message)); - System.out.println("##############################################################"); + // System.out.println("##############################################################"); + // System.out.println("CiscoListener | message received : " + new String(message)); + // System.out.println("##############################################################"); return message; } static public void main(String[] args) throws Exception { if (args.length != 3) { - System.out.println("java " + Muxer.class.getName() + " "); + // System.out.println("java " + Muxer.class.getName() + " "); return; } @@ -77,9 +77,9 @@ class MuxerRequestProcessor implements IRequestProcessor { } public synchronized byte[] handle(byte[] message) throws EAIException { - System.out.println("##############################################################"); - System.out.println("MuxerRequestProcessor | message received : " + new String(message)); - System.out.println("##############################################################"); + // System.out.println("##############################################################"); + // System.out.println("MuxerRequestProcessor | message received : " + new String(message)); + // System.out.println("##############################################################"); return (byte[]) outboundAdapter.sendMessage(message); } diff --git a/src/main/java/com/eactive/eai/adapter/socket2/app/proxy/ProxyServer.java b/src/main/java/com/eactive/eai/adapter/socket2/app/proxy/ProxyServer.java index 38f238a..d4114f3 100644 --- a/src/main/java/com/eactive/eai/adapter/socket2/app/proxy/ProxyServer.java +++ b/src/main/java/com/eactive/eai/adapter/socket2/app/proxy/ProxyServer.java @@ -34,7 +34,7 @@ public class ProxyServer { static public void main(String[] args) throws Exception { if (args.length != 3) { - System.out.println("java " + ProxyServer.class.getName() + " "); + // System.out.println("java " + ProxyServer.class.getName() + " "); return; } diff --git a/src/main/java/com/eactive/eai/adapter/socket2/app/tester/LoadRunner.java b/src/main/java/com/eactive/eai/adapter/socket2/app/tester/LoadRunner.java index 4d2ca64..2fb9795 100644 --- a/src/main/java/com/eactive/eai/adapter/socket2/app/tester/LoadRunner.java +++ b/src/main/java/com/eactive/eai/adapter/socket2/app/tester/LoadRunner.java @@ -188,9 +188,9 @@ public class LoadRunner { } stopLatch.countDown(); } catch (Exception e) { - System.out.println(e.toString()); + // System.out.println(e.toString()); } catch (Error e) { - System.out.println(e.toString()); + // System.out.println(e.toString()); } } }); @@ -202,7 +202,7 @@ public class LoadRunner { stopLatch.await(); } catch (InterruptedException ex) { //ex.printStackTrace(); - System.out.println("wait error"); + // System.out.println("wait error"); } executor.shutdown(); @@ -211,27 +211,27 @@ public class LoadRunner { boolean result = executor.awaitTermination(1000, TimeUnit.MILLISECONDS); if (result) break; - System.out.println("[LoadRunner] shutdown() progressing ... await 1 seconds more"); + // System.out.println("[LoadRunner] shutdown() progressing ... await 1 seconds more"); } catch (InterruptedException e) { //e.printStackTrace(); - System.out.println("awaitTermination error"); + // System.out.println("awaitTermination error"); } } latch.await(); stopWatch.stop(); - System.out.println(); - System.out.println(); - System.out.println("==============================================================="); - System.out.println(" think time : " + thinkTime + " ms"); - System.out.println(" thread count : " + threadCount); - System.out.println(" loop count : " + loopCount); - System.out.println(" total request : " + (threadCount * loopCount)); - System.out.println(" elapsed : " + stopWatch.toString()); - System.out.println(" tps : " + new Integer(threadCount * loopCount * 1000).longValue() / stopWatch.getTime()); - System.out.println("==============================================================="); - System.out.println(); + // System.out.println(); + // System.out.println(); + // System.out.println("==============================================================="); + // System.out.println(" think time : " + thinkTime + " ms"); + // System.out.println(" thread count : " + threadCount); + // System.out.println(" loop count : " + loopCount); + // System.out.println(" total request : " + (threadCount * loopCount)); + // System.out.println(" elapsed : " + stopWatch.toString()); + // System.out.println(" tps : " + new Integer(threadCount * loopCount * 1000).longValue() / stopWatch.getTime()); + // System.out.println("==============================================================="); + // System.out.println(); } @@ -245,13 +245,13 @@ public class LoadRunner { break; } else if ("".equals(line.trim())) { } else if ("help".equals(line.trim())) { - System.out.println("==============================================================="); - System.out.println("LoadRunner v1.0 (http port = 8282)"); - System.out.println("==============================================================="); - System.out.println(" help : help"); - System.out.println(" start : start [thread count] [loop count] [think time]"); - System.out.println(" exit : exit"); - System.out.println(""); + // System.out.println("==============================================================="); + // System.out.println("LoadRunner v1.0 (http port = 8282)"); + // System.out.println("==============================================================="); + // System.out.println(" help : help"); + // System.out.println(" start : start [thread count] [loop count] [think time]"); + // System.out.println(" exit : exit"); + // System.out.println(""); } else if (line.trim().startsWith("start")) { String[] tokens = line.trim().split("[ ]+"); if (tokens.length > 1) @@ -264,10 +264,10 @@ public class LoadRunner { } else if ("exit".equals(line.trim())) { System.exit(1); } else { - System.out.println("Unknow command. type help."); + // System.out.println("Unknow command. type help."); } } catch(Exception e) { - System.out.println("Error " + e.toString()); + // System.out.println("Error " + e.toString()); } } } @@ -298,7 +298,7 @@ public class LoadRunner { if(br != null) br.close(); } catch(Exception ee) { - System.out.println("close error"); + // System.out.println("close error"); } } @@ -369,10 +369,10 @@ public class LoadRunner { if (args.length == 2) { hostname = args[0]; - System.out.println("remote host : " + hostname); + // System.out.println("remote host : " + hostname); filename = args[1]; } else { - System.out.println("Usage : loadrunner [ip] [file]"); + // System.out.println("Usage : loadrunner [ip] [file]"); return; } diff --git a/src/main/java/com/eactive/eai/adapter/socket2/app/tester/LoadRunner2.java b/src/main/java/com/eactive/eai/adapter/socket2/app/tester/LoadRunner2.java index 2248622..a2724f5 100644 --- a/src/main/java/com/eactive/eai/adapter/socket2/app/tester/LoadRunner2.java +++ b/src/main/java/com/eactive/eai/adapter/socket2/app/tester/LoadRunner2.java @@ -189,10 +189,10 @@ public class LoadRunner2 { stopLatch.countDown(); } catch (Exception e) { // e.printStackTrace(); - System.out.println("executor.execute Exception"); + // System.out.println("executor.execute Exception"); } catch (Error e) { // e.printStackTrace(); - System.out.println("executor.execute error"); + // System.out.println("executor.execute error"); } } }); @@ -204,7 +204,7 @@ public class LoadRunner2 { stopLatch.await(); } catch (InterruptedException ex) { // ex.printStackTrace(); - System.out.println("InterruptedException"); + // System.out.println("InterruptedException"); } executor.shutdown(); @@ -213,27 +213,27 @@ public class LoadRunner2 { boolean result = executor.awaitTermination(1000, TimeUnit.MILLISECONDS); if (result) break; - System.out.println("[LoadRunner] shutdown() progressing ... await 1 seconds more"); + // System.out.println("[LoadRunner] shutdown() progressing ... await 1 seconds more"); } catch (InterruptedException e) { // e.printStackTrace(); - System.out.println("[LoadRunner] shutdown() progressing ...InterruptedException"); + // System.out.println("[LoadRunner] shutdown() progressing ...InterruptedException"); } } latch.await(); stopWatch.stop(); - System.out.println(); - System.out.println(); - System.out.println("==============================================================="); - System.out.println(" think time : " + thinkTime + " ms"); - System.out.println(" thread count : " + threadCount); - System.out.println(" loop count : " + loopCount); - System.out.println(" total request : " + (threadCount * loopCount)); - System.out.println(" elapsed : " + stopWatch.toString()); - System.out.println(" tps : " + new Integer(threadCount * loopCount * 1000).longValue() / stopWatch.getTime()); - System.out.println("==============================================================="); - System.out.println(); + // System.out.println(); + // System.out.println(); + // System.out.println("==============================================================="); + // System.out.println(" think time : " + thinkTime + " ms"); + // System.out.println(" thread count : " + threadCount); + // System.out.println(" loop count : " + loopCount); + // System.out.println(" total request : " + (threadCount * loopCount)); + // System.out.println(" elapsed : " + stopWatch.toString()); + // System.out.println(" tps : " + new Integer(threadCount * loopCount * 1000).longValue() / stopWatch.getTime()); + // System.out.println("==============================================================="); + // System.out.println(); } @@ -247,13 +247,13 @@ public class LoadRunner2 { break; } else if ("".equals(line.trim())) { } else if ("help".equals(line.trim())) { - System.out.println("==============================================================="); - System.out.println("LoadRunner v1.0 (http port = 8282)"); - System.out.println("==============================================================="); - System.out.println(" help : help"); - System.out.println(" start : start [thread count] [loop count] [think time]"); - System.out.println(" exit : exit"); - System.out.println(""); + // System.out.println("==============================================================="); + // System.out.println("LoadRunner v1.0 (http port = 8282)"); + // System.out.println("==============================================================="); + // System.out.println(" help : help"); + // System.out.println(" start : start [thread count] [loop count] [think time]"); + // System.out.println(" exit : exit"); + // System.out.println(""); } else if (line.trim().startsWith("start")) { String[] tokens = line.trim().split("[ ]+"); if (tokens.length > 1) @@ -266,11 +266,11 @@ public class LoadRunner2 { } else if ("exit".equals(line.trim())) { System.exit(1); } else { - System.out.println("Unknow command. type help."); + // System.out.println("Unknow command. type help."); } } catch(Exception e) { // e.printStackTrace(); - System.out.println("Exception"); + // System.out.println("Exception"); } } } @@ -293,14 +293,14 @@ public class LoadRunner2 { } } catch(Exception e) { - System.out.println(e.toString()); + // System.out.println(e.toString()); } finally { try { br.close(); } catch(Exception e) { - System.out.println(e.toString()); + // System.out.println(e.toString()); } } @@ -371,10 +371,10 @@ public class LoadRunner2 { if (args.length == 2) { hostname = args[0]; - System.out.println("remote host : " + hostname); + // System.out.println("remote host : " + hostname); filename = args[1]; } else { - System.out.println("Usage : loadrunner [ip] [file]"); + // System.out.println("Usage : loadrunner [ip] [file]"); return; } diff --git a/src/main/java/com/eactive/eai/adapter/socket2/common/ExpiringMap.java b/src/main/java/com/eactive/eai/adapter/socket2/common/ExpiringMap.java index f1cc512..f267d00 100644 --- a/src/main/java/com/eactive/eai/adapter/socket2/common/ExpiringMap.java +++ b/src/main/java/com/eactive/eai/adapter/socket2/common/ExpiringMap.java @@ -623,14 +623,14 @@ public class ExpiringMap implements Map { ExpiringMap m = new ExpiringMap(1); String key ="aaaaaaa"; m.put(key,key); - System.out.println(m.get(key)); + // System.out.println(m.get(key)); Thread.sleep(1 * 1000L); - System.out.println(m.get(key)); + // System.out.println(m.get(key)); Thread.sleep(1 * 1000L); - System.out.println(m.get(key)); + // System.out.println(m.get(key)); Thread.sleep(1 * 1000L); - System.out.println(m.get(key)); + // System.out.println(m.get(key)); Thread.sleep(1 * 1000L); - System.out.println(m.get(key)); + // System.out.println(m.get(key)); } } diff --git a/src/main/java/com/eactive/eai/adapter/socket2/protocol/admin/TelnetAdminHandler.java b/src/main/java/com/eactive/eai/adapter/socket2/protocol/admin/TelnetAdminHandler.java index 590feb2..7caba50 100644 --- a/src/main/java/com/eactive/eai/adapter/socket2/protocol/admin/TelnetAdminHandler.java +++ b/src/main/java/com/eactive/eai/adapter/socket2/protocol/admin/TelnetAdminHandler.java @@ -18,7 +18,7 @@ public class TelnetAdminHandler extends ProtocolHandler { @Override public void messageReceived(IoSession session, Object message) throws Exception { String msg = message.toString().trim(); - System.out.println(" " + msg); + // System.out.println(" " + msg); if ("quit".equals(msg) || "exit".equals(msg)) { session.write("bye......"); diff --git a/src/main/java/com/eactive/eai/adapter/socket2/protocol/http/Server.java b/src/main/java/com/eactive/eai/adapter/socket2/protocol/http/Server.java index d093d96..8720275 100644 --- a/src/main/java/com/eactive/eai/adapter/socket2/protocol/http/Server.java +++ b/src/main/java/com/eactive/eai/adapter/socket2/protocol/http/Server.java @@ -42,10 +42,10 @@ public class Server { acceptor .bind(new InetSocketAddress(port), new ServerHandler(), cfg); - System.out.println("Server now listening on port " + port); + // System.out.println("Server now listening on port " + port); } catch (Exception ex) { // ex.printStackTrace(); - System.out.println("Error" + ex.toString()); + // System.out.println("Error" + ex.toString()); } } } diff --git a/src/main/java/com/eactive/eai/adapter/socket2/protocol/http/codec/HttpResponse.java b/src/main/java/com/eactive/eai/adapter/socket2/protocol/http/codec/HttpResponse.java index 84362ed..b9e0ef6 100644 --- a/src/main/java/com/eactive/eai/adapter/socket2/protocol/http/codec/HttpResponse.java +++ b/src/main/java/com/eactive/eai/adapter/socket2/protocol/http/codec/HttpResponse.java @@ -61,7 +61,7 @@ public class HttpResponse { try { body.write(b); } catch (IOException ex) { - System.out.println("appendBody error"); + // System.out.println("appendBody error"); } } @@ -69,7 +69,7 @@ public class HttpResponse { try { body.write(s.getBytes()); } catch (IOException ex) { - System.out.println("appendBody string error"); + // System.out.println("appendBody string error"); } } diff --git a/src/main/java/com/eactive/eai/adapter/socket2/tool/admin/NetAdmin.java b/src/main/java/com/eactive/eai/adapter/socket2/tool/admin/NetAdmin.java index bcb0491..dffe926 100644 --- a/src/main/java/com/eactive/eai/adapter/socket2/tool/admin/NetAdmin.java +++ b/src/main/java/com/eactive/eai/adapter/socket2/tool/admin/NetAdmin.java @@ -10,8 +10,8 @@ public class NetAdmin { if (args.length == 1) { hostname = args[0]; } else if (args.length == 2) { - System.out.println("args[0] " + args[0]); - System.out.println("args[1] " + args[1]); + // System.out.println("args[0] " + args[0]); + // System.out.println("args[1] " + args[1]); hostname = args[0]; port = Integer.parseInt(args[1]); } @@ -32,6 +32,6 @@ public class NetAdmin { sb.append("set connection - Max Connection 수 조정 ( netadmin set connection adapterName #OfConnection )"); sb.append("set thread - Max Thread 수 조정 ( netadmin set thread adapterName #OfSession )"); sb.append("set trace - 소켓어뎁터 추적관리 레벨 조정 ( netadmin set trace adapterName [ 0 | 1 | 2] )\n"); - System.out.println(sb.toString()); + // System.out.println(sb.toString()); } } diff --git a/src/main/java/com/eactive/eai/adapter/socket2/tool/admin/Shell.java b/src/main/java/com/eactive/eai/adapter/socket2/tool/admin/Shell.java index 75b6b71..3e7fe11 100644 --- a/src/main/java/com/eactive/eai/adapter/socket2/tool/admin/Shell.java +++ b/src/main/java/com/eactive/eai/adapter/socket2/tool/admin/Shell.java @@ -64,7 +64,7 @@ public class Shell { public void loop() throws Exception { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); - System.out.println(welcomeMsg); + // System.out.println(welcomeMsg); do { // set prompt prompt = "\nnetadmin-" + hostname + ":" + port + "| " + context + "> "; @@ -74,7 +74,7 @@ public class Shell { try { if(line != null) process(line); } catch(Exception e) { - System.out.println("loop error "+ e.toString()); + // System.out.println("loop error "+ e.toString()); } } while(true); } @@ -87,9 +87,9 @@ public class Shell { SimpleFuture future = admin.stop(); future.join(); } catch(Exception e) { - System.out.println("stop error"); + // System.out.println("stop error"); } - System.out.println(byeMsg); + // System.out.println(byeMsg); System.exit(1); } @@ -103,6 +103,6 @@ public class Shell { context = res; } } - System.out.println(new String(response)); + // System.out.println(new String(response)); } } diff --git a/src/main/java/com/eactive/eai/adapter/wca/WCASessionThread.java b/src/main/java/com/eactive/eai/adapter/wca/WCASessionThread.java index 2536f9f..9bd65fe 100644 --- a/src/main/java/com/eactive/eai/adapter/wca/WCASessionThread.java +++ b/src/main/java/com/eactive/eai/adapter/wca/WCASessionThread.java @@ -393,7 +393,7 @@ public class WCASessionThread implements Runnable { myLog.logMsg(MyLog.WARN, "myLog Path : " + sMyLogPath); } catch(Exception ignore) { - System.out.println("WCASessionThread> Exception Msg = " + ignore.toString()); + // System.out.println("WCASessionThread> Exception Msg = " + ignore.toString()); } /* 20080523 End */ } @@ -739,7 +739,7 @@ public class WCASessionThread implements Runnable { } } catch (Exception ignore) { - System.out.println("WCASessionThread:run> Exception Msg = " + ignore.toString()); + // System.out.println("WCASessionThread:run> Exception Msg = " + ignore.toString()); } /* 20080523 SMS 로그 추가 끝 */ } diff --git a/src/main/java/com/eactive/eai/adapter/wca/data/WCAQueue.java b/src/main/java/com/eactive/eai/adapter/wca/data/WCAQueue.java index d4872b0..47fe9e6 100644 --- a/src/main/java/com/eactive/eai/adapter/wca/data/WCAQueue.java +++ b/src/main/java/com/eactive/eai/adapter/wca/data/WCAQueue.java @@ -382,7 +382,7 @@ public class WCAQueue { if (pBuff.length >= WCAHeader.WCA_HEADER_LEN + 3) System.arraycopy(pBuff, WCAHeader.WCA_HEADER_LEN, pDFSBuff, 0, pDFSBuff.length); - System.out.println("------> DFS : " + new String(pDFSBuff)); + // System.out.println("------> DFS : " + new String(pDFSBuff)); if((new String(pDFSBuff)).equals(new String(WCADefine.DFS_MSG))) bDFSFlag = true; else bDFSFlag = false; diff --git a/src/main/java/com/eactive/eai/adapter/wca/util/MyLog.java b/src/main/java/com/eactive/eai/adapter/wca/util/MyLog.java index 243b102..def9be8 100644 --- a/src/main/java/com/eactive/eai/adapter/wca/util/MyLog.java +++ b/src/main/java/com/eactive/eai/adapter/wca/util/MyLog.java @@ -544,7 +544,7 @@ public class MyLog { logMsg("LOG LEVLE = " + nLogLevel + ", LOG SIZE = " + MAX_LOG_FILE_SIZE + "M"); } catch (Exception e) { - System.out.println("openLogStream error -"+e.toString()); + // System.out.println("openLogStream error -"+e.toString()); } } @@ -559,7 +559,7 @@ public class MyLog { } } catch (Exception e) { - System.out.println("closeLogStream error -"+e.toString()); + // System.out.println("closeLogStream error -"+e.toString()); } } diff --git a/src/main/java/com/eactive/eai/agent/inflow/ReloadInflowGroupControlCommand.java b/src/main/java/com/eactive/eai/agent/inflow/ReloadInflowGroupControlCommand.java new file mode 100644 index 0000000..0582f01 --- /dev/null +++ b/src/main/java/com/eactive/eai/agent/inflow/ReloadInflowGroupControlCommand.java @@ -0,0 +1,56 @@ +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.InflowControlManager; +import com.eactive.eai.common.util.Logger; + +public class ReloadInflowGroupControlCommand extends Command { + + private static final long serialVersionUID = 1L; + + public ReloadInflowGroupControlCommand() { + super("ReloadInflowGroupControlCommand"); + } + + 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 { + InflowControlManager manager = InflowControlManager.getInstance(); + + if (keyName != null) { + if ("ALL".equals(keyName)) { + manager.reloadGroup(); + if (logger.isWarn()) + logger.warn(this.name + "] all group rule Reload."); + } else { + manager.reloadGroup(keyName); + if (logger.isWarn()) + logger.warn(this.name + "] group " + 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"; + + } + +} diff --git a/src/main/java/com/eactive/eai/agent/inflow/RemoveInflowGroupControlCommand.java b/src/main/java/com/eactive/eai/agent/inflow/RemoveInflowGroupControlCommand.java new file mode 100644 index 0000000..a4bdf03 --- /dev/null +++ b/src/main/java/com/eactive/eai/agent/inflow/RemoveInflowGroupControlCommand.java @@ -0,0 +1,45 @@ +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.InflowControlManager; +import com.eactive.eai.common.util.Logger; + +public class RemoveInflowGroupControlCommand extends Command { + + private static final long serialVersionUID = 1L; + + public RemoveInflowGroupControlCommand() { + super("RemoveInflowGroupControlCommand"); + } + + 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 { + InflowControlManager manager = InflowControlManager.getInstance(); + manager.removeGroup(key); + if (logger.isWarn()) + logger.warn(this.name + "] group " + 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"; + } + +} diff --git a/src/main/java/com/eactive/eai/agent/property/ReloadPropertyCommand.java b/src/main/java/com/eactive/eai/agent/property/ReloadPropertyCommand.java index 23ae3f1..e4837e0 100644 --- a/src/main/java/com/eactive/eai/agent/property/ReloadPropertyCommand.java +++ b/src/main/java/com/eactive/eai/agent/property/ReloadPropertyCommand.java @@ -41,6 +41,10 @@ public class ReloadPropertyCommand extends Command { if (logger.isWarn()) logger.warn(this.name + "] " + keyName + " Reload."); } + + if (keyName.startsWith("FileLogger{")) { + com.eactive.eai.common.util.Logger.setLoggerLevel(keyName); + } } } catch (Exception e) { String rspErrorCode = "RECEAIMCM002"; diff --git a/src/main/java/com/eactive/eai/authoutbound/client/HttpClientAccessTokenServiceByDB.java b/src/main/java/com/eactive/eai/authoutbound/client/HttpClientAccessTokenServiceByDB.java index 40ac62a..fd589d1 100644 --- a/src/main/java/com/eactive/eai/authoutbound/client/HttpClientAccessTokenServiceByDB.java +++ b/src/main/java/com/eactive/eai/authoutbound/client/HttpClientAccessTokenServiceByDB.java @@ -31,6 +31,6 @@ public interface HttpClientAccessTokenServiceByDB { * @return 반환 된 AccessTokenVO * @exception Exception 수동 시스템 간 통신 중 발생 **/ - public Object execute(String name, Properties adapterProp, OutboundOAuthCredentialVo oAuthCredentialVo) throws Exception ; + public Object execute(String adapterGroupName, Properties adapterProp, OutboundOAuthCredentialVo oAuthCredentialVo) throws Exception ; } diff --git a/src/main/java/com/eactive/eai/authoutbound/client/impl/HttpClientAccessTokenServiceWithBase64Header.java b/src/main/java/com/eactive/eai/authoutbound/client/impl/HttpClientAccessTokenServiceWithBase64Header.java index 6316890..30ef683 100644 --- a/src/main/java/com/eactive/eai/authoutbound/client/impl/HttpClientAccessTokenServiceWithBase64Header.java +++ b/src/main/java/com/eactive/eai/authoutbound/client/impl/HttpClientAccessTokenServiceWithBase64Header.java @@ -1,6 +1,6 @@ package com.eactive.eai.authoutbound.client.impl; - + import com.eactive.eai.adapter.AdapterGroupVO; import com.eactive.eai.adapter.AdapterManager; import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey; @@ -96,8 +96,7 @@ public class HttpClientAccessTokenServiceWithBase64Header implements HttpClientA if (!UrlUtils.isAbsoluteUrl(uri)) { uri = appendPath(adapterUrl, uri); } - //String contentType = "application/json;"; // comment by jwhong - String contentType = "application/x-www-form-urlencoded"; // 광주은행 나이스지키미 + String contentType = "application/json;"; Charset charset; if (StringUtils.isNotBlank(encode)) { @@ -114,9 +113,7 @@ public class HttpClientAccessTokenServiceWithBase64Header implements HttpClientA "uri:{}, charset:{}, transactionTimeout:{}, connectionTimeout:{}, useForwardProxy:{}, forwardProxyUrl:{}", uri, encode, timeout, connectionTimeout, useForwardProxy, forwardProxyUrl); - - - + // mTLS config with default connection parameters boolean useMtls = StringUtils.equalsIgnoreCase(adapterProp.getProperty(HttpClientAdapterServiceKey.USE_MTLS), "Y"); @@ -237,17 +234,19 @@ public class HttpClientAccessTokenServiceWithBase64Header implements HttpClientA logger.debug("contentType = [" + contentType + "]"); logger.debug("encode = [" + encode + "]"); + OAuth2AccessTokenVO accessToken = new OAuth2AccessTokenVO(); try (CloseableHttpResponse response = httpClient.execute(httpPost)) { if (response.getCode() != 200) { throw new Exception("OAuth token receive status fail value= " + response.getCode()); } + + logger.info("HttpClientAccessTokenServiceWithBase64Header==>" + response.getCode()); HttpEntity entity = response.getEntity(); String responseString = EntityUtils.toString(entity, encode); - logger.debug("oauthToken RECV = [" + responseString + "]"); + logger.debug("Base64Header oauthToken RECV = [" + responseString + "]"); if (StringUtils.isNotBlank(responseString)) { - OAuth2AccessTokenVO accessToken = new OAuth2AccessTokenVO(); ObjectMapper objectMapper = new ObjectMapper(); JsonNode responseJSON = objectMapper.readTree(responseString); @@ -272,6 +271,10 @@ public class HttpClientAccessTokenServiceWithBase64Header implements HttpClientA } else { throw new Exception("oauth token return null"); } + } catch (Exception e) { + e.printStackTrace(); + logger.error("[HttpClientAccessTokenServiceWithBase64Header] retrieve accessToken exception :" + e.getMessage()); + return accessToken; } } } diff --git a/src/main/java/com/eactive/eai/authoutbound/client/impl/HttpClientAccessTokenServiceWithBase64NiceOn.java b/src/main/java/com/eactive/eai/authoutbound/client/impl/HttpClientAccessTokenServiceWithBase64NiceOn.java new file mode 100644 index 0000000..450962a --- /dev/null +++ b/src/main/java/com/eactive/eai/authoutbound/client/impl/HttpClientAccessTokenServiceWithBase64NiceOn.java @@ -0,0 +1,308 @@ + +package com.eactive.eai.authoutbound.client.impl; + +import com.eactive.eai.adapter.AdapterGroupVO; +import com.eactive.eai.adapter.AdapterManager; +import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey; +import com.eactive.eai.adapter.http.secure.HttpClient5SSLContextFactory; +import com.eactive.eai.authoutbound.OutboundOAuthCredentialVo; +import com.eactive.eai.authoutbound.client.HttpClientAccessTokenServiceByDB; +import com.eactive.eai.common.util.Logger; +import com.eactive.eai.httpouttlsinfo.HttpOutTlsInfoManager; +import com.eactive.eai.httpouttlsinfo.HttpOutTlsInfoVO; +import com.eactive.eai.util.TestModeChecker; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.openbanking.eai.common.token.AccessTokenVO; +import com.openbanking.eai.common.token.OAuth2AccessTokenVO; +import org.apache.commons.lang3.StringUtils; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.TrustAllStrategy; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.io.entity.StringEntity; +import org.apache.hc.core5.http.message.BasicNameValuePair; +import org.apache.hc.core5.ssl.SSLContextBuilder; +import org.apache.hc.core5.util.Timeout; +import org.springframework.security.web.util.UrlUtils; +import tcseed.base64; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.util.*; +import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; + +/** + * 1. 기능 : HTTP 웹 컴포넌트를 POST 방식으로 호출할 수 있는 기능을 제공한다. 2. 처리 개요 : * - 2009.11.24 + * retry 로직 제거 : 요청 3. 주의사항 + * + * @author : + * @version : v 1.0.0 + * @see : WLIAdapterFactory.java, WLIAdapter.java, WLIDefaultAdapter.java + * @since : + * + */ +public class HttpClientAccessTokenServiceWithBase64NiceOn implements HttpClientAccessTokenServiceByDB { + + public static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); + + private static boolean testMode = TestModeChecker.isTestMode(); + + /** + * 1. 기능 : 법인검증 토큰 발급에 사용 2. 처리 개요 : - 속성 정보를 설정 하고 토큰 발급 URL 호출 한다. 3. 주의사항 + * - JSON 방식 + * - ( Header Authorization Basic ) 으로 구성 + * @param adapterProp Http Adapter 속성 정보 + * @return 반환 된 AccessTokenVO + * @exception Exception 수동 시스템 간 통신 중 발생 + **/ + public AccessTokenVO execute(String name, Properties adapterProp, OutboundOAuthCredentialVo oAuthCredentialVo) + throws Exception { + AdapterGroupVO gvo = AdapterManager.getInstance().getAdapterGroupVO(name); + String adapterUrl = adapterProp.getProperty("URL"); + String encode = gvo.getMessageEncode(); + String timeoutTemp = adapterProp.getProperty("HTTP_TIME_OUT"); + if (StringUtils.isBlank(timeoutTemp)) { + timeoutTemp = "30000"; + } + String connectionTimeoutTemp = adapterProp.getProperty("CONNECTION_TIMEOUT"); + if (StringUtils.isBlank(connectionTimeoutTemp)) { + connectionTimeoutTemp = "30000"; + } + + int timeout = Integer.parseInt(timeoutTemp); + int connectionTimeout = Integer.parseInt(connectionTimeoutTemp); + long currentTime = System.currentTimeMillis(); + + String uri = oAuthCredentialVo.getUrl(); + + if (!UrlUtils.isAbsoluteUrl(uri)) { + uri = appendPath(adapterUrl, uri); + } + String contentType = "application/x-www-form-urlencoded"; // 광주은행 나이스지키미 + + Charset charset; + if (StringUtils.isNotBlank(encode)) { + charset = Charset.forName(encode); + } else { + charset = Charset.defaultCharset(); + encode = charset.toString(); + } + + boolean useForwardProxy = StringUtils.equalsIgnoreCase(adapterProp.getProperty("FORWARD_PROXY_USE_YN"), "Y"); + String forwardProxyUrl = adapterProp.getProperty("FORWARD_PROXY_URL"); + + logger.debug( + "uri:{}, charset:{}, transactionTimeout:{}, connectionTimeout:{}, useForwardProxy:{}, forwardProxyUrl:{}", + uri, encode, timeout, connectionTimeout, useForwardProxy, forwardProxyUrl); + + List formParams = new ArrayList<>(); + //formParams.add(new BasicNameValuePair("client_id", oAuthCredentialVo.getClientId())); + //formParams.add(new BasicNameValuePair("client_secret", oAuthCredentialVo.getClientSecret())); + formParams.add(new BasicNameValuePair("grant_type", oAuthCredentialVo.getGrantType())); + formParams.add(new BasicNameValuePair("scope", oAuthCredentialVo.getScope())); + //String postParameters = "grant_type=" + oAuthCredentialVo.getGrantType() + "&scope=" + oAuthCredentialVo.getScope(); + + + // mTLS config with default connection parameters + boolean useMtls = StringUtils.equalsIgnoreCase(adapterProp.getProperty(HttpClientAdapterServiceKey.USE_MTLS), + "Y"); + AdapterGroupVO adapterGroup = AdapterManager.getInstance().getAdapterGroup(name); + String clientId = adapterGroup.getClientId(); + + if (logger.isInfo()) { + logger.info("MTLS adapterGroupName. : {}, useMtls. : {}, clientId : {}", name, useMtls, clientId); + } + + int maxTotalConnections = HttpClientAdapterServiceKey.DEFAULT_MAX_TOTAL_CONNECTIONS; + int maxHostConnections = HttpClientAdapterServiceKey.DEFAULT_MAX_CONNECTION_PER_HOST; + + HttpOutTlsInfoVO mtlsInfo = null; + SSLContext sslContext = null; + PoolingHttpClientConnectionManagerBuilder cmBuilder = PoolingHttpClientConnectionManagerBuilder.create(); + PoolingHttpClientConnectionManager connectionManager = null; + + try { + if (useMtls) { + HttpOutTlsInfoManager tlsManager = HttpOutTlsInfoManager.getInstance(); + if (StringUtils.isNotEmpty(clientId)) { + mtlsInfo = tlsManager.getHttpOutTlsInfo(clientId); + } + } + + if (useMtls && mtlsInfo != null) { + String storeType = mtlsInfo.getStoreType(); + String keyStoreInfo = mtlsInfo.getKeystoreInfo(); + String keyStorePassword = mtlsInfo.getKeystorePassword(); + String trustStoreInfo = mtlsInfo.getTruststoreInfo(); + String trustStorePassword = mtlsInfo.getTruststorePassword(); + + String[] tlsVersions = null; + String[] cipherSuites = null; + + if (StringUtils.isAnyEmpty(keyStoreInfo, keyStorePassword)) { + throw new Exception("mTLS keyStore config error"); + } + + boolean skipTrust = false; + if (StringUtils.isAnyEmpty(trustStoreInfo, trustStorePassword)) { + if (logger.isWarn()) + logger.warn("Skip trustStore validation adapterGroupName : " + name); + skipTrust = true; + } + + sslContext = HttpClient5SSLContextFactory.createMTLSContextFromContent(storeType, keyStoreInfo, + keyStorePassword, trustStoreInfo, trustStorePassword, skipTrust, tlsVersions, cipherSuites); + + SSLConnectionSocketFactory sslSocketFactory = null; + if (testMode) { + sslSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); + } else { + sslSocketFactory = new SSLConnectionSocketFactory(sslContext); + } + cmBuilder.setSSLSocketFactory(sslSocketFactory); + } else { + sslContext = SSLContextBuilder.create().loadTrustMaterial(new TrustAllStrategy()).build(); + SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext); + cmBuilder.setSSLSocketFactory(csf); + } + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException | CertificateException + | IOException | UnrecoverableKeyException e) { + throw new RuntimeException(e); + } catch (Exception e) { + throw new RuntimeException(e); + } + + connectionManager = cmBuilder.build(); + connectionManager.setMaxTotal(maxTotalConnections); + connectionManager.setDefaultMaxPerRoute(maxHostConnections); + + try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();) { + HttpPost httpPost = new HttpPost(uri); + httpPost.setEntity(new UrlEncodedFormEntity(formParams, charset)); + //httpPost.setEntity(new StringEntity(postParameters, StandardCharsets.UTF_8)); + httpPost.setHeader("Content-Type", contentType+";charset=" + encode); // 중간에 ; 주어야 함 + + //HTTP HEADER에 client id, client secret를 base64Encode 한 후 추가 + String cId = oAuthCredentialVo.getClientId(); + String cSecret = oAuthCredentialVo.getClientSecret(); + String authValue = cId + ":" + cSecret; + String encodedAuth = Base64.getEncoder().encodeToString(authValue.getBytes(StandardCharsets.UTF_8)); + httpPost.setHeader("Authorization","Basic "+ encodedAuth); + + + RequestConfig.Builder requestConfigBuilder = RequestConfig.custom(); + + if (useForwardProxy) { + java.net.URL url = new java.net.URL(forwardProxyUrl); + + // 프로토콜, 호스트, 포트 추출 + String protocol = url.getProtocol(); + String host = url.getHost(); + int port = url.getPort(); + HttpHost proxy = new HttpHost(protocol, host, port); + requestConfigBuilder.setProxy(proxy); + } + + RequestConfig requestConfig = requestConfigBuilder + .setConnectTimeout(Timeout.ofMilliseconds(connectionTimeout)) + .setResponseTimeout(Timeout.ofMilliseconds(timeout)).build(); + httpPost.setConfig(requestConfig); + + logger.debug("uri = [" + uri + "]"); + logger.debug("oauthClientId = [" + oAuthCredentialVo.getClientId() + "]"); + logger.debug("oauthClientSecret = [" + oAuthCredentialVo.getClientSecret() + "]"); + logger.debug("oauthScope = [" + oAuthCredentialVo.getScope() + "]"); + logger.debug("oauthGrantType = [" + oAuthCredentialVo.getGrantType() + "]"); + logger.debug("oauthauthValue = [" + authValue + "]"); + logger.debug("oauthauthEncodedAuth = [" + encodedAuth + "]"); + logger.debug("contentType = [" + contentType + "]"); + logger.debug("encode = [" + encode + "]"); + + OAuth2AccessTokenVO accessToken = new OAuth2AccessTokenVO(); + try (CloseableHttpResponse response = httpClient.execute(httpPost)) { + if (response.getCode() != 200) { + throw new Exception("NiceOn token receive status fail value== " + response.getCode()); + } + + logger.info("HttpClientAccessTokenServiceWithBase64NiceOn==>" + response.getCode()); + + HttpEntity entity = response.getEntity(); + String responseString = EntityUtils.toString(entity, encode); + logger.debug("Base64NiceOn oauthToken RECV == [" + responseString + "]"); + + if (StringUtils.isNotBlank(responseString)) { + + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode responseJSONRtn = objectMapper.readTree(responseString); + JsonNode responseJSON = null; + String gwRsltCd = responseJSONRtn.get("dataHeader").get("GW_RSLT_CD").asText(); + + if ("1200".equals(gwRsltCd)) { + responseJSON = responseJSONRtn.get("dataBody"); + } + + if (responseJSON.has("access_token") && responseJSON.has("token_type") + && responseJSON.has("expires_in") && responseJSON.has("scope")) { + accessToken.setAccessToken(responseJSON.get("access_token").asText()); + accessToken.setTokenType(responseJSON.get("token_type").asText()); + + long expiresIn = responseJSON.get("expires_in").asLong(); + accessToken.setExpiration(new Date(currentTime + expiresIn * 1000L)); + accessToken.setScope(responseJSON.get("scope").asText()); + accessToken.setClientId(cId); + } + + if (responseJSON.has("client_use_code")) { + accessToken.setClientUseCode(responseJSON.get("client_use_code").asText()); + } + + logger.debug("NiceOn oauthToken =" + accessToken.toString()); + + return accessToken; + } else { + throw new Exception("oauth token return null"); + } + } catch (Exception e) { + e.printStackTrace(); + logger.error("[HttpClientAccessTokenServiceWithBase64NiceOn] retrieve accessToken exception :" + e.getMessage()); + return accessToken; + } + } + } + + /** + * URL에 경로를 추가합니다. 중복되는 슬래시를 방지합니다. + * + * @param baseUrl 기본 URL + * @param pathToAdd 추가할 경로 + * @return 완성된 URL 문자열 + */ + public static String appendPath(String baseUrl, String pathToAdd) { + if (!baseUrl.endsWith("/") && !pathToAdd.startsWith("/")) { + return baseUrl + "/" + pathToAdd; + } else if (baseUrl.endsWith("/") && pathToAdd.startsWith("/")) { + return baseUrl + pathToAdd.substring(1); + } else { + return baseUrl + pathToAdd; + } + } +} diff --git a/src/main/java/com/eactive/eai/authoutbound/client/impl/HttpClientAccessTokenServiceWithFixedToken.java b/src/main/java/com/eactive/eai/authoutbound/client/impl/HttpClientAccessTokenServiceWithFixedToken.java new file mode 100644 index 0000000..aae9f06 --- /dev/null +++ b/src/main/java/com/eactive/eai/authoutbound/client/impl/HttpClientAccessTokenServiceWithFixedToken.java @@ -0,0 +1,27 @@ +package com.eactive.eai.authoutbound.client.impl; + +import java.util.Properties; + +import com.eactive.eai.authoutbound.OutboundOAuthCredentialVo; +import com.eactive.eai.authoutbound.client.HttpClientAccessTokenServiceByDB; +import com.openbanking.eai.common.token.OAuth2AccessTokenVO; + +public class HttpClientAccessTokenServiceWithFixedToken implements HttpClientAccessTokenServiceByDB { + + @Override + public Object execute(String adapterGroupName, Properties adapterProp, OutboundOAuthCredentialVo oAuthCredentialVo) + throws Exception { + + OAuth2AccessTokenVO fixedAccessToken = new OAuth2AccessTokenVO(); + + fixedAccessToken.setAccessToken(oAuthCredentialVo.getClientSecret()); + fixedAccessToken.setClientId("none"); + fixedAccessToken.setClientUseCode("anyone"); + fixedAccessToken.setExpiresIn(60 * 60 * 24 * 365); //1년 + fixedAccessToken.setScope("none"); + fixedAccessToken.setTokenType("fixed"); + + return fixedAccessToken; + } + +} diff --git a/src/main/java/com/eactive/eai/authoutbound/client/impl/HttpClientAccessTokenServiceWithParam.java b/src/main/java/com/eactive/eai/authoutbound/client/impl/HttpClientAccessTokenServiceWithParam.java index 45e7c60..5eb9f07 100644 --- a/src/main/java/com/eactive/eai/authoutbound/client/impl/HttpClientAccessTokenServiceWithParam.java +++ b/src/main/java/com/eactive/eai/authoutbound/client/impl/HttpClientAccessTokenServiceWithParam.java @@ -193,7 +193,8 @@ public class HttpClientAccessTokenServiceWithParam implements HttpClientAccessTo connectionManager.setMaxTotal(maxTotalConnections); connectionManager.setDefaultMaxPerRoute(maxHostConnections); - try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();) { + // http header에 zip 제외하려면 disableContentCompression() 추가해서 제외할것 + try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).disableContentCompression().disableDefaultUserAgent().build();) { HttpPost httpPost = new HttpPost(uri); httpPost.setEntity(new UrlEncodedFormEntity(formParams, charset)); httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=" + encode); @@ -227,10 +228,10 @@ public class HttpClientAccessTokenServiceWithParam implements HttpClientAccessTo OAuth2AccessTokenVO accessToken = new OAuth2AccessTokenVO(); try (CloseableHttpResponse response = httpClient.execute(httpPost)) { if (response.getCode() != 200) { - System.out.println("OAuth token receive status fail value= "+ response.getCode()); + logger.info("OAuth token receive status fail value= " + response.getCode()); throw new Exception("OAuth token receive status fail value= " + response.getCode()); } - System.out.println("OAuth token receive status SUCCESS value= "+ response.getCode()); + logger.info("OAuth token receive status SUCCESS value= "+ response.getCode()); HttpEntity entity = response.getEntity(); String responseString = EntityUtils.toString(entity, encode); diff --git a/src/main/java/com/eactive/eai/authserver/dao/ScopeDAO.java b/src/main/java/com/eactive/eai/authserver/dao/ScopeDAO.java index 83676f6..d24d681 100644 --- a/src/main/java/com/eactive/eai/authserver/dao/ScopeDAO.java +++ b/src/main/java/com/eactive/eai/authserver/dao/ScopeDAO.java @@ -31,9 +31,15 @@ public class ScopeDAO extends BaseDAO { Map> clientEntitymap = new HashMap<>(); scopeEntities.forEach(scopeEntity -> { - HashSet set = new HashSet<>(); - String scopeId = scopeEntity.getId().getBzwksvckeyname() + scopeEntity.getId().getScopeid(); - clientEntitymap.put(scopeId, set); + String apiId = scopeEntity.getId().getBzwksvckeyname(); + HashSet scopeSet = clientEntitymap.get(apiId); + if (scopeSet == null) { + scopeSet = new HashSet(); + clientEntitymap.put(apiId, scopeSet); + } + String scopeId = scopeEntity.getId().getScopeid(); + clientEntitymap.get(apiId).add(scopeId); +// clientEntitymap.put(scopeId, set); }); return clientEntitymap; @@ -48,7 +54,7 @@ public class ScopeDAO extends BaseDAO { ScopeEntity scopeEntity = scopeLoader.findByIdBzwksvckeyname(apiId); - scopeSet.add(scopeEntity.getId().getBzwksvckeyname()); + scopeSet.add(scopeEntity.getId().getScopeid()); return scopeSet; } catch (Exception e) { throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAIAUC001")); diff --git a/src/main/java/com/eactive/eai/authserver/service/BearerTokenInfo.java b/src/main/java/com/eactive/eai/authserver/service/BearerTokenInfo.java new file mode 100644 index 0000000..390ad6d --- /dev/null +++ b/src/main/java/com/eactive/eai/authserver/service/BearerTokenInfo.java @@ -0,0 +1,49 @@ +package com.eactive.eai.authserver.service; + +import java.util.Set; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class BearerTokenInfo { + @JsonProperty("client_id") + private String clientId; + private Long expiresIn; + private Long expiresAt; + private Set scopeSet; + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public Long getExpiresIn() { + return expiresIn; + } + + public void setExpiresIn(Long expiresIn) { + this.expiresIn = expiresIn; + } + + public Long getExpiresAt() { + return expiresAt; + } + + public void setExpiresAt(Long expiresIn) { + this.expiresAt = System.currentTimeMillis() + (expiresIn * 1000); + } + + public Set getScopeSet() { + return scopeSet; + } + + public void setScopeSet(Set scopeSet) { + this.scopeSet = scopeSet; + } + + public boolean isExpired() { + return System.currentTimeMillis() > expiresAt; + } +} diff --git a/src/main/java/com/eactive/eai/authserver/service/BearerTokenService.java b/src/main/java/com/eactive/eai/authserver/service/BearerTokenService.java new file mode 100644 index 0000000..f4b29d6 --- /dev/null +++ b/src/main/java/com/eactive/eai/authserver/service/BearerTokenService.java @@ -0,0 +1,73 @@ +package com.eactive.eai.authserver.service; + +import java.security.SecureRandom; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.eactive.eai.common.session.SessionManager; +import com.eactive.eai.common.session.SessionManagerForIgnite; + +@Service +public class BearerTokenService { + + + + + public String generateCAToken(String clientId, Long expiresIn, Set scopeSet) { + + + + String token = UUID.randomUUID().toString(); + + BearerTokenInfo CATokenInfo = new BearerTokenInfo(); + CATokenInfo.setClientId(clientId); + CATokenInfo.setExpiresIn(expiresIn); + CATokenInfo.setExpiresAt(expiresIn); + CATokenInfo.setScopeSet(scopeSet); + + //CATokenStore.put(token, CATokenInfo); + + SessionManager.getInstance().putCAToken(token, CATokenInfo); + + return token; + } + + public boolean validateCA(String token) { + BearerTokenInfo CATokenInfo = SessionManager.getInstance().getCAToken(token); + if (CATokenInfo == null) return false; + + if (CATokenInfo.isExpired()) { + SessionManager.getInstance().removeCAToken(token); + return false; + }else { + return true; + } + } + + public String getClientIdFromCA(String token) { + BearerTokenInfo CATokenInfo = SessionManager.getInstance().getCAToken(token); + return CATokenInfo.getClientId(); + } + +// private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; +// private static final SecureRandom secureRandom = new SecureRandom(); +// +// public static String generateTokenString(int length) { +// // Java 8의 IntStream과 Collectors.joining을 사용한 효율적인 방법 +// return IntStream.range(0, length) +// .map(i -> secureRandom.nextInt(CHARACTERS.length())) +// .mapToObj(CHARACTERS::charAt) +// .map(String::valueOf) +// .collect(Collectors.joining()); +// } +} + diff --git a/src/main/java/com/eactive/eai/common/TransactionContextKeys.java b/src/main/java/com/eactive/eai/common/TransactionContextKeys.java index 89c19d7..2b6d870 100644 --- a/src/main/java/com/eactive/eai/common/TransactionContextKeys.java +++ b/src/main/java/com/eactive/eai/common/TransactionContextKeys.java @@ -8,4 +8,5 @@ public interface TransactionContextKeys { public static final String GUID = "GUID"; public static final String INTERFACE_ID = "INTERFACE_ID"; public static final String TRANSACTION_UUID = "TRANSACTION_UUID"; + public static final String X_LOAN_TOKEN = "X-LOAN-TOKEN"; } diff --git a/src/main/java/com/eactive/eai/common/circuitBreaker/CircuitBreakerManager.java b/src/main/java/com/eactive/eai/common/circuitBreaker/CircuitBreakerManager.java index 1b59209..4dce347 100644 --- a/src/main/java/com/eactive/eai/common/circuitBreaker/CircuitBreakerManager.java +++ b/src/main/java/com/eactive/eai/common/circuitBreaker/CircuitBreakerManager.java @@ -6,6 +6,11 @@ import com.eactive.eai.common.lifecycle.LifecycleListener; import com.eactive.eai.common.lifecycle.LifecycleSupport; import com.eactive.eai.common.property.PropManager; import com.eactive.eai.common.util.Logger; +import com.eactive.eai.custom.alarm.AlarmStateManager; +import com.eactive.eai.custom.alarm.condition.AlarmCondition; +import com.eactive.eai.custom.alarm.event.AlarmEvent; +import com.eactive.eai.custom.alarm.key.CoreAlarmKey; + import io.github.resilience4j.circuitbreaker.CircuitBreaker; import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; @@ -71,6 +76,28 @@ public class CircuitBreakerManager implements Lifecycle { circuitBreakerRegistry = CircuitBreakerRegistry.of(config); TaggedCircuitBreakerMetrics.ofCircuitBreakerRegistry(circuitBreakerRegistry).bindTo(meterRegistry); + + circuitBreakerRegistry.getEventPublisher().onEntryAdded(event -> { + CircuitBreaker cb = event.getAddedEntry(); + String apiId = cb.getName(); + + // 여기서 상태 변경 리스너를 한 번만 등록 + cb.getEventPublisher().onStateTransition(stateEvent -> { + CircuitBreaker.State from = stateEvent.getStateTransition().getFromState(); + CircuitBreaker.State to = stateEvent.getStateTransition().getToState(); + + AlarmEvent alarmEvent = AlarmEvent.builder().key(CoreAlarmKey.CircuitBreaker) + .condition(AlarmCondition.builder().build()) + .message(String.format("CircuitBreaker state changed. apiId=%s, %s -> %s", apiId, from, to)) + .build(); + + AlarmStateManager.getAlarmStateManager().onEvnet(alarmEvent); + + logger.warn("CircuitBreaker state changed. apiId={}, {} -> {}", apiId, from, to); + }); + + logger.info("Registered StateTransition listener for: {}", apiId); + }); logger.info("init CircuitBreaker - "+config); } diff --git a/src/main/java/com/eactive/eai/common/circuitBreaker/PrometheusController.java b/src/main/java/com/eactive/eai/common/circuitBreaker/PrometheusController.java index 4364a38..4df265a 100644 --- a/src/main/java/com/eactive/eai/common/circuitBreaker/PrometheusController.java +++ b/src/main/java/com/eactive/eai/common/circuitBreaker/PrometheusController.java @@ -7,7 +7,7 @@ public class PrometheusController { public PrometheusController() { - System.out.println("init"); + // System.out.println("init"); } // @GetMapping("/prometheus") diff --git a/src/main/java/com/eactive/eai/common/inflow/Bucket.java b/src/main/java/com/eactive/eai/common/inflow/Bucket.java index 51db277..b0888b0 100644 --- a/src/main/java/com/eactive/eai/common/inflow/Bucket.java +++ b/src/main/java/com/eactive/eai/common/inflow/Bucket.java @@ -6,4 +6,10 @@ public interface Bucket { public InflowTargetVO getAdapterInflowThreashold(String adapter); public InflowTargetVO getInterfaceInflowThreashold(String inter); public InflowTargetVO getInflowThreashold(String inter); + + // 그룹 관련 메서드 + /** @return null이면 통과, "PER_SECOND" 또는 "THRESHOLD"면 해당 버킷에서 차단 */ + public String isGroupPass(String groupId); + public InflowGroupVO getGroupInflowThreshold(String groupId); + public String getGroupIdByInterface(String interfaceId); } diff --git a/src/main/java/com/eactive/eai/common/inflow/CustomGroupBucket.java b/src/main/java/com/eactive/eai/common/inflow/CustomGroupBucket.java new file mode 100644 index 0000000..49d0aba --- /dev/null +++ b/src/main/java/com/eactive/eai/common/inflow/CustomGroupBucket.java @@ -0,0 +1,84 @@ +package com.eactive.eai.common.inflow; + +import io.github.bucket4j.local.LocalBucket; + +/** + * 그룹 유량제어 전용 버킷 + * 초당 임계치와 추가 임계치를 별도 버킷으로 관리하여 개별 토큰 조회 가능 + */ +public class CustomGroupBucket { + private LocalBucket perSecondBucket; // 초당 임계치 버킷 (null 가능) + private LocalBucket thresholdBucket; // 추가 임계치 버킷 (null 가능) + private InflowGroupVO groupVo; + + public CustomGroupBucket(LocalBucket perSecondBucket, LocalBucket thresholdBucket, InflowGroupVO groupVo) { + this.perSecondBucket = perSecondBucket; + this.thresholdBucket = thresholdBucket; + this.groupVo = groupVo; + } + + /** 소비 결과: 성공 */ + public static final String RESULT_PASS = null; + /** 소비 결과: 초당 임계치 초과 */ + public static final String RESULT_BLOCKED_PER_SECOND = "PER_SECOND"; + /** 소비 결과: 추가 임계치 초과 */ + public static final String RESULT_BLOCKED_THRESHOLD = "THRESHOLD"; + + /** + * 두 버킷 모두에서 토큰 소비 시도 + * @return null이면 성공, "PER_SECOND" 또는 "THRESHOLD"면 해당 버킷에서 차단 + */ + public String tryConsume() { + boolean perSecondPass = (perSecondBucket == null) || perSecondBucket.tryConsume(1); + if (!perSecondPass) { + return RESULT_BLOCKED_PER_SECOND; + } + + boolean thresholdPass = (thresholdBucket == null) || thresholdBucket.tryConsume(1); + if (!thresholdPass) { + // 초당 버킷에서 이미 소비했으므로 롤백은 불가 (Token Bucket 특성상) + // 하지만 초당 버킷은 빠르게 리필되므로 실질적 영향 미미 + return RESULT_BLOCKED_THRESHOLD; + } + + return RESULT_PASS; + } + + /** + * 초당 임계치 버킷의 사용 가능한 토큰 수 + */ + public long getPerSecondAvailableTokens() { + return (perSecondBucket != null) ? perSecondBucket.getAvailableTokens() : -1; + } + + /** + * 추가 임계치 버킷의 사용 가능한 토큰 수 + */ + public long getThresholdAvailableTokens() { + return (thresholdBucket != null) ? thresholdBucket.getAvailableTokens() : -1; + } + + public LocalBucket getPerSecondBucket() { + return perSecondBucket; + } + + public void setPerSecondBucket(LocalBucket perSecondBucket) { + this.perSecondBucket = perSecondBucket; + } + + public LocalBucket getThresholdBucket() { + return thresholdBucket; + } + + public void setThresholdBucket(LocalBucket thresholdBucket) { + this.thresholdBucket = thresholdBucket; + } + + public InflowGroupVO getGroupVo() { + return groupVo; + } + + public void setGroupVo(InflowGroupVO groupVo) { + this.groupVo = groupVo; + } +} diff --git a/src/main/java/com/eactive/eai/common/inflow/InflowControlDAO.java b/src/main/java/com/eactive/eai/common/inflow/InflowControlDAO.java index b294bc7..9cbd12e 100644 --- a/src/main/java/com/eactive/eai/common/inflow/InflowControlDAO.java +++ b/src/main/java/com/eactive/eai/common/inflow/InflowControlDAO.java @@ -12,16 +12,21 @@ import org.springframework.transaction.annotation.Transactional; import com.eactive.eai.common.dao.BaseDAO; import com.eactive.eai.common.dao.DAOException; import com.eactive.eai.common.exception.ExceptionUtil; +import com.eactive.eai.common.inflow.loader.InflowControlGroupLoader; +import com.eactive.eai.common.inflow.loader.InflowControlGroupMappingLoader; import com.eactive.eai.common.inflow.loader.InflowControlLoader; import com.eactive.eai.common.inflow.loader.InflowControlLogLogger; import com.eactive.eai.common.util.Logger; import com.eactive.eai.data.entity.onl.inflow.InflowControl; +import com.eactive.eai.data.entity.onl.inflow.InflowControlGroup; +import com.eactive.eai.data.entity.onl.inflow.InflowControlGroupMapping; import com.eactive.eai.data.entity.onl.inflow.InflowControlLog; import com.eactive.eai.data.entity.onl.inflow.InflowControlLogId; @Service @Transactional public class InflowControlDAO extends BaseDAO { + private static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); @Autowired @@ -30,6 +35,12 @@ public class InflowControlDAO extends BaseDAO { @Autowired private InflowControlLogLogger inflowControlLogLogger; + @Autowired + private InflowControlGroupLoader inflowControlGroupLoader; + + @Autowired + private InflowControlGroupMappingLoader inflowControlGroupMappingLoader; + public List getInflowAdapterList() throws DAOException { return getInflowList("01"); } @@ -132,4 +143,90 @@ public class InflowControlDAO extends BaseDAO { throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAICMM101")); } } + + // ==================== 그룹 관련 메서드 ==================== + + /** + * 활성화된 유량제어 그룹 목록 조회 + */ + public List getInflowGroupList() throws DAOException { + try { + Iterable groups = inflowControlGroupLoader.findActiveGroups(); + List groupList = new ArrayList<>(); + logger.info("[ @@ Load InflowControlGroup Configuration - starting >>>>>>>>>>>>>>>>> ]"); + + for (InflowControlGroup group : groups) { + InflowGroupVO vo = convertToGroupVO(group); + // 그룹에 속한 인터페이스 목록 조회 + Iterable mappings = inflowControlGroupMappingLoader.findActiveByGroupId(group.getGroupId()); + for (InflowControlGroupMapping mapping : mappings) { + vo.addInterface(mapping.getInterfaceId()); + } + groupList.add(vo); + } + logger.info("[>>Load InflowControlGroup Configuration - ended. count=" + groupList.size() + " ]"); + return groupList; + } catch (Exception e) { + throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAICMM101")); + } + } + + /** + * 인터페이스ID → 그룹ID 매핑 조회 + */ + public Map getInterfaceToGroupMap() throws DAOException { + try { + Iterable mappings = inflowControlGroupMappingLoader.findActiveMappings(); + Map interfaceToGroupMap = new HashMap<>(); + logger.info("[ @@ Load InterfaceToGroupMap Configuration - starting >>>>>>>>>>>>>>>>> ]"); + + for (InflowControlGroupMapping mapping : mappings) { + interfaceToGroupMap.put(mapping.getInterfaceId(), mapping.getGroupId()); + } + logger.info("[>>Load InterfaceToGroupMap Configuration - ended. count=" + interfaceToGroupMap.size() + " ]"); + return interfaceToGroupMap; + } catch (Exception e) { + throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAICMM101")); + } + } + + /** + * 특정 그룹 조회 + */ + public Map getInflowTargetByGroup(String groupId) throws DAOException { + try { + Iterable groups = inflowControlGroupLoader.findByConditions(groupId); + Map groupMap = new HashMap<>(); + logger.info("[ @@ Load InflowControlGroup getInflowTargetByGroup Configuration - starting >>>>>>>>>>>>>>>>> ]"); + + for (InflowControlGroup group : groups) { + InflowGroupVO vo = convertToGroupVO(group); + // 그룹에 속한 인터페이스 목록 조회 + Iterable mappings = inflowControlGroupMappingLoader.findActiveByGroupId(group.getGroupId()); + for (InflowControlGroupMapping mapping : mappings) { + vo.addInterface(mapping.getInterfaceId()); + } + groupMap.put(vo.getGroupId(), vo); + } + logger.info("[>>Load InflowControlGroup getInflowTargetByGroup Configuration - ended ]"); + return groupMap; + } catch (Exception e) { + throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAICMM101")); + } + } + + /** + * Entity → VO 변환 + */ + private InflowGroupVO convertToGroupVO(InflowControlGroup group) { + InflowGroupVO vo = new InflowGroupVO(); + vo.setGroupId(group.getGroupId()); + vo.setGroupName(group.getGroupName()); + vo.setThreshold(group.getThreshold() != null ? group.getThreshold() : 0); + vo.setThresholdPerSecond(group.getThresholdPerSecond() != null ? group.getThresholdPerSecond() : 0); + vo.setThresholdTimeUnit(group.getThresholdTimeUnit()); + vo.setActivate(!"0".equals(group.getUseYn())); + return vo; + } + } \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/common/inflow/InflowControlManager.java b/src/main/java/com/eactive/eai/common/inflow/InflowControlManager.java index 1f33788..f200d3e 100644 --- a/src/main/java/com/eactive/eai/common/inflow/InflowControlManager.java +++ b/src/main/java/com/eactive/eai/common/inflow/InflowControlManager.java @@ -27,6 +27,7 @@ import com.ext.eai.common.stdmessage.STDMessageKeys; import io.github.bucket4j.Bandwidth; import io.github.bucket4j.Bucket4j; +import io.github.bucket4j.local.LocalBucket; import io.github.bucket4j.local.LocalBucketBuilder; @Component @@ -40,6 +41,9 @@ public class InflowControlManager implements Lifecycle, Bucket { private Map adapterBucketList = new HashMap<>(); private Map interfaceBucketList = new HashMap<>(); + private Map groupBucketList = new HashMap<>(); + private Map interfaceToGroupMap = new HashMap<>(); + private Map groupVoMap = new HashMap<>(); private boolean started; private LifecycleSupport lifecycle = new LifecycleSupport(this); @@ -63,11 +67,9 @@ public class InflowControlManager implements Lifecycle, Bucket { */ public static Boolean isTargetOfInflowControl(EAIServerManager eaiServerManager, EAIMessage eaiMessage) { InterfaceMapper mapper = eaiMessage.getMapper(); - String inExDiv = MessageUtil.getInExDivision(mapper.getInExDivision(eaiMessage.getStandardMessage()), - eaiMessage.getInternalExternalDvcd()); // 1|2 String returnType = mapper.getSendRecvDivision(eaiMessage.getStandardMessage()); // S|R - if (STDMessageKeys.DIRECTION_IN.equals(inExDiv) && STDMessageKeys.SEND_RECV_CD_SEND.equals(returnType)) { + if (STDMessageKeys.SEND_RECV_CD_SEND.equals(returnType)) { return Boolean.valueOf(true); } @@ -91,6 +93,7 @@ public class InflowControlManager implements Lifecycle, Bucket { private void init() throws Exception { initAdapter(); initInterface(); + initGroup(); } private void initAdapter() throws Exception { @@ -121,6 +124,33 @@ public class InflowControlManager implements Lifecycle, Bucket { } } + private void initGroup() throws Exception { + groupBucketList = new HashMap<>(); + interfaceToGroupMap = new HashMap<>(); + groupVoMap = new HashMap<>(); + + List inflowGroupVoList = inflowControlDAO.getInflowGroupList(); + + for (InflowGroupVO groupVo : inflowGroupVoList) { + if (isInflowGroupTarget(groupVo)) { + CustomGroupBucket bucket = makeGroupBucket(groupVo); + if (bucket != null) { + groupBucketList.put(groupVo.getGroupId(), bucket); + groupVoMap.put(groupVo.getGroupId(), groupVo); + // 인터페이스 → 그룹 매핑 등록 + for (String interfaceId : groupVo.getInterfaceList()) { + interfaceToGroupMap.put(interfaceId, groupVo.getGroupId()); + } + } + } + } + + if (logger.isInfo()) { + logger.info("InflowControlManager] initGroup completed. groups=" + groupBucketList.size() + + ", mappings=" + interfaceToGroupMap.size()); + } + } + public synchronized void reloadAdapter() throws Exception { if (logger.isWarn()) { logger.warn("InflowControlManager] reload all Started ..."); @@ -200,6 +230,61 @@ public class InflowControlManager implements Lifecycle, Bucket { } } + public synchronized void reloadGroup() throws Exception { + if (logger.isWarn()) { + logger.warn("InflowControlManager] reloadGroup all Started ..."); + } + initGroup(); + if (logger.isWarn()) { + logger.warn("InflowControlManager] reloadGroup all finished ..."); + } + } + + public synchronized void reloadGroup(String groupId) throws Exception { + if (logger.isWarn()) { + logger.warn("InflowControlManager] reloadGroup Started ... groupId=" + groupId); + } + Map map = inflowControlDAO.getInflowTargetByGroup(groupId); + if (map != null) { + // 기존 그룹에 속한 인터페이스 매핑 제거 + Iterator> mappingIt = interfaceToGroupMap.entrySet().iterator(); + while (mappingIt.hasNext()) { + Map.Entry entry = mappingIt.next(); + if (groupId.equals(entry.getValue())) { + mappingIt.remove(); + } + } + + Iterator it = map.keySet().iterator(); + while (it.hasNext()) { + String key = it.next(); + InflowGroupVO groupVo = map.get(key); + + if (isInflowGroupTarget(groupVo)) { + CustomGroupBucket bucket = makeGroupBucket(groupVo); + if (bucket != null) { + groupBucketList.put(groupVo.getGroupId(), bucket); + groupVoMap.put(groupVo.getGroupId(), groupVo); + // 인터페이스 → 그룹 매핑 재등록 + for (String interfaceId : groupVo.getInterfaceList()) { + interfaceToGroupMap.put(interfaceId, groupVo.getGroupId()); + } + } else { + groupBucketList.remove(groupVo.getGroupId()); + groupVoMap.remove(groupVo.getGroupId()); + } + } else { + groupBucketList.remove(groupVo.getGroupId()); + groupVoMap.remove(groupVo.getGroupId()); + } + } + } + + if (logger.isWarn()) { + logger.warn("InflowControlManager] reloadGroup finished ..."); + } + } + public void stop() throws LifecycleException { // Validate and update our current component state if (!started) @@ -210,6 +295,9 @@ public class InflowControlManager implements Lifecycle, Bucket { adapterBucketList.clear(); interfaceBucketList.clear(); + groupBucketList.clear(); + interfaceToGroupMap.clear(); + groupVoMap.clear(); started = false; // Notify our interested LifecycleListeners @@ -260,6 +348,29 @@ public class InflowControlManager implements Lifecycle, Bucket { interfaceBucketList.remove(inter); } + public void removeGroup(String groupId) { + groupBucketList.remove(groupId); + groupVoMap.remove(groupId); + // 해당 그룹에 속한 인터페이스 매핑도 제거 + Iterator> it = interfaceToGroupMap.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + if (groupId.equals(entry.getValue())) { + it.remove(); + } + } + } + + public String[] getGroupAllKeys() { + Iterator it = this.groupBucketList.keySet().iterator(); + String[] groupIds = new String[this.groupBucketList.size()]; + for (int i = 0; it.hasNext(); i++) { + groupIds[i] = it.next(); + } + Arrays.sort(groupIds); + return groupIds; + } + private CustomBucket makeBucketUsingInflowVO(InflowTargetVO inflowTarget) { if (InflowControlManager.isInflowTarget(inflowTarget)) { LocalBucketBuilder builder = Bucket4j.builder(); @@ -278,6 +389,35 @@ public class InflowControlManager implements Lifecycle, Bucket { return null; } + /** + * 그룹용 버킷 생성 - 초당/추가 임계치를 별도 버킷으로 분리 + */ + private CustomGroupBucket makeGroupBucket(InflowGroupVO groupVo) { + if (!isInflowGroupTarget(groupVo)) { + return null; + } + + LocalBucket perSecondBucket = null; + LocalBucket thresholdBucket = null; + + // 초당 임계치 버킷 (별도) + if (groupVo.getThresholdPerSecond() > 0) { + perSecondBucket = Bucket4j.builder() + .addLimit(Bandwidth.simple(groupVo.getThresholdPerSecond(), Duration.ofSeconds(1))) + .build(); + } + + // 추가 임계치 버킷 (별도) + if (groupVo.getThreshold() > 0 && StringUtils.isNotBlank(groupVo.getThresholdTimeUnit())) { + thresholdBucket = Bucket4j.builder() + .addLimit(Bandwidth.simple(groupVo.getThreshold(), + InflowControlManager.getPeriod(groupVo.getThresholdTimeUnit()))) + .build(); + } + + return new CustomGroupBucket(perSecondBucket, thresholdBucket, groupVo); + } + @Override public boolean isAdapterPass(String adapter) { CustomBucket b = adapterBucketList.get(adapter); @@ -327,6 +467,30 @@ public class InflowControlManager implements Lifecycle, Bucket { return getInterfaceInflowThreashold(inter); } + @Override + public String isGroupPass(String groupId) { + CustomGroupBucket b = groupBucketList.get(groupId); + + if (b == null) + return null; + + return b.tryConsume(); + } + + @Override + public InflowGroupVO getGroupInflowThreshold(String groupId) { + return groupVoMap.get(groupId); + } + + @Override + public String getGroupIdByInterface(String interfaceId) { + return interfaceToGroupMap.get(interfaceId); + } + + public InflowGroupVO getGroupInflow(String groupId) { + return getGroupInflowThreshold(groupId); + } + public static boolean isInflowTarget(InflowTargetVO inflowTarget) { if (inflowTarget == null || !inflowTarget.isActivate()) { return false; @@ -338,6 +502,16 @@ public class InflowControlManager implements Lifecycle, Bucket { } + public static boolean isInflowGroupTarget(InflowGroupVO groupVo) { + if (groupVo == null || !groupVo.isActivate()) { + return false; + } + + return groupVo.getThresholdPerSecond() > 0 || (groupVo.getThreshold() > 0 && StringUtils + .equalsAnyIgnoreCase(groupVo.getThresholdTimeUnit(), QUOTA_TIMEUNIT_DAY, QUOTA_TIMEUNIT_SECOND, + QUOTA_TIMEUNIT_MINUTE, QUOTA_TIMEUNIT_HOUR, QUOTA_TIMEUNIT_DAY, QUOTA_TIMEUNIT_MONTH)); + } + public static Duration getPeriod(String timeUnit) { if (StringUtils.equalsIgnoreCase(timeUnit, QUOTA_TIMEUNIT_SECOND)) { return Duration.ofSeconds(1); diff --git a/src/main/java/com/eactive/eai/common/inflow/InflowGroupVO.java b/src/main/java/com/eactive/eai/common/inflow/InflowGroupVO.java new file mode 100644 index 0000000..4c05bdc --- /dev/null +++ b/src/main/java/com/eactive/eai/common/inflow/InflowGroupVO.java @@ -0,0 +1,102 @@ +package com.eactive.eai.common.inflow; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +@SuppressWarnings("serial") +public class InflowGroupVO implements Serializable { + private String groupId; + private String groupName; + private long thresholdPerSecond; + private long threshold; + private String thresholdTimeUnit; + private boolean activate; + private List interfaceList = new ArrayList<>(); + + @Override + public boolean equals(Object obj) { + if (obj instanceof InflowGroupVO) { + return groupId.equals(((InflowGroupVO) obj).getGroupId()); + } + return false; + } + + @Override + public int hashCode() { + return groupId != null ? groupId.hashCode() : 0; + } + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public long getThresholdPerSecond() { + return thresholdPerSecond; + } + + public void setThresholdPerSecond(long thresholdPerSecond) { + this.thresholdPerSecond = thresholdPerSecond; + } + + public long getThreshold() { + return threshold; + } + + public void setThreshold(long threshold) { + this.threshold = threshold; + } + + public String getThresholdTimeUnit() { + return thresholdTimeUnit; + } + + public void setThresholdTimeUnit(String thresholdTimeUnit) { + this.thresholdTimeUnit = thresholdTimeUnit; + } + + public boolean isActivate() { + return activate; + } + + public void setActivate(boolean activate) { + this.activate = activate; + } + + public List getInterfaceList() { + return interfaceList; + } + + public void setInterfaceList(List interfaceList) { + this.interfaceList = interfaceList; + } + + public void addInterface(String interfaceId) { + if (this.interfaceList == null) { + this.interfaceList = new ArrayList<>(); + } + this.interfaceList.add(interfaceId); + } + + @Override + public String toString() { + return "InflowGroupVO [groupId=" + groupId + ", groupName=" + groupName + + ", thresholdPerSecond=" + thresholdPerSecond + + ", threshold=" + threshold + + ", thresholdTimeUnit=" + thresholdTimeUnit + + ", activate=" + activate + + ", interfaceCount=" + (interfaceList != null ? interfaceList.size() : 0) + "]"; + } +} diff --git a/src/main/java/com/eactive/eai/common/logger/EAILogDAO.java b/src/main/java/com/eactive/eai/common/logger/EAILogDAO.java index 4dfc052..55b386f 100644 --- a/src/main/java/com/eactive/eai/common/logger/EAILogDAO.java +++ b/src/main/java/com/eactive/eai/common/logger/EAILogDAO.java @@ -60,7 +60,6 @@ import com.ext.eai.common.stdmessage.STDMessageKeys; // safeDB import com.eactive.ext.kjb.safedb.KjbSafedbWrapper; import com.eactive.ext.kjb.safedb.Utils; -// until here @Service @@ -240,8 +239,8 @@ public class EAILogDAO { if (svcLogLvl > 3) { loggingBizData = false; } - if (logger.isWarn()) - logger.warn("EAILogDAO] loggingBizData - " + loggingBizData); + if (logger.isInfo()) + logger.info("EAILogDAO] loggingBizData - " + loggingBizData); // 복합거래인 경우 2X1,3X1 -> 200, 2X2,3X2 -> 300 처럼 처리한다. if ((logPssSno > 200 && logPssSno < 300) || (logPssSno > 300 && logPssSno < 400)) { @@ -814,7 +813,7 @@ public class EAILogDAO { StatLog statLog = statLogMapper.toEntity(vo); statLogLogger.save(statLog); } catch (Exception e) { - logger.error("DB Logging[STATIC_LOG] Failed - " + vo.toString(), e); + //logger.error("DB Logging[STATIC_LOG] Failed - " + vo.toString(), e); throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAICLG003")); } } @@ -824,7 +823,7 @@ public class EAILogDAO { StatTranLog statTranLog = statTranLogMapper.toEntity(vo); statTranLogLogger.save(statTranLog); } catch (Exception e) { - logger.error("DB Logging[STATIC_TRANCD_LOG] Failed - " + vo.toString(), e); + //logger.error("DB Logging[STATIC_TRANCD_LOG] Failed - " + vo.toString(), e); throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAICLG003")); } } @@ -834,7 +833,7 @@ public class EAILogDAO { StatAdapterLog statAdapterLog = statAdapterLogMapper.toEntity(vo); statAdapterLogLogger.save(statAdapterLog); } catch (Exception e) { - logger.error("DB Logging[STATIC_ADAPTER_LOG] Failed - " + vo.toString(), e); + //logger.error("DB Logging[STATIC_ADAPTER_LOG] Failed - " + vo.toString(), e); throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAICLG003")); } } @@ -881,7 +880,7 @@ public class EAILogDAO { } originalAttribute = sb.toString(); - System.out.println("DB 암호화 #2 : {"+ originalAttribute +"} -> {"+attribute+"}"); + // System.out.println("DB 암호화 #2 : {"+ originalAttribute +"} -> {"+attribute+"}"); //logger.debug("DB 암호화 #2 : {} -> {}", originalAttribute, attribute); } } @@ -965,7 +964,7 @@ public class EAILogDAO { try { encryptedBytes1 = safedb.encrypt(userName, tableName, columnName1, byteMsg); - System.out.println("Encrypted Data : [" + new String(encryptedBytes1) + "]"); + // System.out.println("Encrypted Data : [" + new String(encryptedBytes1) + "]"); byte[] decryptedBytes1 = safedb.decrypt(userName, tableName, columnName1, encryptedBytes1); diff --git a/src/main/java/com/eactive/eai/common/logger/HttpAdapterExtraHeaderVo.java b/src/main/java/com/eactive/eai/common/logger/HttpAdapterExtraHeaderVo.java index 975f134..cce3a62 100644 --- a/src/main/java/com/eactive/eai/common/logger/HttpAdapterExtraHeaderVo.java +++ b/src/main/java/com/eactive/eai/common/logger/HttpAdapterExtraHeaderVo.java @@ -2,11 +2,15 @@ package com.eactive.eai.common.logger; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; @Data @AllArgsConstructor public class HttpAdapterExtraHeaderVo { private String name; - private String value; + + public HttpAdapterExtraHeaderVo() { + + } } diff --git a/src/main/java/com/eactive/eai/common/logger/HttpAdapterExtraLogVo.java b/src/main/java/com/eactive/eai/common/logger/HttpAdapterExtraLogVo.java index 4dcb0ac..318c57c 100644 --- a/src/main/java/com/eactive/eai/common/logger/HttpAdapterExtraLogVo.java +++ b/src/main/java/com/eactive/eai/common/logger/HttpAdapterExtraLogVo.java @@ -8,6 +8,7 @@ import java.util.List; public class HttpAdapterExtraLogVo { private String guid; private int serviceProcessNumber; + private String prcsDate; private String adapterGroupName; private String adapterName; private String url; diff --git a/src/main/java/com/eactive/eai/common/logger/async/HttpAdapterExtraLogH2Factory.java b/src/main/java/com/eactive/eai/common/logger/async/HttpAdapterExtraLogH2Factory.java index 7eb5292..93d9150 100644 --- a/src/main/java/com/eactive/eai/common/logger/async/HttpAdapterExtraLogH2Factory.java +++ b/src/main/java/com/eactive/eai/common/logger/async/HttpAdapterExtraLogH2Factory.java @@ -3,7 +3,7 @@ package com.eactive.eai.common.logger.async; import com.eactive.eai.common.property.PropManager; import com.eactive.eai.common.server.EAIServerManager; import com.eactive.eai.common.util.LogKeys; -import com.eactive.eai.data.entity.onl.logger.HttpAdapterExtraHeader; +//import com.eactive.eai.data.entity.onl.logger.HttpAdapterExtraHeader; import com.eactive.eai.data.entity.onl.logger.HttpAdapterExtraLog; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; @@ -66,7 +66,7 @@ public class HttpAdapterExtraLogH2Factory { // 엔티티 클래스 추가 configuration.addAnnotatedClass(HttpAdapterExtraLog.class); - configuration.addAnnotatedClass(HttpAdapterExtraHeader.class); +// configuration.addAnnotatedClass(HttpAdapterExtraHeader.class); return configuration.buildSessionFactory(); } catch (Throwable ex) { diff --git a/src/main/java/com/eactive/eai/common/logger/mapper/HttpAdapterExtraHeaderMapper.java b/src/main/java/com/eactive/eai/common/logger/mapper/HttpAdapterExtraHeaderMapper.java deleted file mode 100644 index e6eabe0..0000000 --- a/src/main/java/com/eactive/eai/common/logger/mapper/HttpAdapterExtraHeaderMapper.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.eactive.eai.common.logger.mapper; - -import com.eactive.eai.common.logger.HttpAdapterExtraHeaderVo; -import com.eactive.eai.data.entity.onl.logger.HttpAdapterExtraHeader; -import com.eactive.eai.data.mapper.BaseMapperConfig; -import com.eactive.eai.data.mapper.GenericMapper; - -import org.mapstruct.InheritInverseConfiguration; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -@Mapper(config = BaseMapperConfig.class) -public interface HttpAdapterExtraHeaderMapper extends GenericMapper { - - @Override - @Mapping(source = "id.name", target = "name") - HttpAdapterExtraHeaderVo toVo(HttpAdapterExtraHeader entity); - - @Override - @InheritInverseConfiguration - HttpAdapterExtraHeader toEntity(HttpAdapterExtraHeaderVo vo); -} diff --git a/src/main/java/com/eactive/eai/common/logger/mapper/HttpAdapterExtraLogMapper.java b/src/main/java/com/eactive/eai/common/logger/mapper/HttpAdapterExtraLogMapper.java index 73ba243..002e401 100644 --- a/src/main/java/com/eactive/eai/common/logger/mapper/HttpAdapterExtraLogMapper.java +++ b/src/main/java/com/eactive/eai/common/logger/mapper/HttpAdapterExtraLogMapper.java @@ -1,42 +1,80 @@ package com.eactive.eai.common.logger.mapper; +import com.eactive.eai.common.logger.HttpAdapterExtraHeaderVo; import com.eactive.eai.common.logger.HttpAdapterExtraLogVo; -import com.eactive.eai.data.entity.onl.logger.HttpAdapterExtraHeaderId; import com.eactive.eai.data.entity.onl.logger.HttpAdapterExtraLog; import com.eactive.eai.data.mapper.BaseMapperConfig; import com.eactive.eai.data.mapper.GenericMapper; - +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; import org.mapstruct.*; -import java.time.DayOfWeek; import java.time.LocalDate; -import java.util.Optional; +import java.time.format.DateTimeFormatter; +import java.util.Collections; +import java.util.List; -@Mapper(config = BaseMapperConfig.class, uses = HttpAdapterExtraHeaderMapper.class) -public interface HttpAdapterExtraLogMapper extends GenericMapper { +@Slf4j +@Mapper(config = BaseMapperConfig.class) +public abstract class HttpAdapterExtraLogMapper implements GenericMapper { + + private final static ObjectMapper objectMapper = new ObjectMapper(); + private static final DateTimeFormatter SDF_YYYYMMDD = DateTimeFormatter.ofPattern( "yyyyMMdd"); @Override @Mapping(source = "id.guid", target = "guid") @Mapping(source = "id.serviceProcessNumber", target = "serviceProcessNumber") - HttpAdapterExtraLogVo toVo(HttpAdapterExtraLog entity); + abstract public HttpAdapterExtraLogVo toVo(HttpAdapterExtraLog entity); @Override @InheritInverseConfiguration - HttpAdapterExtraLog toEntity(HttpAdapterExtraLogVo vo); + abstract public HttpAdapterExtraLog toEntity(HttpAdapterExtraLogVo vo); @AfterMapping - default void setHeaderIdAndWeekday(@MappingTarget HttpAdapterExtraLog entity, HttpAdapterExtraLogVo vo) { - DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek(); // 현재 요일 - int dayOfWeekNumber = dayOfWeek.getValue() % 7 + 1; // 1 (일요일)부터 7 (토요일)까지 - entity.getId().setWeekday(dayOfWeekNumber); - Optional.ofNullable(entity.getHeaderList()) - .ifPresent(headers -> headers.forEach(header -> { - if (header.getId() == null) { - header.setId(new HttpAdapterExtraHeaderId()); - } - header.getId().setWeekday(dayOfWeekNumber); - header.getId().setGuid(vo.getGuid()); - header.getId().setServiceProcessNumber(vo.getServiceProcessNumber()); - })); + public void voToEntity(@MappingTarget HttpAdapterExtraLog entity, HttpAdapterExtraLogVo vo) { + + // 1. Set weekday for partition table +// DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek(); // 현재 요일 +// int dayOfWeekNumber = dayOfWeek.getValue() % 7 + 1; // 1 (일요일)부터 7 (토요일)까지 +// entity.getId().setWeekday(dayOfWeekNumber); + +// String prcs_date = SDF_YYYYMMDD.format(ZonedDateTime.now()); + String prcs_date = LocalDate.now().format(SDF_YYYYMMDD); + entity.getId().setPrcsDate(prcs_date); + + // 2. Set Content + try { + String headerContent = objectMapper.writeValueAsString(vo.getHeaderList()); + entity.setHeaderContent(headerContent); + } catch (JsonProcessingException e) { + log.warn("Http Header Json Parse 실패", e); + entity.setHeaderContent("[{ \"error\": \"parse error\"}]"); + } + + } + + /** + * Entity → VO 변환 후 추가 처리 + */ + @AfterMapping + protected void entityToVo(@MappingTarget HttpAdapterExtraLogVo vo, HttpAdapterExtraLog entity) { + String headerContent = entity.getHeaderContent(); + if (headerContent == null || headerContent.isEmpty()) { + vo.setHeaderList(Collections.emptyList()); + return; + } + + try { + List headerList = objectMapper.readValue( + headerContent, + new TypeReference>() {} + ); + vo.setHeaderList(headerList); + } catch (JsonProcessingException e) { + log.warn("Http Header 역직렬화 실패", e); + vo.setHeaderList(Collections.emptyList()); + } } } diff --git a/src/main/java/com/eactive/eai/common/message/EAIMessage.java b/src/main/java/com/eactive/eai/common/message/EAIMessage.java index 255e974..b8345e0 100644 --- a/src/main/java/com/eactive/eai/common/message/EAIMessage.java +++ b/src/main/java/com/eactive/eai/common/message/EAIMessage.java @@ -3,7 +3,9 @@ package com.eactive.eai.common.message; import java.io.Serializable; import java.nio.charset.Charset; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import com.eactive.eai.message.StandardMessage; import com.eactive.eai.message.manager.StandardMessageManager; @@ -32,6 +34,7 @@ public class EAIMessage implements EAIMessageKeys, Serializable, Comparable(); this.svcPssSeq = 1; @@ -181,6 +185,10 @@ public class EAIMessage implements EAIMessageKeys, Serializable, Comparable transactionContextTransfer; + + /** + * [비동기 전달 전용] 컨텍스트 전달용 Map 반환 + * @see #transactionContextTransfer + */ + public Map getTransactionContextTransfer() { + return transactionContextTransfer; + } + + /** + * [비동기 전달 전용] 컨텍스트 전달용 Map 설정 + * @see #transactionContextTransfer + */ + public void setTransactionContextTransfer(Map transactionContextTransfer) { + this.transactionContextTransfer = transactionContextTransfer; + } + @Override public Object clone() throws CloneNotSupportedException { EAIMessage cloned = (EAIMessage) super.clone(); @@ -636,6 +685,8 @@ public class EAIMessage implements EAIMessageKeys, Serializable, Comparable(transactionContextTransfer)); return cloned; } diff --git a/src/main/java/com/eactive/eai/common/monitor/EAIServiceMonitor.java b/src/main/java/com/eactive/eai/common/monitor/EAIServiceMonitor.java index ce3628b..baa1c70 100644 --- a/src/main/java/com/eactive/eai/common/monitor/EAIServiceMonitor.java +++ b/src/main/java/com/eactive/eai/common/monitor/EAIServiceMonitor.java @@ -110,6 +110,9 @@ public class EAIServiceMonitor implements Lifecycle { private MonitorCleaner cleaner; private Timer cleanerTimer; + + @Autowired + private StatisticsMonitor statisticsMonitor; public static synchronized EAIServiceMonitor getInstance() { return ApplicationContextProvider.getContext().getBean(EAIServiceMonitor.class); @@ -328,6 +331,9 @@ public class EAIServiceMonitor implements Lifecycle { } } + // 통계용 에러코드 설정 + msg.setStatErrorCode(iErrorCode); + if (monitors == null) monitors = createMonitorVO(); @@ -374,6 +380,12 @@ public class EAIServiceMonitor implements Lifecycle { intfacSendTranCd, adapterGroupName); } } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + // 실시간 통계 로직 추가 + statisticsMonitor.recordStatistics(msg); + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + HashMap bwkVO = bwkClss.get(bwkCls); @@ -391,7 +403,7 @@ public class EAIServiceMonitor implements Lifecycle { logger.error(ExceptionUtil.make("RECEAICMT204", errorText)); } } - + public void resetAll() { String[] keys = getAllMonitorVOKey(); MonitorVO vo = null; diff --git a/src/main/java/com/eactive/eai/common/monitor/MonitorChecker.java b/src/main/java/com/eactive/eai/common/monitor/MonitorChecker.java index 486ef4f..48acba6 100644 --- a/src/main/java/com/eactive/eai/common/monitor/MonitorChecker.java +++ b/src/main/java/com/eactive/eai/common/monitor/MonitorChecker.java @@ -246,7 +246,7 @@ public class MonitorChecker extends TimerTask try { dao.addStaticLog(logVo); } catch(Exception e) { - if (logger.isError()) logger.error("MonitorVO.insertStaticCount ERROR. - " + e.getMessage(),e); + //if (logger.isError()) logger.error("MonitorVO.insertStaticCount ERROR. - " + e.getMessage(),e); } } @@ -280,8 +280,7 @@ public class MonitorChecker extends TimerTask try { dao.addStaticTranCdLog(tmpLogVo); } catch(Exception e) { - if (logger.isError()) logger.error("MonitorVO.insertStaticCount TRANCODE ERROR. - " - + tmpLogVo.toString() + "\n" + e.getMessage(),e); + } } @@ -294,8 +293,7 @@ public class MonitorChecker extends TimerTask try { dao.addStaticAdapterLog(tmpLogVo); } catch(Exception e) { - if (logger.isError()) logger.error("MonitorVO.insertStaticCount ADAPTER ERROR. - " - + tmpLogVo.toString() + "\n" + e.getMessage(),e); + } } } @@ -310,7 +308,7 @@ public class MonitorChecker extends TimerTask logVo.setPrcssTtmVal((statVo.getSumOfprocessTime() - statVo.getPsvSumOfPssTime())); logVo.setPsvPrcssTtmVal(statVo.getPsvSumOfPssTime()); logVo.setTotalPrcssTtmVal(statVo.getSumOfprocessTime()); - + logVo.setKey(" "); if(IFType.AA.equals(ifType)) { if( rType == 'S') { totCnt = statVo.getCnt100() + statVo.getErr100(); diff --git a/src/main/java/com/eactive/eai/common/monitor/StatisticsMonitor.java b/src/main/java/com/eactive/eai/common/monitor/StatisticsMonitor.java new file mode 100644 index 0000000..875f123 --- /dev/null +++ b/src/main/java/com/eactive/eai/common/monitor/StatisticsMonitor.java @@ -0,0 +1,9 @@ +package com.eactive.eai.common.monitor; + +import com.eactive.eai.common.message.EAIMessage; + +public interface StatisticsMonitor { + + public void recordStatistics(EAIMessage requestEaiMessage); + +} diff --git a/src/main/java/com/eactive/eai/common/routing/ElinkESBProcessProxy.java b/src/main/java/com/eactive/eai/common/routing/ElinkESBProcessProxy.java index 72e8e32..cf183ed 100644 --- a/src/main/java/com/eactive/eai/common/routing/ElinkESBProcessProxy.java +++ b/src/main/java/com/eactive/eai/common/routing/ElinkESBProcessProxy.java @@ -1,11 +1,13 @@ package com.eactive.eai.common.routing; -import com.eactive.eai.common.message.EAIMessage; -import com.eactive.eai.common.util.Logger; - import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; +import com.eactive.eai.common.context.ElinkTransactionContext; +import com.eactive.eai.common.message.EAIMessage; +import com.eactive.eai.common.message.EAIMessageKeys; +import com.eactive.eai.common.util.Logger; + /** * 1. 기능 : ElinkESBProcess를 호출하는 공통 Class @@ -42,17 +44,30 @@ public class ElinkESBProcessProxy public static EAIMessage callElinkESBProcess(String serviceURI, EAIMessage eaiMessage, boolean isLocal, Properties prop) throws Exception { EAIMessage retMsg = null; + + // [ElinkTransactionContext] 비동기 거래 시 컨텍스트 초기화 여부 판단 + // - ASYNC 거래이고, outbound Process 호출이 아닌 경우에만 초기화 + boolean shouldManageContext = eaiMessage != null + && EAIMessageKeys.ASYNC_SVC.equals(eaiMessage.getSvcTsmtUsgTp()) + && (serviceURI == null || !serviceURI.startsWith("com.eactive.eai.outbound")); + try { - if (isLocal){ + // [ElinkTransactionContext] 비동기 거래 진입점 - 컨텍스트 복원 + if (shouldManageContext) { + ElinkTransactionContext.restore(eaiMessage.getTransactionContextTransfer()); + eaiMessage.setTransactionContextTransfer(null); // 복원 후 전달용 필드 초기화 + } + + if (isLocal){ Class cl = classLocalCache.get(serviceURI); - + if(cl == null) { cl = Class.forName(serviceURI); classLocalCache.put(serviceURI, cl); } Process proc = (Process)cl.newInstance(); proc.callService(eaiMessage, prop); - + retMsg = proc.clientReturn(); }else{ if(eaiMessage == null) { @@ -62,12 +77,17 @@ public class ElinkESBProcessProxy retMsg = RemoteProxyClient.callProxyBean(eaiMessage, prop); } } - } catch( ClassNotFoundException e) { + } catch( ClassNotFoundException e) { if (logger.isError()) logger.error("ElinkProcessProxy] callElinkESBProcess["+serviceURI+"] Class Not Found Exception : "); - throw new Exception(PROXY_ERROR_CODE); - } catch( Exception e) { + throw new Exception(PROXY_ERROR_CODE); + } catch( Exception e) { if (logger.isError()) logger.error("ElinkProcessProxy] callElinkESBProcess["+serviceURI+"] Exception : "+e.getMessage(),e); - throw new Exception(PROXY_ERROR_CODE); + throw new Exception(PROXY_ERROR_CODE); + } finally { + // [ElinkTransactionContext] 비동기 거래 - 해제 + if (shouldManageContext) { + ElinkTransactionContext.clear(); + } } return retMsg; } diff --git a/src/main/java/com/eactive/eai/common/routing/FlowRouter.java b/src/main/java/com/eactive/eai/common/routing/FlowRouter.java index 466c797..8c9158f 100644 --- a/src/main/java/com/eactive/eai/common/routing/FlowRouter.java +++ b/src/main/java/com/eactive/eai/common/routing/FlowRouter.java @@ -2,6 +2,7 @@ package com.eactive.eai.common.routing; import java.util.Properties; +import com.eactive.eai.common.context.ElinkTransactionContext; import com.eactive.eai.common.exception.ExceptionUtil; import com.eactive.eai.common.message.EAIMessage; import com.eactive.eai.common.property.PropManager; @@ -136,6 +137,8 @@ public class FlowRouter } try { + // [ElinkTransactionContext] 비동기 송신 전 컨텍스트 복사 + eaiMessage.setTransactionContextTransfer(ElinkTransactionContext.getAll()); JMSSender.sendToQueue(eaiMessage, queueConFactory, routeQueueName, prop); } catch(Exception e) { if (logger.isError()) logger.error(guidLogPrefix +" process.Queue Error. Queue Name[" + routeQueueName + "]- " + e.getMessage(), e); @@ -164,6 +167,8 @@ public class FlowRouter } try { + // [ElinkTransactionContext] 비동기 송신 전 컨텍스트 복사 + eaiMessage.setTransactionContextTransfer(ElinkTransactionContext.getAll()); if (ElinkConfig.isUseCacheTopic()) { SessionManager.getInstance().putTopic(traceKey, eaiMessage); } diff --git a/src/main/java/com/eactive/eai/common/routing/Process.java b/src/main/java/com/eactive/eai/common/routing/Process.java index 9720241..0731da5 100644 --- a/src/main/java/com/eactive/eai/common/routing/Process.java +++ b/src/main/java/com/eactive/eai/common/routing/Process.java @@ -33,7 +33,9 @@ public abstract class Process { String outboundAdapterGroupName = eaiMessage.getCurrentSvcMsg().getPsvSysItfTp(); AdapterGroupVO outboundAdapterGvo = AdapterManager.getInstance().getAdapterGroupVO(outboundAdapterGroupName); standardMessage.setBizData(bizObject, outboundAdapterGvo.getMessageEncode()); - + + StandardMessageManager.getInstance().getMessageCoordinator().coordinateBeforeStandardMessageSend(standardMessage, msgType, charset); + if(MessageType.JSON.equals(msgType)) { return standardMessage.toJson(); } diff --git a/src/main/java/com/eactive/eai/common/session/SessionManager.java b/src/main/java/com/eactive/eai/common/session/SessionManager.java index fcf007a..1136743 100644 --- a/src/main/java/com/eactive/eai/common/session/SessionManager.java +++ b/src/main/java/com/eactive/eai/common/session/SessionManager.java @@ -1,5 +1,6 @@ package com.eactive.eai.common.session; +import com.eactive.eai.authserver.service.BearerTokenInfo; import com.eactive.eai.common.lifecycle.Lifecycle; import com.eactive.eai.common.lifecycle.LifecycleException; import com.eactive.eai.common.lifecycle.LifecycleListener; @@ -58,6 +59,7 @@ public abstract class SessionManager implements Lifecycle { public static final String USERID_CAHCE_NAME = "convertUserIdSession"; public static final String WEBSOCKER_CAHCE_NAME = "webSocketTimeout"; public static final String TERMINAL_CAHCE_NAME = "terminalSession"; + public static final String CAGATEWAY_TOKEN_CACHE_NAME = "CAGatewayToken"; public static final String SESSION_MANAGER_GROUPNAME = "RMIInfo"; public static final String SESSION_MANAGER_CACHETYPE = "cacheType"; @@ -66,6 +68,7 @@ public abstract class SessionManager implements Lifecycle { public static final String SESSION_MANAGER_EXPIRE_INTERVAL = "expireInterval"; public static final String SESSION_MANAGER_MULTI_GROUP_IP = "multi_group_ip"; + public static final String LOGGER_LEVEL = "loggerLevel"; public static final String SESSION_MANAGER_MULTI_GROUP_PORT = "multi_group_port"; public static final String SESSION_MANAGER_SESSION_TIMEOUT = "sessionTimeout"; public static final String SESSION_MANAGER_WEBSOCKET_TIMEOUT = "webSocketTimeout"; @@ -193,6 +196,14 @@ public abstract class SessionManager implements Lifecycle { public abstract void putLogin(String key, SessionVO value); public abstract void removeLogin(String key); + + //CA Token Cache + public abstract BearerTokenInfo getCAToken(String key); + + public abstract void putCAToken(String key, BearerTokenInfo value); + + public abstract void removeCAToken(String key); + // HTTP Cache public abstract SessionVO getHttpLogin(String key); diff --git a/src/main/java/com/eactive/eai/common/session/SessionManagerForEhcache.java b/src/main/java/com/eactive/eai/common/session/SessionManagerForEhcache.java index 571afa3..e23b465 100644 --- a/src/main/java/com/eactive/eai/common/session/SessionManagerForEhcache.java +++ b/src/main/java/com/eactive/eai/common/session/SessionManagerForEhcache.java @@ -3,6 +3,7 @@ package com.eactive.eai.common.session; import java.util.Properties; import java.util.concurrent.TimeUnit; +import com.eactive.eai.authserver.service.BearerTokenInfo; import com.eactive.eai.common.ehcache.CustomRMICacheReplicatorFactory; import com.eactive.eai.common.logger.EAIDBLogControl; import com.eactive.eai.common.message.EAIMessage; @@ -155,7 +156,7 @@ public class SessionManagerForEhcache extends SessionManager { } System.setProperty("net.sf.ehcache.skipUpdateCheck", "true"); - String bootstrapAsynchronously = "false"; + String bootstrapAsynchronously = "true"; Configuration cf = new Configuration(); FactoryConfiguration ppFactory = new FactoryConfiguration(); @@ -921,4 +922,19 @@ public class SessionManagerForEhcache extends SessionManager { sb.append(""); return sb.toString(); } + + @Override + public BearerTokenInfo getCAToken(String key) { + throw new UnsupportedOperationException(); + } + + @Override + public void putCAToken(String key, BearerTokenInfo value) { + throw new UnsupportedOperationException(); + } + + @Override + public void removeCAToken(String key) { + throw new UnsupportedOperationException(); + } } diff --git a/src/main/java/com/eactive/eai/common/session/SessionManagerForIgnite.java b/src/main/java/com/eactive/eai/common/session/SessionManagerForIgnite.java index fa397a5..e5c13b1 100644 --- a/src/main/java/com/eactive/eai/common/session/SessionManagerForIgnite.java +++ b/src/main/java/com/eactive/eai/common/session/SessionManagerForIgnite.java @@ -42,6 +42,7 @@ import org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMultic import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; import com.eactive.eai.adapter.socket2.common.Env; +import com.eactive.eai.authserver.service.BearerTokenInfo; import com.eactive.eai.common.logger.EAIDBLogControl; import com.eactive.eai.common.message.EAIMessage; import com.eactive.eai.common.property.PropManager; @@ -63,6 +64,7 @@ import ch.qos.logback.classic.Level; // 에러내용 : Failed to execute the cache operation // (all partition owners have left the grid, partition data has been lost) //------------------------------------------------------------------------------------ + public class SessionManagerForIgnite extends SessionManager { // evictMaster Instance - single socket 관련 private static IgniteCache evictMasterCache = null; @@ -72,7 +74,8 @@ public class SessionManagerForIgnite extends SessionManager { private static IgniteCache cacheTopic = null; // 비동기 거래 복원용 private static IgniteCache cacheStore = null; - + // CA Gateway Token 관리용 + private static IgniteCache cacheCAToken = null; // webSocket Login cache 정보 private static IgniteCache cacheLogin = null; // key = loginId private static IgniteCache cacheConvertUserId = null; // 단말ID 를 userID로 변경 @@ -273,7 +276,7 @@ public class SessionManagerForIgnite extends SessionManager { String server = null; // 서버정보의 IP가 시스템과 다른 ip로 설정되면 기동이 안되는 문제 if (localServerName.equals(key) && !"GW".equals(System.getProperty("spring.profiles.active", ""))) { - server = "127.0.0.1:" + discoverPort; + server = vo.getAddress() + ":" + discoverPort; } else { server = vo.getAddress() + ":" + discoverPort; } @@ -330,7 +333,32 @@ public class SessionManagerForIgnite extends SessionManager { ch.qos.logback.classic.Logger blogger = (ch.qos.logback.classic.Logger) org.slf4j.LoggerFactory .getLogger("org.apache.ignite"); - blogger.setLevel(Level.INFO); + + String loggerLevel = prpty.getProperty(SessionManager.LOGGER_LEVEL, "ERROR"); + + switch(loggerLevel) { + case "ERROR": + blogger.setLevel(Level.ERROR); + break; + case "INFO": + blogger.setLevel(Level.INFO); + break; + case "WARN": + blogger.setLevel(Level.WARN); + break; + case "DEBUG": + blogger.setLevel(Level.DEBUG); + break; + case "TRACE": + blogger.setLevel(Level.TRACE); + break; + } + + if( logger.isDebug() ) { + + logger.debug("Ignite loggerLevel = "+loggerLevel); + + } IgniteLogger log = new Slf4jLogger((org.slf4j.Logger) blogger); config.setGridLogger(log); @@ -364,6 +392,7 @@ public class SessionManagerForIgnite extends SessionManager { caches.add(initCache(config, sessionTimeout, bootstrapAsynchronously, USERID_CAHCE_NAME, 20000, false)); caches.add(initCache(config, webSocketTimeout, bootstrapAsynchronously, WEBSOCKER_CAHCE_NAME, 20000, false)); caches.add(initCache(config, sessionTimeout, bootstrapAsynchronously, TERMINAL_CAHCE_NAME, 20000, false)); + caches.add(initCache(config, 0, bootstrapAsynchronously, CAGATEWAY_TOKEN_CACHE_NAME, 1000, false)); config.setCacheConfiguration(caches.stream().toArray(CacheConfiguration[]::new)); @@ -391,6 +420,7 @@ public class SessionManagerForIgnite extends SessionManager { cacheSocket = manager.cache(ADAPTER_CAHCE_NAME); cacheTopic = manager.cache(TOPIC_CAHCE_NAME); cacheStore = manager.cache(STORE_CAHCE_NAME); + cacheCAToken = manager.cache(CAGATEWAY_TOKEN_CACHE_NAME); cacheLogin = manager.cache(LOGIN_CAHCE_NAME); httpLogin = manager.cache(HTTP_CAHCE_NAME); @@ -810,4 +840,33 @@ public class SessionManagerForIgnite extends SessionManager { sb.append(""); return sb.toString(); } + + @Override + public BearerTokenInfo getCAToken(String key) { + try { + return cacheCAToken.get(key); + } catch (Exception e) { + logger.error("getCAToken null key=" + key, e); + return null; + } + } + + @Override + public void putCAToken(String key, BearerTokenInfo value) { + if (logger.isWarn()) { + logger.warn("Put CAToken key - " + key + ", CAToken - " + value.toString()); + } + cacheCAToken.put(key, value); + + } + + @Override + public void removeCAToken(String key) { + if (logger.isWarn()) { + logger.warn("Remove CAToken key - " + key); + } + cacheCAToken.remove(key); + + } + } diff --git a/src/main/java/com/eactive/eai/common/state/ElinkStateManager.java b/src/main/java/com/eactive/eai/common/state/ElinkStateManager.java index 7f69873..31823bc 100644 --- a/src/main/java/com/eactive/eai/common/state/ElinkStateManager.java +++ b/src/main/java/com/eactive/eai/common/state/ElinkStateManager.java @@ -19,7 +19,7 @@ public class ElinkStateManager { if (logger != null) { logger.warn(message); } - System.out.println(DatetimeUtil.getCurrentTime() + " " + LOG_PREFIX + message); + // System.out.println(DatetimeUtil.getCurrentTime() + " " + LOG_PREFIX + message); } public static synchronized ElinkStateManager getInstance() { diff --git a/src/main/java/com/eactive/eai/common/stdmessage/STDMessageDAO.java b/src/main/java/com/eactive/eai/common/stdmessage/STDMessageDAO.java index 8b8c320..307845c 100644 --- a/src/main/java/com/eactive/eai/common/stdmessage/STDMessageDAO.java +++ b/src/main/java/com/eactive/eai/common/stdmessage/STDMessageDAO.java @@ -12,9 +12,13 @@ import org.springframework.transaction.annotation.Transactional; import com.eactive.eai.common.dao.BaseDAO; import com.eactive.eai.common.dao.DAOException; import com.eactive.eai.common.exception.ExceptionUtil; +import com.eactive.eai.common.message.EAIMessage; +import com.eactive.eai.common.message.EAIMessageDAO; +import com.eactive.eai.common.message.EAIMessageManager; import com.eactive.eai.common.stdmessage.loader.StandardMessageInfoLoader; import com.eactive.eai.common.stdmessage.loader.StandardMessageRestoreService; import com.eactive.eai.common.util.Logger; +import com.eactive.eai.data.entity.onl.message.EAIMessageEntity; import com.eactive.eai.data.entity.onl.stdmessage.StandardMessageInfo; import com.eactive.eai.data.entity.onl.stdmessage.StandardMessageItem; import com.eactive.eai.data.entity.onl.stdmessage.StandardMessageRestore; @@ -224,4 +228,71 @@ public class STDMessageDAO extends BaseDAO { throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAICKE111")); } } + + // jwhong 추가 + public StandardMessageInfo getSTDMsgByPath(String apiFullPath) throws DAOException { + Optional optional = standardMessageInfoLoader.findByApiFullPath(apiFullPath); + return optional.orElseThrow(() -> new DAOException("해당 full path의 TSEAIHS04 에 데이터가 없습니다.")); + } + + // Path Variable 처리를 위한 Method/FullURL 베이스 처리. + public HashMap getAllStdMsgInfos() throws DAOException { + HashMap apiInfo = new HashMap<>(); + + EAIMessageManager eaiManager = EAIMessageManager.getInstance(); + EAIMessage eaiMsg = null; + STDMsgInfoAddOnVO vo = null; + try { + List list = standardMessageInfoLoader.findAll(); + for (StandardMessageInfo info : list) { + eaiMsg = eaiManager.getEAIMessage(info.getEaisvcname()); + vo = new STDMsgInfoAddOnVO(); + vo.setBzwksvckeyname(info.getBzwksvckeyname()); + vo.setEaiSvcCd(info.getEaisvcname()); + vo.setApiFullPath(info.getApifullpath()); + vo.setAdapterGroupName(eaiMsg.getSngSysItfTp()); + apiInfo.put(vo.getApiFullPath(), vo); + } + return apiInfo; + } catch (Exception e) { + throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAICKE102"), e); + } + } + + public STDMsgInfoAddOnVO getUrlStdMsgInfo(String apiFullPath) throws DAOException { + EAIMessageManager eaiManager = EAIMessageManager.getInstance(); + EAIMessage eaiMsg = null; + STDMsgInfoAddOnVO vo = null; + try { + Optional optional = standardMessageInfoLoader.findByApiFullPath(apiFullPath); + if (optional.isPresent()) { + StandardMessageInfo info = optional.get(); + eaiMsg = eaiManager.getEAIMessage(info.getEaisvcname()); + vo.setBzwksvckeyname(info.getBzwksvckeyname()); + vo.setEaiSvcCd(info.getEaisvcname()); + vo.setApiFullPath(info.getApifullpath()); + vo.setAdapterGroupName(eaiMsg.getSngSysItfTp()); + } + return vo; + } catch (Exception e) { + throw new DAOException("RECEAICKE110"); + } + } + + public String getApiFullPath(String serviceKey) throws DAOException { + try { + Optional optional = standardMessageInfoLoader.findById(serviceKey); + if (optional.isPresent()) { + StandardMessageInfo info = optional.get(); + return info.getApifullpath(); + } else { + throw new DAOException("RECEAICKE110"); + } + } catch (DAOException e) { + throw e; + } catch(Exception e) { + throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAICKE111")); + } + } + } diff --git a/src/main/java/com/eactive/eai/common/stdmessage/STDMessageManager.java b/src/main/java/com/eactive/eai/common/stdmessage/STDMessageManager.java index 08d440d..ed14e24 100644 --- a/src/main/java/com/eactive/eai/common/stdmessage/STDMessageManager.java +++ b/src/main/java/com/eactive/eai/common/stdmessage/STDMessageManager.java @@ -30,6 +30,8 @@ public class STDMessageManager implements Lifecycle { private HashMap headers = new HashMap<>(); private HashMap headersForPathVariables = new HashMap<>(); + private HashMap headerUrls = new HashMap<>(); + private HashMap headerUrlsForPathVariables = new HashMap<>(); private boolean started; private LifecycleSupport lifecycle = new LifecycleSupport(this); @@ -60,6 +62,14 @@ public class STDMessageManager implements Lifecycle { headersForPathVariables.put(entry.getKey(), entry.getValue()); } } + // url base로 처리 추가. + headerUrls = sTDMessageDAO.getAllStdMsgInfos(); + headerUrlsForPathVariables.clear(); + for (Map.Entry entry : headerUrls.entrySet()) { + if (isPathVariable(entry.getKey())) { + headerUrlsForPathVariables.put(entry.getKey(), entry.getValue()); + } + } } public static boolean isPathVariable(String key) { @@ -86,6 +96,17 @@ public class STDMessageManager implements Lifecycle { } else { throw new Exception("STDMessage not found in Database : key[" + keyName + "]"); } + // url base로 처리 추가. + String apiFullPath = sTDMessageDAO.getApiFullPath(keyName); + STDMsgInfoAddOnVO msgUrl = sTDMessageDAO.getUrlStdMsgInfo(apiFullPath); + if (msgUrl != null) { + headerUrls.put(apiFullPath, msgUrl); + if (isPathVariable(apiFullPath)) { + headerUrlsForPathVariables.put(apiFullPath, msgUrl); + } + } else { + throw new Exception("STDMessage not found in Database : key[" + apiFullPath + "]"); + } } public void stop() throws LifecycleException { @@ -145,6 +166,41 @@ public class STDMessageManager implements Lifecycle { return null; } + // apiFullPath 기준 Path Variable 조회 + public StandardMessage getSTDMessageForUrlPathVariable(String apiFullPath) { + String matchedKey = getMatchedUrlPathVariable(apiFullPath); + if (matchedKey != null) { + return getSTDMessage(matchedKey); + } else { + return null; + } + } + + public String getMatchedUrlPathVariable(String apiFullPath) { + AntPathMatcher matcher = new AntPathMatcher(); + for (String key : headerUrlsForPathVariables.keySet()) { + if (matcher.match(key, apiFullPath)) { + return key; + } + } + return null; + } + + public STDMsgInfoAddOnVO getStdMsgInfoAddOn(String apiFullPath) { + for (Map.Entry entry : headerUrls.entrySet()) { + if (StringUtils.equals(entry.getKey(), apiFullPath) ) { + return entry.getValue(); + } + } + String apiPathVariable = getMatchedUrlPathVariable(apiFullPath); + for (Map.Entry entry : headerUrlsForPathVariables.entrySet()) { + if (StringUtils.equals(entry.getKey(), apiPathVariable) ) { + return entry.getValue(); + } + } + return null; + } + public String[] getAllSTDMessageKeys() { String[] ks = new String[this.headers.size()]; Iterator it = this.headers.keySet().iterator(); @@ -163,6 +219,19 @@ public class STDMessageManager implements Lifecycle { } return al; } + + // 업무서비스키로 기 동록된 apiFullPath 가져오기. + public String getApiFullPath(String serviceKey) { + String apiFullPath = ""; + for (Map.Entry entry : headerUrls.entrySet()) { + STDMsgInfoAddOnVO msgVO = entry.getValue(); + if (StringUtils.equals(serviceKey, msgVO.getBzwksvckeyname())) { + apiFullPath = msgVO.getApiFullPath(); + return apiFullPath; + } + } + return null; + } public void addSTDMessage(StandardMessage msg) { this.headers.put(msg.getServiceKey(), msg); @@ -175,5 +244,9 @@ public class STDMessageManager implements Lifecycle { public synchronized void removeSTDMessage(String bwkSvcKey) { this.headers.remove(bwkSvcKey); this.headersForPathVariables.remove(bwkSvcKey); + // apiFullPath 기준 등록정보 삭제. + String apiFullPath = getApiFullPath(bwkSvcKey); + this.headerUrls.remove(apiFullPath); + this.headerUrlsForPathVariables.remove(apiFullPath); } } diff --git a/src/main/java/com/eactive/eai/common/stdmessage/STDMsgInfoAddOnVO.java b/src/main/java/com/eactive/eai/common/stdmessage/STDMsgInfoAddOnVO.java new file mode 100644 index 0000000..cf9aa5a --- /dev/null +++ b/src/main/java/com/eactive/eai/common/stdmessage/STDMsgInfoAddOnVO.java @@ -0,0 +1,40 @@ +package com.eactive.eai.common.stdmessage; + +import org.json.simple.JSONObject; + +public class STDMsgInfoAddOnVO { + + private String bzwksvckeyname = null;// 업무서비스키 + private String eaiSvcCd = null;// EAI서비스코드 + private String apiFullPath = null;// Method/Url + private String adapterGroupName = null;// 인바운드 어댑터그룹 + + public String getBzwksvckeyname() { + return bzwksvckeyname; + } + public void setBzwksvckeyname(String bzwksvckeyname) { + this.bzwksvckeyname = bzwksvckeyname; + } + + public String getEaiSvcCd() { + return eaiSvcCd; + } + public void setEaiSvcCd(String eaiSvcCd) { + this.eaiSvcCd = eaiSvcCd; + } + + public String getApiFullPath() { + return apiFullPath; + } + public void setApiFullPath(String apiFullPath) { + this.apiFullPath = apiFullPath; + } + + public String gAdapterGroupName() { + return adapterGroupName; + } + public void setAdapterGroupName(String adapterGroupName) { + this.adapterGroupName = adapterGroupName; + } + +} diff --git a/src/main/java/com/eactive/eai/common/util/HttpAdapterExtraLogUtil.java b/src/main/java/com/eactive/eai/common/util/HttpAdapterExtraLogUtil.java index 8251e53..2797a88 100644 --- a/src/main/java/com/eactive/eai/common/util/HttpAdapterExtraLogUtil.java +++ b/src/main/java/com/eactive/eai/common/util/HttpAdapterExtraLogUtil.java @@ -1,6 +1,8 @@ package com.eactive.eai.common.util; +import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -34,7 +36,13 @@ public class HttpAdapterExtraLogUtil { } public static void insertHttpAdapterExtraLog(String guid, int serviceProcessNumber, String adapterGroupName, String adapterName, Header[] headers, String url, String httpMethod, int httpStatus){ - List headerVoList = convertHeaderToListOfHttpAdapterExtraHeaderVo(headers); + + List headerVoList = new ArrayList(); + + if ( headers != null && headers.length != 0 ) { + headerVoList = convertHeaderToListOfHttpAdapterExtraHeaderVo(headers); + } + insertHttpAdapterExtraLog(guid, serviceProcessNumber, adapterGroupName, adapterName, headerVoList, url, httpMethod, httpStatus); } @@ -50,17 +58,13 @@ public class HttpAdapterExtraLogUtil { httpAdapterExtraLogVo.setHttpMethod(httpMethod); for (HttpAdapterExtraHeaderVo httpAdapterExtraHeaderVo : headerVoList) { - String name = httpAdapterExtraHeaderVo.getName(); - if(StringUtils.isNotBlank(name) && "authorization".equals(name.toLowerCase())) { - httpAdapterExtraHeaderVo.setValue("{hidden}"); - } + String value = httpAdapterExtraHeaderVo.getValue(); - if(StringUtils.isNotBlank(value) && value.length() > 400) { - value = value.substring(0, 400) + "..."; - httpAdapterExtraHeaderVo.setValue(value); - }else if(value == null){ - httpAdapterExtraHeaderVo.setValue(" "); - } + + if (value == null) { + httpAdapterExtraHeaderVo.setValue(" "); + } + } httpAdapterExtraLogVo.setHeaderList(headerVoList); httpAdapterExtraLogVo.setHttpStatus(httpStatus); @@ -101,14 +105,15 @@ public class HttpAdapterExtraLogUtil { public static List convertHeaderToListOfHttpAdapterExtraHeaderVo(Header[] headers) { Set seenNames = new HashSet<>(); return Arrays.stream(headers) - .filter(header -> seenNames.add(header.getName())) // 중복된 이름을 스킵 +// .filter(header -> seenNames.add(header.getName())) // 중복된 이름을 스킵 .map(header -> new HttpAdapterExtraHeaderVo(header.getName(), header.getValue())) .collect(Collectors.toList()); } public static List convertMapToListOfHttpAdapterExtraHeaderVo(Map map) { return map.entrySet().stream() - .map(entry -> new HttpAdapterExtraHeaderVo(entry.getKey().toString(), entry.getValue().toString())) + .map(entry -> new HttpAdapterExtraHeaderVo(entry.getKey().toString(), entry.getValue() == null ? "" : entry.getValue().toString())) .collect(Collectors.toList()); } + } diff --git a/src/main/java/com/eactive/eai/common/util/JMSSender.java b/src/main/java/com/eactive/eai/common/util/JMSSender.java index c775498..73b15d6 100644 --- a/src/main/java/com/eactive/eai/common/util/JMSSender.java +++ b/src/main/java/com/eactive/eai/common/util/JMSSender.java @@ -1,5 +1,5 @@ package com.eactive.eai.common.util; - + import java.util.Iterator; import java.util.Properties; @@ -69,6 +69,7 @@ public class JMSSender { throw new Exception("qconFactory not found -" + connectionFactory); queue = locator.getQueue(destination); + logger.info("resolved quene name is:" + "["+ queue + "]"); qsender = qsession.createSender(queue); ObjectMessage msg = qsession.createObjectMessage(); diff --git a/src/main/java/com/eactive/eai/common/util/Jsons.java b/src/main/java/com/eactive/eai/common/util/Jsons.java new file mode 100644 index 0000000..a9379f4 --- /dev/null +++ b/src/main/java/com/eactive/eai/common/util/Jsons.java @@ -0,0 +1,10 @@ +package com.eactive.eai.common.util; + +import com.google.gson.Gson; + +public final class Jsons { + + private Jsons() {} + + public static final Gson GSON = new Gson(); +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/common/util/MessageUtil.java b/src/main/java/com/eactive/eai/common/util/MessageUtil.java index fc5c9a9..82e3980 100644 --- a/src/main/java/com/eactive/eai/common/util/MessageUtil.java +++ b/src/main/java/com/eactive/eai/common/util/MessageUtil.java @@ -1,5 +1,25 @@ package com.eactive.eai.common.util; +import java.io.BufferedInputStream; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.util.Iterator; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; + +import org.apache.commons.lang3.StringUtils; +import org.apache.tools.ant.filters.StringInputStream; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; + import com.eactive.eai.common.EAIKeys; import com.eactive.eai.common.message.MessageType; import com.eactive.eai.common.monitor.EAIServiceMonitor; @@ -10,30 +30,17 @@ import com.eactive.eai.transformer.util.ISO8583DumpUtil; import com.ext.eai.common.stdmessage.STDMessageErrorKeys; import com.jayway.jsonpath.JsonPath; import com.solab.iso8583.IsoMessage; -import org.apache.commons.lang3.StringUtils; -import org.apache.tools.ant.filters.StringInputStream; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.JSONValue; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathFactory; -import java.io.BufferedInputStream; -import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; -import java.util.Iterator; -import java.util.List; -import java.util.Map; public final class MessageUtil { static Logger logger = LoggerFactory.getLogger(MessageUtil.class); + //public static final String ERROR_MESSAGE_DEFAULT_FORMAT = "{\"error\":{\"code\":\"%s\",\"message\":\"%s\"}}"; + public static final String ERROR_MESSAGE_DEFAULT_FORMAT = "{\"code\":\"%s\",\"message\":\"%s\"}"; + + public static final String ERROR_CODE_AP_ERROR = "E.GW.AP_ERROR"; + public static final String ERROR_CODE_AUTH_FAIL = "E.GW.AUTH_FAIL"; + public static final String ERROR_CODE_SERVICE_NOT_FOUND = "E.GW.SERVICE_NOT_FOUND"; + private MessageUtil() { } @@ -492,12 +499,10 @@ public final class MessageUtil { public static String makeErrorMessageByMessageType(String msgType, String msgCharset, String code, String msg, String errorFormat) { - if (StringUtils.equals(msgType, MessageType.JSON)) { - return makeJsonErrorMessage(code, msg, errorFormat); - } else if (StringUtils.equals(msgType, MessageType.XML)) { + if (StringUtils.equals(msgType, MessageType.XML)) { return makeXmlErrorMessage(code, msg, msgCharset, errorFormat); } else { - return "[errCd]" + code + "[/errCd]" + "[errMsg]" + msg + "[/errMsg]"; + return makeJsonErrorMessage(code, msg, errorFormat); } } @@ -510,14 +515,17 @@ public final class MessageUtil { } public static String makeJsonErrorMessage(String code, String msg, String errorFormat) { - if (StringUtils.isNotBlank(errorFormat)) { - try { - return String.format(errorFormat, code, JSONValue.escape(msg)); - } catch (Exception e) { - logger.error(e.getMessage()); - } + if (StringUtils.isBlank(errorFormat)) { + errorFormat = ERROR_MESSAGE_DEFAULT_FORMAT; + } + + // errorFormat에 %s가 1개만 있으면 msg만, 2개 이상이면 code, msg 전달 + int paramCount = StringUtils.countMatches(errorFormat, "%s"); + if (paramCount == 1) { + return String.format(errorFormat, JSONValue.escape(msg)); + } else { + return String.format(errorFormat, code, JSONValue.escape(msg)); } - return String.format("{\"error\":\"%s\",\"error_description\":\"%s\"}", code, JSONValue.escape(msg)); } public static String makeXmlErrorMessage(String code, String msg, String charset, String errorFormat) { diff --git a/src/main/java/com/eactive/eai/common/web/AppInitializer.java b/src/main/java/com/eactive/eai/common/web/AppInitializer.java index 7b1e723..e10fcb4 100644 --- a/src/main/java/com/eactive/eai/common/web/AppInitializer.java +++ b/src/main/java/com/eactive/eai/common/web/AppInitializer.java @@ -6,6 +6,8 @@ import java.lang.reflect.Method; import java.net.InetAddress; import java.nio.charset.Charset; import java.rmi.RemoteException; +import java.security.Security; +import java.util.Arrays; import javax.sql.DataSource; @@ -203,6 +205,8 @@ public class AppInitializer implements InitializingBean, DisposableBean { * eLink FrameWork의 웹어플리케이션이 될 때 초기화 작업을 수행 **/ private void init() { + + ElinkStateManager.getInstance().setWaitMaxMs(shutdownWaitSecs * 1000); ElinkStateManager.getInstance().setSleepIntervalMs(shutdownWaitIntervalMs); ElinkStateManager.getInstance().starting(); @@ -399,6 +403,11 @@ public class AppInitializer implements InitializingBean, DisposableBean { if (pRmiServicePort != null) { this.rmiServicePort = pRmiServicePort; } + + Arrays.stream(Security.getProviders()) + .forEach(p -> System.out.println("JavaSecurityProviders name=" + p.getName() +" / info="+ p.getInfo() +" / version="+ p.getVersion())); + + Security.removeProvider("BC"); try { logger.warn("\n@@ eLink RMI Register Port : " + rmiPort + ", Service Port : " + rmiServicePort); diff --git a/src/main/java/com/eactive/eai/custom/alarm/AlarmService.java b/src/main/java/com/eactive/eai/custom/alarm/AlarmService.java new file mode 100644 index 0000000..7f26e67 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/AlarmService.java @@ -0,0 +1,132 @@ +package com.eactive.eai.custom.alarm; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; + +import org.springframework.stereotype.Service; + +import com.eactive.eai.common.property.PropManager; +import com.eactive.eai.common.util.Jsons; +import com.eactive.eai.common.util.Logger; +import com.eactive.eai.custom.alarm.key.AlarmKey; +import com.eactive.eai.custom.alarm.key.DynamicAlarmKey; +import com.eactive.eai.custom.alarm.policy.AlarmPolicy; +import com.eactive.eai.custom.alarm.policy.CounterPolicy; +import com.eactive.eai.custom.alarm.policy.SendPolicy; +import com.eactive.eai.custom.alarm.policy.TimerPolicy; +import com.google.gson.JsonObject; + +@Service +public class AlarmService { + + protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); + + final static String ALARM_GROUP = "Alarm"; + final static String ALARM_KEY = "{ALARM}"; + final static String ALARM_RECIVER = "{RECIVER}"; + final static String ALARM_EABLE = "enable.alarm"; + + public Map getAlarmPolicy() { + + Map policyMap = new HashMap(); + + try { + + Properties props = PropManager.getInstance().getProperties(ALARM_GROUP); + + props.forEach((key, value) -> { + + String keyName = (String) key; + String configStr = (String) value; + + if (keyName.contains(ALARM_KEY)) { + + AlarmPolicy newPolicy = buildAlarmPolicy(keyName, configStr); + policyMap.put(newPolicy.getAlarmKey(), newPolicy); + + } + }); + + } catch (Exception e) { + logger.warn("getAlarmPolicy fail.", e); + return Collections.EMPTY_MAP; + } + + return policyMap; + } + + public boolean isAlarmEnabled() { + return Optional.ofNullable(PropManager.getInstance().getProperty(ALARM_GROUP, ALARM_EABLE)) + .map(Boolean::valueOf).orElse(false); + } + + private AlarmPolicy buildAlarmPolicy(String key, String configJsonStr) { + + JsonObject alarmConfig = Jsons.GSON.fromJson(configJsonStr, JsonObject.class); + + String policyType = alarmConfig.get("type").getAsString(); + int thresholdCount = Optional.ofNullable(alarmConfig.get("thresholdCount")).map(i -> i.getAsInt()).orElse(5); + int timeWindowSec = Optional.ofNullable(alarmConfig.get("timeWindowSec")).map(i -> i.getAsInt()).orElse(60); + + AlarmPolicy alarmPolicy; + + if ("count".equals(policyType)) { + alarmPolicy = CounterPolicy.builder().alarmKey(new DynamicAlarmKey(key)).thresholdCount(thresholdCount) + .build(); + } else { + alarmPolicy = TimerPolicy.builder().alarmKey(new DynamicAlarmKey(key)).timeWindowMs(timeWindowSec * 1000) + .build(); + } + + return alarmPolicy; + + } + + public Map getSendPolicy() { + + Map policyMap = new HashMap(); + + try { + + Properties props = PropManager.getInstance().getProperties(ALARM_GROUP); + + props.forEach((key, value) -> { + String keyName = (String) key; + String configStr = (String) value; + + if (!keyName.contains(ALARM_RECIVER)) + return; + + SendPolicy newPolicy = buildSendPolicy(keyName, configStr); + + policyMap.put(newPolicy.getAlarmKey(), newPolicy); + + }); + + } catch (Exception e) { + logger.warn("getSendPolicy fail.", e); + return Collections.EMPTY_MAP; + } + + return policyMap; + } + + private SendPolicy buildSendPolicy(String key, String configStr) { + + List reciverList = Optional.ofNullable(configStr).map(t -> Arrays.asList(t.split(","))) + .orElse(Collections.EMPTY_LIST); + + key = key.replace(ALARM_RECIVER, "").trim() + "{ALARM}"; + + SendPolicy sendPolicy = new SendPolicy(key, reciverList); + + return sendPolicy; + + } +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/AlarmStateManager.java b/src/main/java/com/eactive/eai/custom/alarm/AlarmStateManager.java new file mode 100644 index 0000000..f03ae3b --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/AlarmStateManager.java @@ -0,0 +1,146 @@ +package com.eactive.eai.custom.alarm; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.eactive.eai.common.util.ApplicationContextProvider; +import com.eactive.eai.common.util.Logger; +import com.eactive.eai.custom.alarm.event.AlarmEvent; +import com.eactive.eai.custom.alarm.key.AlarmKey; +import com.eactive.eai.custom.alarm.policy.AlarmPolicy; +import com.eactive.eai.custom.alarm.policy.SendPolicy; +import com.eactive.eai.custom.alarm.ums.UmsSendManager; +import com.eactive.eai.custom.alarm.ums.UmsService; +import com.eactive.eai.custom.alarm.ums.payload.ObpMonitoringUmsTemplate; +import com.eactive.eai.custom.alarm.ums.payload.UmsRequestPayload; + +@Component +public class AlarmStateManager { + + List registerAlarmList = new ArrayList(); + + private final ScheduledExecutorService scheduler; + + protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); + + private static AlarmStateManager alarmStateManager; + + @Autowired + AlarmService alarmService; + + @Autowired + UmsSendManager umsSendManager; + + public static AlarmStateManager getAlarmStateManager() { + if (alarmStateManager == null) { + alarmStateManager = ApplicationContextProvider.getContext().getBean(AlarmStateManager.class); + } + return alarmStateManager; + } + + public AlarmStateManager() { + + this.scheduler = Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r); + t.setName("AlarmStateManager-worker"); + t.setDaemon(false); + return t; + }); + + scheduler.scheduleWithFixedDelay(() -> { + + try { + // === 여기에 지속 실행할 로직 === + fireAlarm(); + + } catch (Throwable e) { + // 반드시 예외 잡기 (안 잡으면 스케줄 자체가 죽음) + logger.error("fireAlarm fail", e); + } + + }, 0, 5, TimeUnit.SECONDS); // 최초 0초, 이후 5초 간격 + } + + public void onEvnet(AlarmEvent alaramEvent) { + + Optional existEvent = registerAlarmList.stream().filter(e -> e.equals(alaramEvent)).findFirst(); + + if (existEvent.isPresent()) { + AlarmEvent event = existEvent.get(); + event.onOcurr(); + } else { + registerAlarmList.add(alaramEvent); + } + + } + + private void fireAlarm() { + + Map alarmPolicyMap = alarmService.getAlarmPolicy(); + + Map sendPolicyMap = alarmService.getSendPolicy(); + + Iterator iterator = registerAlarmList.iterator(); + + while (iterator.hasNext()) { + AlarmEvent event = iterator.next(); + AlarmPolicy alarmPolicy = alarmPolicyMap.get(event.getKey()); + + if (alarmPolicy != null && alarmPolicy.isAlarmTriggered(event)) { + // 알람 발송 로직 + SendPolicy sendPolicy = sendPolicyMap.get(event.getKey()); + if (alarmService.isAlarmEnabled()) { + send(sendPolicy, event); + } else { + logger.info("Alarm is disabled, event = {}, policy = {}", event, sendPolicy); + } + // 리스트에서 안전하게 제거 + iterator.remove(); + } else { // 트리거 조건이 안되더라도, 이벤트발생한지 오래 되었으면 제거하여 OOM 예방. + + long firstOcurredAt = event.getCondition().getOcurredAt(); + + long diffInMs = System.currentTimeMillis() - firstOcurredAt; + + if (diffInMs >= TimeUnit.MINUTES.toMillis(60)) { // 1시간 지난거면 삭제 + iterator.remove(); + } + } + } + + } + + private void send(SendPolicy sendPolicy, AlarmEvent event) { + + UmsRequestPayload payload = null; + + try { + + List cellPhoneList = sendPolicy.getCellPhoneList(); + + for (String cellPhone : cellPhoneList) { + + payload = UmsRequestPayload.builder() + .content(ObpMonitoringUmsTemplate.builder().message(event.getMessage()).build()) + .cellphone(cellPhone).build(); + logger.info("Alarm is disabled, UmsRequestPayload = {}", payload); + + umsSendManager.enqueue(payload); + } + + } catch (Exception e) { + logger.error(String.format("Alarm message delivery failed (UMS), payload=%s", payload), e); + + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/custom/alarm/condition/AlarmCondition.java b/src/main/java/com/eactive/eai/custom/alarm/condition/AlarmCondition.java new file mode 100644 index 0000000..2313fdf --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/condition/AlarmCondition.java @@ -0,0 +1,21 @@ +package com.eactive.eai.custom.alarm.condition; + +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; + +@Builder +@Getter +@ToString +public class AlarmCondition { + final long ocurredAt = System.currentTimeMillis(); + long lastOcurredAt; // 일단, 미사용 + @Builder.Default + long count = 1; + + public void onOcurr() { + this.lastOcurredAt = System.currentTimeMillis(); + this.count++; + } + +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/condition/AlarmLevel.java b/src/main/java/com/eactive/eai/custom/alarm/condition/AlarmLevel.java new file mode 100644 index 0000000..f88986a --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/condition/AlarmLevel.java @@ -0,0 +1,5 @@ +package com.eactive.eai.custom.alarm.condition; + +public enum AlarmLevel { + ERROR, WARN, FATAL +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/event/AlarmEvent.java b/src/main/java/com/eactive/eai/custom/alarm/event/AlarmEvent.java new file mode 100644 index 0000000..194128d --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/event/AlarmEvent.java @@ -0,0 +1,44 @@ +package com.eactive.eai.custom.alarm.event; + +import java.util.Objects; + +import com.eactive.eai.custom.alarm.condition.AlarmCondition; +import com.eactive.eai.custom.alarm.key.AlarmKey; +import com.eactive.eai.custom.alarm.policy.AlarmPolicy; +import com.eactive.eai.custom.alarm.policy.CounterPolicy; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@Builder +@ToString +public class AlarmEvent { + AlarmKey key; + AlarmCondition condition; + String message; + + public void onOcurr() { + condition.onOcurr(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AlarmEvent)) return false; + + AlarmEvent that = (AlarmEvent) o; + return Objects.equals(this.key, that.key) + && Objects.equals(this.message, that.message); + } + + @Override + public int hashCode() { + return Objects.hash(key, message); + } + + +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/key/AlarmKey.java b/src/main/java/com/eactive/eai/custom/alarm/key/AlarmKey.java new file mode 100644 index 0000000..ddcf0ad --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/key/AlarmKey.java @@ -0,0 +1,6 @@ +package com.eactive.eai.custom.alarm.key; + + +public interface AlarmKey { + String code(); +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/key/CoreAlarmKey.java b/src/main/java/com/eactive/eai/custom/alarm/key/CoreAlarmKey.java new file mode 100644 index 0000000..cc1d79b --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/key/CoreAlarmKey.java @@ -0,0 +1,12 @@ +package com.eactive.eai.custom.alarm.key; + +public final class CoreAlarmKey { + + private CoreAlarmKey() { } + + public static final AlarmKey CircuitBreaker = new DynamicAlarmKey("CircuitBreaker{ALARM}"); + + public static final AlarmKey Timeout = new DynamicAlarmKey("Timeout{ALARM}"); + + +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/custom/alarm/key/DynamicAlarmKey.java b/src/main/java/com/eactive/eai/custom/alarm/key/DynamicAlarmKey.java new file mode 100644 index 0000000..6a76d46 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/key/DynamicAlarmKey.java @@ -0,0 +1,33 @@ +package com.eactive.eai.custom.alarm.key; + +import lombok.ToString; + +@ToString +public final class DynamicAlarmKey implements AlarmKey { + + private final String code; + + public DynamicAlarmKey(String code) { + if (code == null || code.isEmpty()) { + throw new IllegalArgumentException("AlarmKey code must not be empty"); + } + this.code = code; + } + + @Override + public String code() { + return code; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AlarmKey)) return false; + return code.equals(((AlarmKey) o).code()); + } + + @Override + public int hashCode() { + return code.hashCode(); + } +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/custom/alarm/policy/AlarmPolicy.java b/src/main/java/com/eactive/eai/custom/alarm/policy/AlarmPolicy.java new file mode 100644 index 0000000..3c6dd8f --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/policy/AlarmPolicy.java @@ -0,0 +1,71 @@ +package com.eactive.eai.custom.alarm.policy; + +import com.eactive.eai.custom.alarm.event.AlarmEvent; +import com.eactive.eai.custom.alarm.key.AlarmKey; + +public abstract class AlarmPolicy { + + private AlarmKey alarmKey; + + private int thresholdCount; + + private long timeWindowMs; + + protected AlarmPolicy(Builder builder) { + this.alarmKey = builder.alarmKey; + this.thresholdCount = builder.thresholdCount; + this.timeWindowMs = builder.timeWindowMs; + } + + public AlarmKey getAlarmKey() { + return alarmKey; + } + + public int getThresholdCount() { + return thresholdCount; + } + + public long getTimeWindowMs() { + return timeWindowMs; + } + + public abstract boolean isAlarmTriggered(AlarmEvent event); + + + public boolean hasElapsed(long baseTimeMs) { + + return System.currentTimeMillis() - baseTimeMs >= timeWindowMs; + + } + + public boolean hasExceededLimit(long count) { + return count >= thresholdCount; + } + + public abstract static class Builder> { + + private AlarmKey alarmKey; + private int thresholdCount; + private long timeWindowMs; + + public T alarmKey(AlarmKey alarmKey) { + this.alarmKey = alarmKey; + return self(); + } + + public T thresholdCount(int thresholdCount) { + this.thresholdCount = thresholdCount; + return self(); + } + + public T timeWindowMs(long timeWindowMs) { + this.timeWindowMs = timeWindowMs; + return self(); + } + + protected abstract T self(); + + abstract AlarmPolicy build(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/custom/alarm/policy/AlarmType.java b/src/main/java/com/eactive/eai/custom/alarm/policy/AlarmType.java new file mode 100644 index 0000000..547eaf2 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/policy/AlarmType.java @@ -0,0 +1,5 @@ +package com.eactive.eai.custom.alarm.policy; + +public enum AlarmType { + COUNT, TIMER +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/policy/CounterPolicy.java b/src/main/java/com/eactive/eai/custom/alarm/policy/CounterPolicy.java new file mode 100644 index 0000000..7bf3c0a --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/policy/CounterPolicy.java @@ -0,0 +1,39 @@ +package com.eactive.eai.custom.alarm.policy; + +import com.eactive.eai.custom.alarm.event.AlarmEvent; + +public class CounterPolicy extends AlarmPolicy { + + private CounterPolicy(Builder builder) { + super(builder); + } + + @Override + public boolean isAlarmTriggered(AlarmEvent event) { + + if (!event.getKey().equals(getAlarmKey())) { + return false; + } + + long count = event.getCondition().getCount(); + return hasExceededLimit(count); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends AlarmPolicy.Builder { + + @Override + protected Builder self() { + return this; + } + + @Override + public CounterPolicy build() { + return new CounterPolicy(this); + } + } + +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/policy/SendPolicy.java b/src/main/java/com/eactive/eai/custom/alarm/policy/SendPolicy.java new file mode 100644 index 0000000..592d529 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/policy/SendPolicy.java @@ -0,0 +1,23 @@ +package com.eactive.eai.custom.alarm.policy; + +import java.util.List; + +import com.eactive.eai.custom.alarm.key.AlarmKey; +import com.eactive.eai.custom.alarm.key.DynamicAlarmKey; + +import lombok.Getter; +import lombok.ToString; +@ToString +@Getter +public class SendPolicy { + + final AlarmKey alarmKey; + + final List cellPhoneList; + + public SendPolicy(String alarmKey, List cellPhoneList) { + this.alarmKey = new DynamicAlarmKey(alarmKey); + this.cellPhoneList = cellPhoneList; + } + +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/policy/TimerPolicy.java b/src/main/java/com/eactive/eai/custom/alarm/policy/TimerPolicy.java new file mode 100644 index 0000000..29c719a --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/policy/TimerPolicy.java @@ -0,0 +1,51 @@ +package com.eactive.eai.custom.alarm.policy; + +import com.eactive.eai.custom.alarm.condition.AlarmCondition; +import com.eactive.eai.custom.alarm.event.AlarmEvent; +import com.eactive.eai.custom.alarm.policy.CounterPolicy.Builder; + +public class TimerPolicy extends AlarmPolicy { + + private TimerPolicy(Builder builder) { + super(builder); + } + + @Override + public boolean isAlarmTriggered(AlarmEvent event) { + + if (event.getKey().equals(getAlarmKey())) { + + AlarmCondition condition = event.getCondition(); + + long baseTimeMs = condition.getOcurredAt(); + + if (hasElapsed(baseTimeMs)) { + return true; + } else { + return false; + } + + } + + return false; + + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends AlarmPolicy.Builder { + + @Override + protected Builder self() { + return this; + } + + @Override + public TimerPolicy build() { + return new TimerPolicy(this); + } + } + +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/ums/UmsCallResult.java b/src/main/java/com/eactive/eai/custom/alarm/ums/UmsCallResult.java new file mode 100644 index 0000000..f63b6d8 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/ums/UmsCallResult.java @@ -0,0 +1,18 @@ +package com.eactive.eai.custom.alarm.ums; + + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class UmsCallResult { + private String umsMessageId; + private boolean isSuccess; + + private String returnCode; + private String returnMessage; + private String returnPayload; + + private Throwable throwable; +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/ums/UmsSendManager.java b/src/main/java/com/eactive/eai/custom/alarm/ums/UmsSendManager.java new file mode 100644 index 0000000..8e9c5d5 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/ums/UmsSendManager.java @@ -0,0 +1,86 @@ +package com.eactive.eai.custom.alarm.ums; + +import java.util.Queue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import javax.annotation.PreDestroy; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.eactive.eai.common.util.Logger; +import com.eactive.eai.custom.alarm.ums.payload.UmsRequestPayload; + +@Component +public class UmsSendManager { + + protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); + // 1. I/O 처리를 위한 전용 스레드 풀 (예: 최대 10개 스레드) + private final ExecutorService ioExecutor = Executors.newFixedThreadPool(10); + private final ScheduledExecutorService scheduler; + + // 2. 메모리 보호를 위해 크기 제한이 있는 큐 권장 (선택사항) + private final Queue queue = new ConcurrentLinkedQueue<>(); + + @Autowired + UmsService umsService; + + public UmsSendManager() { + this.scheduler = Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r); + t.setName("UmsSendManager-worker"); + return t; + }); + + scheduler.scheduleWithFixedDelay(() -> { + try { + sendMessage(); + } catch (Throwable e) { + logger.error("UMS 스케줄러 실행 중 오류", e); + } + }, 0, 30, TimeUnit.SECONDS); + } + + void sendMessage() { + UmsRequestPayload payload; + // 3. 한 번의 주기당 최대 처리량 제한 (필요시) + int count = 0; + while ((payload = queue.poll()) != null && count < 1000) { + final UmsRequestPayload finalPayload = payload; + + // 전용 Executor를 사용하여 공용 풀 보호 + CompletableFuture.runAsync(() -> { + try { + umsService.send(finalPayload); + } catch (Exception e) { + logger.error("UMS 전송 실패", e); + } + }, ioExecutor); + count++; + } + } + + // 4. 안전한 종료 처리 + @PreDestroy + public void stop() { + scheduler.shutdown(); + ioExecutor.shutdown(); + try { + if (!ioExecutor.awaitTermination(60, TimeUnit.SECONDS)) { + ioExecutor.shutdownNow(); + } + } catch (InterruptedException e) { + ioExecutor.shutdownNow(); + logger.error("UmsSendManager shutdownNow.", e); + } + } + + public void enqueue(UmsRequestPayload payload) { + queue.offer(payload); + } +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/ums/UmsService.java b/src/main/java/com/eactive/eai/custom/alarm/ums/UmsService.java new file mode 100644 index 0000000..74777de --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/ums/UmsService.java @@ -0,0 +1,154 @@ +package com.eactive.eai.custom.alarm.ums; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import javax.annotation.PreDestroy; + +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.entity.EntityBuilder; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.util.TimeValue; +import org.apache.hc.core5.util.Timeout; +import org.springframework.stereotype.Component; + +import com.eactive.eai.common.property.PropManager; +import com.eactive.eai.common.util.Jsons; +import com.eactive.eai.common.util.Logger; +import com.eactive.eai.custom.alarm.ums.payload.UmsRequestPayload; +import com.eactive.eai.custom.alarm.ums.payload.ValidationUtil; + +@Component +public class UmsService { + + protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); + + // 설정 상수 + private final static String UMS_GROUP_PROP_NAME = "UMS"; + private final static String UMS_PROP_HOST = "host"; + private final static String UMS_PROP_URL = "url"; + private final static String UMS_PROP_API_KEY = "apiKey"; + private final static String UMS_PROP_CONNECTION_TIMEOUT = "timeout.connection.ms"; + private final static String UMS_PROP_TIMEOUT = "timeout.ms"; + + // 기본값 + private final static String DEFAULT_UMS_URL = "http://172.31.35.144:9021"; + private final static String DEFAULT_SEND_URI = "/ums/openapi/send"; + private final static String DEFAULT_API_KEY = "7cca6d58-e4f7-474d-9edd-525806bc99ff"; + private final static String AUTHORIZATION_FMT = "Bearer %s"; + + // 재사용되는 HttpClient (Thread-Safe) + private final CloseableHttpClient httpClient; + + public UmsService() { + // 커넥션 풀 설정: 매번 소켓을 열고 닫지 않고 재사용함 + HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create() + .setMaxConnTotal(100) // 전체 최대 커넥션 수 + .setMaxConnPerRoute(20) // 호스트당 최대 커넥션 수 + .setConnectionTimeToLive(TimeValue.ofMinutes(3)) // TTL + .setValidateAfterInactivity(TimeValue.ofSeconds(5)) // 🔥 중요 + .build(); + + this.httpClient = HttpClients.custom() + .setConnectionManager(cm) + .evictExpiredConnections() // 만료 제거 + .evictIdleConnections(TimeValue.ofSeconds(20)) // 20초 idle 제거 + .build(); + } + + public UmsCallResult send(UmsRequestPayload payload) throws Exception { + if (payload.getContent() == null) { + throw new IllegalArgumentException("content is null"); + } + + try { + ValidationUtil.validateOrThrow(payload); + } catch (Exception ex) { + logger.debug(String.format("UMS Request payload validation failed - %s", payload)); + throw ex; + } + + return call(payload); + } + + private UmsCallResult call(UmsRequestPayload requestPayload) throws Exception { + // 1. 프로퍼티 로드 + PropManager prop = PropManager.getInstance(); + String host = prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_HOST, DEFAULT_UMS_URL); + String uri = prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_URL, DEFAULT_SEND_URI); + String apiKey = prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_API_KEY, DEFAULT_API_KEY); + long connectionTimeoutMs = Long.parseLong(prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_CONNECTION_TIMEOUT, "3000")); + long timeoutMs = Long.parseLong(prop.getProperty(UMS_GROUP_PROP_NAME, UMS_PROP_TIMEOUT, "3000")); + // 2. 요청 생성 + HttpPost httpPost = new HttpPost(host + uri); + httpPost.setHeader("Authorization", String.format(AUTHORIZATION_FMT, apiKey)); + + String json = Jsons.GSON.toJson(requestPayload); + httpPost.setEntity(EntityBuilder.create() + .setText(json) + .setContentType(ContentType.APPLICATION_JSON) + .setContentEncoding("UTF-8") + .build()); + + // 3. 타임아웃 설정 (설정파일 값 적용) + RequestConfig config = RequestConfig.custom() + .setConnectTimeout(Timeout.ofMilliseconds(connectionTimeoutMs)) + .setResponseTimeout(Timeout.ofMilliseconds(timeoutMs)) + .build(); + httpPost.setConfig(config); + + if (logger.isDebugEnabled()) { + logger.debug("UMS Request to: {}", host + uri); + logger.debug("UMS Request Body: {}", json); + } + + // 4. 실행 (HttpClient 재사용) + try { + return httpClient.execute(httpPost, response -> { + String body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + + if (logger.isDebugEnabled()) { + logger.debug("UMS Response Status: {}", response.getCode()); + logger.debug("UMS Response Body: {}", body); + } + + UmsCallResult result = Jsons.GSON.fromJson(body, UmsCallResult.class); + result.setUmsMessageId(requestPayload.getMessageIdentityNo()); + + // HTTP 200인 경우만 성공으로 간주 (필요에 따라 조정) + result.setSuccess(response.getCode() == 200); + + if (response.getCode() != 200) { + logger.warn("UMS Call failed with status: {}", response.getCode()); + } + + return result; + }); + } catch (Exception e) { + logger.error("UMS call exception: " + e.getMessage(), e); + return UmsCallResult.builder() + .umsMessageId(requestPayload.getMessageIdentityNo()) + .isSuccess(false) + .throwable(e) + .build(); + } + } + + @PreDestroy + public void destroy() { + try { + if (httpClient != null) { + httpClient.close(); + logger.info("UMS HttpClient closed."); + } + } catch (IOException e) { + logger.error("Error closing UMS HttpClient", e); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/custom/alarm/ums/payload/IUmsGsonObject.java b/src/main/java/com/eactive/eai/custom/alarm/ums/payload/IUmsGsonObject.java new file mode 100644 index 0000000..a1b7220 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/ums/payload/IUmsGsonObject.java @@ -0,0 +1,7 @@ +package com.eactive.eai.custom.alarm.ums.payload; + +/** + * GSON Serialize 용 Object + */ +public interface IUmsGsonObject { +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/ums/payload/ObpMonitoringUmsTemplate.java b/src/main/java/com/eactive/eai/custom/alarm/ums/payload/ObpMonitoringUmsTemplate.java new file mode 100644 index 0000000..9f5af06 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/ums/payload/ObpMonitoringUmsTemplate.java @@ -0,0 +1,12 @@ +package com.eactive.eai.custom.alarm.ums.payload; + +import com.google.gson.annotations.SerializedName; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class ObpMonitoringUmsTemplate implements IUmsGsonObject { + @SerializedName("MOTR_EVAL_CNTN") + private String message; +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/ums/payload/UmsBizWorkCode.java b/src/main/java/com/eactive/eai/custom/alarm/ums/payload/UmsBizWorkCode.java new file mode 100644 index 0000000..d669b23 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/ums/payload/UmsBizWorkCode.java @@ -0,0 +1,19 @@ +package com.eactive.eai.custom.alarm.ums.payload; + +import lombok.Getter; + +public enum UmsBizWorkCode { + MONITORING("B_ELFN_09510", "OBP 모니터링"), + VERIFY_PHONE("S55_ICT_0006", "API Portal 인증번호"), + ; + + @Getter + private String code; + @Getter + private String displayName; + + UmsBizWorkCode(String code, String displayName) { + this.code = code; + this.displayName = displayName; + } +} diff --git a/src/main/java/com/eactive/eai/custom/alarm/ums/payload/UmsRequestPayload.java b/src/main/java/com/eactive/eai/custom/alarm/ums/payload/UmsRequestPayload.java new file mode 100644 index 0000000..51fc6f6 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/ums/payload/UmsRequestPayload.java @@ -0,0 +1,105 @@ +package com.eactive.eai.custom.alarm.ums.payload; + +import com.google.gson.annotations.SerializedName; +import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import org.hibernate.validator.constraints.Length; +import org.hibernate.validator.constraints.NotEmpty; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@Data +@Builder +@Getter +public class UmsRequestPayload { + // MSG_IDNT_NO string 메시지식별번호 50 O "발송 구분을 위한 거래 번호 (GUID 권고) + //GUID로 입력이 어려울시 + //어플리케이션코드(3자리)+난수 로 유니크한 ID로 채번 권고" + @Length(min = 1, max = 50) + @NotEmpty + @SerializedName("MSG_IDNT_NO") + @Builder.Default + private String messageIdentityNo = String.format("APM-%s",DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(LocalDateTime.now())); + + // MSG_BZWK_CD string 메시지업무코드 30 O UMS에 등록된 메시지업무코드(AS-IS 템플릿ID) + @NotEmpty + @Length(min = 1, max = 30) + @SerializedName("MSG_BZWK_CD") + @Builder.Default + private String msgBizWorkCode = UmsBizWorkCode.MONITORING.getCode(); + + // 메시지업무파라미터내용 / 4000 / JSONObject + // MSG_BZWK_PARAM_CTNT object 메시지업무파라미터내용 4000 메시지업무코드의 템플릿에서 사용하는 변수와 변수값 + @NotNull + @SerializedName("MSG_BZWK_PARAM_CTNT") + private IUmsGsonObject content; + + // 발송예약일시 / 14 / 실 발송 일자(yyyyMMddHHmmss) + // SND_RESR_DTTM string 발송예약일시 14 20240418111500 O 실 발송 일자(현재시간) + @Pattern(regexp = "^[0-9]{14}$") + @NotEmpty + @SerializedName("SND_RESR_DTTM") + @Builder.Default + private String sendReservationDatetime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now()); + + // 휴대전화번호 / 44 / 휴대폰번호(평문, 암호화 둘다가능) + // CPNO string 휴대전화번호 44 "암호화 또는 평문 (safedb not rrno) + //문자일 시 암호문 + //숫자일 시 전화번호 + //고객번호 또는 휴대전화번호 필수" + @NotEmpty + @Pattern(regexp = "^[0-9]{10,11}$") + @SerializedName("CPNO") + private String cellphone; + + // 발송부점코드 / 4 / + // SND_BRCD string 발송부점코드 4 O 0333 + @NotEmpty + @SerializedName("SND_BRCD") + @Builder.Default + private String sendBranchCode = "0990"; + + // 발송직원번호 / 7 / ECEB057(텔러번호?) + // SND_EMPNO string 발송직원번호 7 O ? 넣긴해야함 + @NotEmpty + @SerializedName("SND_EMPNO") + @Builder.Default + private String sendEmployeeNo = "ECEB057"; + + // SRVC_ID string 서비스ID 11 요청단 측 서비스ID + @NotEmpty + @SerializedName("SRVC_ID") + @Builder.Default + private String serviceId = "eAPIM"; + + // MSG_SND_CHNL_CD string 메시지발송채널코드 2 + @SerializedName("MSG_SND_CHNL_CD") + @NotNull + @Builder.Default + private ChannelCode msgSndChnlCd = ChannelCode.KM; + + // VALDTN_RSLT_CD string 검증결과코드 2 00으로 고정 + @SerializedName("VALDTN_RSLT_CD") + @NotEmpty + @Builder.Default + private String validationResultCode = "00"; + + public enum ChannelCode { + SM, // SMS + LM, // LMS + MM, // MMS + KM, // 카카오-알림톡 + FM, // 카카오-친구톡 + SR, // RCS-SMS + LR, // RCS-LMS + MR, // RCS-MMS + TR, // RCS-TEMPLATE + IR, // RCS-IMAGE Template + PM // Push + } +} + diff --git a/src/main/java/com/eactive/eai/custom/alarm/ums/payload/ValidationUtil.java b/src/main/java/com/eactive/eai/custom/alarm/ums/payload/ValidationUtil.java new file mode 100644 index 0000000..ecb8cf8 --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/ums/payload/ValidationUtil.java @@ -0,0 +1,53 @@ +package com.eactive.eai.custom.alarm.ums.payload; + +import java.util.Set; +import java.util.stream.Collectors; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; + +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; + +public class ValidationUtil { + private static final ValidatorFactory factory; + private static final Validator validator; + + static { + factory = Validation.byDefaultProvider() + .configure() + .messageInterpolator(new ParameterMessageInterpolator()) + .buildValidatorFactory(); + + validator = factory.getValidator(); + } + + + private ValidationUtil() { + } + + + public static Set> validate(T target) { + return validator.validate(target); + } + + public static void validateOrThrow(T target) { + Set> violations = validate(target); + if (!violations.isEmpty()) { + String message = violations.stream() + .map(v -> v.getPropertyPath() + " : " + v.getMessage()) + .collect(Collectors.joining(", ")); + throw new ConstraintViolationException("Validation failed: " + message, violations); + } + } + + public static String getViolationMessage(T target) { + Set> violations = validate(target); + if (violations.isEmpty()) return null; + return violations.stream() + .map(v -> v.getPropertyPath() + " : " + v.getMessage()) + .collect(Collectors.joining(", ")); + } +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/custom/alarm/ums/payload/VerifyPhoneUmsTemplate.java b/src/main/java/com/eactive/eai/custom/alarm/ums/payload/VerifyPhoneUmsTemplate.java new file mode 100644 index 0000000..4840fbf --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/alarm/ums/payload/VerifyPhoneUmsTemplate.java @@ -0,0 +1,12 @@ +package com.eactive.eai.custom.alarm.ums.payload; + +import com.google.gson.annotations.SerializedName; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class VerifyPhoneUmsTemplate implements IUmsGsonObject { + @SerializedName("ATHN_NO") + private String authNumber; +} diff --git a/src/main/java/com/eactive/eai/env/ElinkConfig.java b/src/main/java/com/eactive/eai/env/ElinkConfig.java index b3024f4..9346065 100644 --- a/src/main/java/com/eactive/eai/env/ElinkConfig.java +++ b/src/main/java/com/eactive/eai/env/ElinkConfig.java @@ -1,11 +1,14 @@ package com.eactive.eai.env; import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import javax.annotation.PostConstruct; +import org.json.simple.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; @@ -13,6 +16,8 @@ import org.springframework.stereotype.Component; 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.common.dao.DAOException; import com.eactive.eai.common.util.ContainerUtil; @@ -297,6 +302,47 @@ public class ElinkConfig implements ConfigKeys { } return getAsyncDummyData(adptrMsgPtrnCd); } + + public static String getAsyncDummyDataForAdapterGroup(String adapterGroupName, String adapterName) { + + Properties httpProp = null; + try { + + + AdapterVO adapterVO = AdapterManager.getInstance().getAdapterVO(adapterGroupName, adapterName); + + httpProp = AdapterPropManager.getInstance().getProperties(adapterVO.getPropGroupName()); + } catch (Exception e) { + return makeResponseBodyMsg(); + } + + String asyncMsgStyle = httpProp.getProperty("ASYNC_RTNMSG_TYPE", "").toUpperCase(); + String responseBody =""; + if (asyncMsgStyle == null || asyncMsgStyle.trim().isEmpty()) { + responseBody = makeResponseBodyMsg(); + } else { + responseBody = asyncMsgStyle; + } + + return responseBody; + } + + static private String makeResponseBodyMsg() { + + Map dataMap = new HashMap<>(); + dataMap.put("result", 1); + Map map = new HashMap<>(); + + map.put("code", "200"); + map.put("data", dataMap); + map.put("message", "정상 처리 되었습니다."); + + JSONObject json = new JSONObject(); + json.putAll(map); + + return json.toJSONString(); + } + public static String getHttpClientUrlReplaceName() { return httpClientUrlReplaceName; } diff --git a/src/main/java/com/eactive/eai/env/SystemPropConfig.java b/src/main/java/com/eactive/eai/env/SystemPropConfig.java index 48eb84a..4c7cf0c 100644 --- a/src/main/java/com/eactive/eai/env/SystemPropConfig.java +++ b/src/main/java/com/eactive/eai/env/SystemPropConfig.java @@ -25,14 +25,14 @@ public class SystemPropConfig implements ServletContextAware { @PostConstruct public void loadlPropertiesToSystemProp() { - System.out.println("loadPropertiesToSystemProp: "+SYSTEM_PROP_FILE_PATH); + // System.out.println("loadPropertiesToSystemProp: "+SYSTEM_PROP_FILE_PATH); Properties sysProp = new Properties(); try(InputStream is = servletContext.getResourceAsStream(SYSTEM_PROP_FILE_PATH)){ sysProp.load(is); sysProp.forEach((key, value) -> { if (StringUtils.isBlank(System.getProperty((String) key))) { System.setProperty((String) key, (String) value); - System.out.println("Set system prop: "+key+"="+value); + // System.out.println("Set system prop: "+key+"="+value); } }); } catch (Throwable th) { diff --git a/src/main/java/com/eactive/eai/flowcontroller/C2RFCProcess.java b/src/main/java/com/eactive/eai/flowcontroller/C2RFCProcess.java index 7808b59..76ed592 100644 --- a/src/main/java/com/eactive/eai/flowcontroller/C2RFCProcess.java +++ b/src/main/java/com/eactive/eai/flowcontroller/C2RFCProcess.java @@ -358,7 +358,7 @@ public class C2RFCProcess extends Process { if (this.callProp != null) { String mode = this.callProp.getProperty(EAIKeys.CALL_MODE_KEY); if (mode != null && EAIKeys.CALL_MODE_WARMUP.equals(mode)) { - System.out.println(guidLogPrefix + " Warming Up Called"); + // System.out.println(guidLogPrefix + " Warming Up Called"); return false; } else { return true; diff --git a/src/main/java/com/eactive/eai/inbound/action/AdapterGroupNameMethodRequestAction.java b/src/main/java/com/eactive/eai/inbound/action/AdapterGroupNameMethodRequestAction.java new file mode 100644 index 0000000..c808571 --- /dev/null +++ b/src/main/java/com/eactive/eai/inbound/action/AdapterGroupNameMethodRequestAction.java @@ -0,0 +1,70 @@ +package com.eactive.eai.inbound.action; + +import com.eactive.eai.adapter.http.dynamic.impl.HttpAdapterServiceRest; +import com.eactive.eai.common.exception.ExceptionUtil; +import com.eactive.eai.common.util.MessageKeyExtractor; + +/** +* 1. 기능 : Inbound Adapter를 통해 전달받은 비표준메시지에서 EAI메시지를 생성하기 위한 키값을 추출 +* 2. 처리 개요 : +* - 어뎁터의 업무그룹명을 키값앞에 추가한다. +* - MessageKeyExtractor를 통해 Adapter별 추출 Rule에 따라 메시지를 구분할 수 있는 키값을 추출한다. +* 3. 주의사항 +* +* @author : +* @version : v 1.0.0 +* @see : +* @since : +*/ +public class AdapterGroupNameMethodRequestAction extends RequestActionSupport +{ + public static final String STEMSG_METHOD_DELIMITER = ":"; + public static final String STEMSG_SERVICE_HEADER_DELIMITER = "^"; + + /** + * 1. 기능 : Inbound Adapter를 통해 전달받은 비표준메시지에서 EAI메시지를 생성하기 위한 키값을 추출 + * 2. 처리 개요 : + * - MessageKeyExtractor를 통해 Adapter별 추출 Rule에 따라 메시지를 구분할 수 있는 키값을 추출한다. + * 3. 주의사항 + * + * @param message Object 타입의 요청메시지 + * @return String 비표준메시지의 메시지키값 + * @exception + **/ + public String[] perform(Object message) throws ActionException + { + byte[] tmp = null; + String key[] = null; + + String adptGrpName = adapterGroupName; + String requestMethod = prop.getProperty(HttpAdapterServiceRest.PROPERTIES_NAME_HTTP_REQUEST_METHOD); + + if(message instanceof byte[]) { + try { + key = MessageKeyExtractor.getMessageKeyValue(this.adapterGroupName, message); + } catch(Exception e) { + throw new ActionException(ExceptionUtil.getErrorCode(e, "RECEAIIRA001")); + } + tmp = (byte[])message; + if (logger.isInfo()) logger.info(adapterName+"] received data >> "+ new String(tmp)); + } else { + try { + key = MessageKeyExtractor.getMessageKeyValue(this.adapterGroupName, message); + } catch(Exception e) { + throw new ActionException(ExceptionUtil.getErrorCode(e, "RECEAIIRA001")); + } + if (logger.isInfo()) logger.info(adapterName+"] received data >> "+ message); + } + + String baseMessageKey = adptGrpName.trim() + STEMSG_METHOD_DELIMITER + requestMethod + STEMSG_SERVICE_HEADER_DELIMITER; + for(int i=0; i 0) { InflowTargetVO inflowTargetVO = null; + InflowGroupVO inflowGroupVO = null; if (blockedType.startsWith("A")) { inflowTargetVO = bucket.getAdapterInflowThreashold(vo.getAdapterGroupName()); + } else if (blockedType.contains("G")) { + inflowGroupVO = bucket.getGroupInflowThreshold(groupId); } else { inflowTargetVO = bucket.getInterfaceInflowThreashold(vo.getEaiSvcCd()); } // 에러처리 vo.setRspErrorCode(EAIMessageKeys.EAI_INFLOW_BLOCKED_CODE); - vo.setRspErrorMsg(ExceptionUtil.make(vo.getRspErrorCode(), vo.getEaiSvcCd() ) + ", " - + inflowTargetVO.toString()); + if (inflowGroupVO != null) { + if ("PER_SECOND".equals(groupBlockedType)) { + inflowErrorMsg = String.format("API 호출 한도 초과 [%s: %dreq/sec]", + inflowGroupVO.getGroupName(), + inflowGroupVO.getThresholdPerSecond()); + } else { + inflowErrorMsg = String.format("API 호출 한도 초과 [%s: %dreq/%s]", + inflowGroupVO.getGroupName(), + inflowGroupVO.getThreshold(), + inflowGroupVO.getThresholdTimeUnit()); + } + } else if (inflowTargetVO != null) { + inflowErrorMsg = String.format("API 호출 한도 초과 [%s]", inflowTargetVO.getName()); + } else { + inflowErrorMsg = "API 호출 한도 초과"; + } + vo.setRspErrorMsg(inflowErrorMsg); // eaiMsg.setRspErrCd(vo.getRspErrorCode()); // eaiMsg.setRspErrMsg(vo.getRspErrorMsg()); @@ -1032,16 +1079,21 @@ public class RequestProcessor extends RequestProcessorSupport { try { Properties inFlowProp = PropManager.getInstance().getProperties("INFLOW"); String controlInflowHistory = inFlowProp.getProperty("inflow.control.history.yn", "N"); - if (StringUtils.equalsIgnoreCase(controlInflowHistory, "Y") && inflowTargetVO != null) { + if (StringUtils.equalsIgnoreCase(controlInflowHistory, "Y") && (inflowTargetVO != null || inflowGroupVO != null)) { DAOFactory factory = DAOFactory.newInstance(); // InflowControlDAO restrictDao = (InflowControlDAO) factory.create(InflowControlDAO.class); // InflowControlDAO를 서비스로 만들어서 factory.create로 하면 안됨. InflowControlDAO restrictDao = (InflowControlDAO) ApplicationContextProvider.getContext().getBean(InflowControlDAO.class); + // 그룹 유량제어 정보가 있으면 그룹 정보로, 없으면 기존 inflowTargetVO 정보로 로그 + long thresholdPerSecond = (inflowGroupVO != null) ? inflowGroupVO.getThresholdPerSecond() : inflowTargetVO.getThresholdPerSecond(); + long threshold = (inflowGroupVO != null) ? inflowGroupVO.getThreshold() : inflowTargetVO.getThreshold(); + String thresholdTimeUnit = (inflowGroupVO != null) ? inflowGroupVO.getThresholdTimeUnit() : inflowTargetVO.getThresholdTimeUnit(); + String logGroupName = (inflowGroupVO != null) ? inflowGroupVO.getGroupId() : vo.getAdapterGroupName(); + restrictDao.addInflowServicetLog(eaiMsg.getBwkCls(), DatetimeUtil.getCurrentTime(eaiMsg.getMsgRcvTm()), eaiMsg.getSvcOgNo(), - eaiServerManager.getLocalServerName(), eaiMsg.getEAISvcCd(), vo.getAdapterGroupName(), - inflowTargetVO.getThresholdPerSecond(), inflowTargetVO.getThreshold(), - inflowTargetVO.getThresholdTimeUnit()); + eaiServerManager.getLocalServerName(), eaiMsg.getEAISvcCd(), logGroupName, + thresholdPerSecond, threshold, thresholdTimeUnit); } } catch (Exception ex) { if (logger.isError()) { @@ -1052,7 +1104,10 @@ public class RequestProcessor extends RequestProcessorSupport { sb.append("EAISevrInstncName [" + eaiServerManager.getLocalServerName() + "]\n"); sb.append("EAISvcName [" + eaiMsg.getEAISvcCd() + "]\n"); sb.append("ADPTRBZWKGROUPNAME[" + vo.getAdapterGroupName() + "]\n"); - sb.append("InflowTargetVO [" + inflowTargetVO.toString() + "]\n"); + sb.append("InflowInfo [" + inflowErrorMsg + "]\n"); + if (groupId != null) { + sb.append("InflowGroupId [" + groupId + "]\n"); + } logger.error(guidLogPrefix + " 유량제어 건수 Log 실패 - " + ex.toString() + "\n" + sb.toString()); } @@ -1111,7 +1166,8 @@ public class RequestProcessor extends RequestProcessorSupport { if (logger.isError()) logger.error(guidLogPrefix + " : 유량제어 비동기 에러응답송신 실패 - " + ee.toString()); } - return null; + throw new HttpStatusException(eaiMsg.getRspErrMsg(), eaiMsg.getRspErrCd(), + HttpStatus.TOO_MANY_REQUESTS.value()); } } } @@ -1221,7 +1277,16 @@ public class RequestProcessor extends RequestProcessorSupport { logger.error("convertToSub failed.", e); } } - + + //응답 전 표준 전문의 로직 처리 필요 한 경우를 위해 호출 + try{ + if(EAIMessageKeys.SYNC_SVC.equals(svcTsmtUsgTp) && retEaiMsg != null){ + standardManager.getMessageCoordinator().coordinateBeforeResponse(retEaiMsg.getStandardMessage(), vo, prop, inboundCharset); + } + }catch(Exception e){ + logger.error("coordinateBeforeResponse failed.", e); + } + // 10. 응답 거래로그 Logging if(EAIMessageKeys.SYNC_SVC.equals(svcTsmtUsgTp) && STDMessageKeys.SEND_RECV_CD_SEND.equals(returnType) ) { @@ -1301,15 +1366,9 @@ public class RequestProcessor extends RequestProcessorSupport { } else { // 비동기 거래, S-A의 응답거래시에는 NULL을 리턴 - //return null; // 원래 null return 인데 광주은행은 GUID를 Return 해 달라고 해서 수정함 jwhong - //map.put("guid", guid); - - Map map = new HashMap<>(); - map.put("uuid", vo.getUuid()); - JSONObject json = new JSONObject(map); - //return json.toJSONString(); - - return vo.getUuid(); + return null; + // S-A 에서 Sync 100에 대한 ack 응답시 http header 에 traceId 에 uuid를 넣어달라고 해서.. + //return vo.getUuid(); } } diff --git a/src/main/java/com/eactive/eai/message/StandardMessageUtil.java b/src/main/java/com/eactive/eai/message/StandardMessageUtil.java index ccb92b6..996b58a 100644 --- a/src/main/java/com/eactive/eai/message/StandardMessageUtil.java +++ b/src/main/java/com/eactive/eai/message/StandardMessageUtil.java @@ -22,6 +22,7 @@ public class StandardMessageUtil { public static String requestProcessorClass = "com.eactive.eai.inbound.processor.RequestProcessor"; + public static String REST_URL_ACTION0 = "com.eactive.eai.inbound.action.RestAdapterMethodUrlRequestAction"; public static String REST_URL_ACTION1 = "com.eactive.eai.inbound.action.RestUrlAdapterGroupParseRequestAction"; public static String REST_URL_ACTION2 = "com.eactive.eai.inbound.action.RestUrlParseRequestAction"; @@ -49,7 +50,7 @@ public class StandardMessageUtil { if (standardMessage == null) { // API 서비스일경우 PathVariable 지원 추가 // ex) /api/account/{no} - if (StringUtils.equalsAny(vo.getActionName(), REST_URL_ACTION1, REST_URL_ACTION2)) { + if (StringUtils.equalsAny(vo.getActionName(), REST_URL_ACTION0, REST_URL_ACTION1, REST_URL_ACTION2)) { standardMessage = stdMessageManager.getSTDMessageForPathVariable(vo.getSelectedKey()); } @@ -79,7 +80,7 @@ public class StandardMessageUtil { } } - if (StringUtils.equalsAny(actionName, REST_URL_ACTION1, REST_URL_ACTION2)) { + if (StringUtils.equalsAny(actionName, REST_URL_ACTION0, REST_URL_ACTION1, REST_URL_ACTION2)) { return stdMessageManager.getMatchedPathVariable(key); } @@ -362,13 +363,13 @@ public class StandardMessageUtil { StandardMessage stdmsg = generateMessageFromCsvFile(filePath); - System.out.println("==========================================================================="); - System.out.println(stdmsg.getChilds().size()); - System.out.println(stdmsg); - System.out.println("==========================================================================="); - System.out.println(stdmsg.getLlDataPath()); - System.out.println(stdmsg.getBizDataPath()); - System.out.println(stdmsg.getZzDataPath()); - System.out.println("==========================================================================="); + // System.out.println("==========================================================================="); + // System.out.println(stdmsg.getChilds().size()); + // System.out.println(stdmsg); + // System.out.println("==========================================================================="); + // System.out.println(stdmsg.getLlDataPath()); + // System.out.println(stdmsg.getBizDataPath()); + // System.out.println(stdmsg.getZzDataPath()); + // System.out.println("==========================================================================="); } } diff --git a/src/main/java/com/eactive/eai/message/parser/FlatReader.java b/src/main/java/com/eactive/eai/message/parser/FlatReader.java index 76e29bc..7bcb93b 100644 --- a/src/main/java/com/eactive/eai/message/parser/FlatReader.java +++ b/src/main/java/com/eactive/eai/message/parser/FlatReader.java @@ -107,42 +107,45 @@ public class FlatReader implements StandardReader { case StandardType.GROUP: logger.debug("@GROUP name={}, getLength={}, getRefPath={}, getRefValue=[{}]" , currentItem.getName(), currentItem.getLength(), currentItem.getRefPath(), currentItem.getRefValue()); - if( currentItem.getSize() == 0 - && StringUtils.isNotBlank(currentItem.getRefPath()) + if( currentItem.getSize() == 0 + && StringUtils.isNotBlank(currentItem.getRefPath()) && StringUtils.isNotBlank(currentItem.getRefValue()) ) { - String refItemValue = itemMap.get(currentItem.getRefPath()); - + //2024.08.07 아래추가로직은 Group 하위의 field 값에 따라서 + //파싱을 해야 될경우 추가 + String refItemValue =""; + if (currentItem.getRefPath().startsWith(fieldName)){ + refItemValue = getRefItemValue(currentItem.getRefPath(), fieldName, srcbytes, currentItem, start); + }else{ + refItemValue = itemMap.get(currentItem.getRefPath()); + } logger.debug("@GROUP name={}, getRefPath={}, refItemValue=[{}], getRefValue=[{}]" , currentItem.getName(), currentItem.getRefPath(), refItemValue, currentItem.getRefValue()); - + if(refItemValue != null) refItemValue = refItemValue.trim(); - + /* - * 값의 경우의수 NR,ER,""(blank) - * ER이 아닐경우 표현하고 싶어서 ! 를 추가했음 - * 원칙으로는 NR을 넣었을경우에는 NR 이 있을경우에만 해당됨 - * !ER일경우에는 blank와 NR일 경우에 해당됨 + * 값의 경우의수 NM,EM,""(blank) + * ! : NOT 조건 (예: !EM → EM이 아닌 경우) + * | : OR 조건 (예: NM|EM → NM 또는 EM인 경우) + * !와 | 조합 가능 (예: !NM|EM → NM도 아니고 EM도 아닌 경우) */ String refValue = currentItem.getRefValue(); - if (refValue.startsWith("!")) { // 느낌표가 들어가면 다음에 나오는게 아닌경우 + boolean isNot = refValue.startsWith("!"); + if (isNot) { refValue = refValue.substring(1); - if (refValue.equals(refItemValue)) { - logger.warn("@GROUP name={} SKIPPED.", currentItem.getName()); - currentItem.setHidden(true); - break; - } else { - currentItem.setHidden(false); - } + } + boolean matched = matchRefValue(refValue, refItemValue); + if (isNot) { + matched = !matched; + } + + if (!matched) { + logger.warn("@GROUP name={} SKIPPED.", currentItem.getName()); + currentItem.setHidden(true); + break; } else { - if (!currentItem.getRefValue().equals(refItemValue)) { - logger.warn("@GROUP name={} SKIPPED.", currentItem.getName()); - currentItem.setHidden(true); - break; - } else { - currentItem.setHidden(false); - } - + currentItem.setHidden(false); } } childList = currentItem.getChildsList(); @@ -284,6 +287,41 @@ public class FlatReader implements StandardReader { } return result; } -// public static void main(String[] args) { -// } + + private String getRefItemValue(String orgRef, String fieldName, byte[] srcbytes , StandardItem currentItem ,int start ){ + String currentFieldName = orgRef.replace(fieldName+".",""); + ArrayList childList = currentItem.getChildsList(); + String refItemValue =""; + for(StandardItem item : childList) { + if (currentFieldName.indexOf(".") < 0) { + byte[] tempValue = null; + if (orgRef.equals(fieldName + "." + item.getName())) { + tempValue = cut(fieldName, srcbytes, start, item.getLength()); + return new String(tempValue); + }else{ + start = start + item.getLength(); + } + } else { + return getRefItemValue(orgRef, fieldName+"."+item.getName(), srcbytes, item, start); + } + } + return refItemValue; + } + + /** + * refValue와 refItemValue를 비교하여 일치 여부를 반환 + * | 구분자로 OR 조건 지원 (예: "NM|EM" → "NM" 또는 "EM"과 일치하면 true) + */ + private boolean matchRefValue(String refValue, String refItemValue) { + if (refValue.contains("|")) { + String[] values = refValue.split("\\|"); + for (String val : values) { + if (val.equals(refItemValue)) { + return true; + } + } + return false; + } + return refValue.equals(refItemValue); + } } \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/message/service/DefaultInterfaceMapper.java b/src/main/java/com/eactive/eai/message/service/DefaultInterfaceMapper.java index 638c5d7..b5f0139 100644 --- a/src/main/java/com/eactive/eai/message/service/DefaultInterfaceMapper.java +++ b/src/main/java/com/eactive/eai/message/service/DefaultInterfaceMapper.java @@ -21,7 +21,7 @@ public class DefaultInterfaceMapper implements InterfaceMapper { protected String getPath(String key) { String path = itemPathMap.get(key); if(StringUtils.isBlank(path)) { - logger.warn("message-mapping not defined key = {}", key); + logger.debug("message-mapping not defined key = {}", key); } return path; } diff --git a/src/main/java/com/eactive/eai/message/service/DefaultStandardMessageCoordinator.java b/src/main/java/com/eactive/eai/message/service/DefaultStandardMessageCoordinator.java index 01a5cc4..81f34b5 100644 --- a/src/main/java/com/eactive/eai/message/service/DefaultStandardMessageCoordinator.java +++ b/src/main/java/com/eactive/eai/message/service/DefaultStandardMessageCoordinator.java @@ -25,6 +25,11 @@ public class DefaultStandardMessageCoordinator implements StandardMessageCoordin mapper.setGuid(standardMessage, UUIDGenerator.getGUID(eaiServerManager.getSystemType())); } + @Override + public void coordinateBeforeStandardMessageSend(StandardMessage standardMessage, String msgType, String charset) { + + } + @Override public void coordinateInReturnObject(StandardMessage standardMessage) { } @@ -72,5 +77,7 @@ public class DefaultStandardMessageCoordinator implements StandardMessageCoordin } - + @Override + public void coordinateBeforeResponse(StandardMessage standardMessage, ProcessVO processVO, Properties prop, String charset) { + } } diff --git a/src/main/java/com/eactive/eai/message/service/StandardMessageCoordinator.java b/src/main/java/com/eactive/eai/message/service/StandardMessageCoordinator.java index 11df794..a9a0e49 100644 --- a/src/main/java/com/eactive/eai/message/service/StandardMessageCoordinator.java +++ b/src/main/java/com/eactive/eai/message/service/StandardMessageCoordinator.java @@ -26,7 +26,14 @@ public interface StandardMessageCoordinator { * @param prop */ public void coordinateAfterCreateMessageByRule(StandardMessage standardMessage, Object paramObject, Properties prop); - + + /** + * 표준전문 송신 전 메시지 조립 전 처리 + * + * @param standardMessage + */ + public void coordinateBeforeStandardMessageSend(StandardMessage standardMessage, String msgType, String charset); + /** * 표준 메시지일경우 ReturnObject 에서 처리 * @@ -97,4 +104,15 @@ public interface StandardMessageCoordinator { * @param responseMessage */ public void coordinateAfterRecvNonStdSyncResponse(StandardMessage responseMessage); + + + /** + * RequestProcess 400 응답 로그 전 표준 메시지 조작 처리 + * + * @param standardMessage + * @param processVO + * @param prop + * @param charset + */ + public void coordinateBeforeResponse(StandardMessage standardMessage, ProcessVO processVO, Properties prop, String charset); } diff --git a/src/main/java/com/eactive/eai/outbound/DefaultProcess.java b/src/main/java/com/eactive/eai/outbound/DefaultProcess.java index 691e07a..71693d3 100644 --- a/src/main/java/com/eactive/eai/outbound/DefaultProcess.java +++ b/src/main/java/com/eactive/eai/outbound/DefaultProcess.java @@ -37,6 +37,7 @@ import com.eactive.eai.message.manager.StandardMessageManager; import com.eactive.eai.message.mapper.MessageMapper; import com.eactive.eai.message.service.InterfaceMapper; import com.ext.eai.common.stdmessage.STDMessageKeys; +import com.eactive.eai.common.message.ServiceMessage; // jwhong public abstract class DefaultProcess extends Process { protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); @@ -252,6 +253,19 @@ public abstract class DefaultProcess extends Process { } // 송신결과확인 checkSendResult(); + // 400 Async 에 대한 ack 오는것 500 으로 log에 저장, jwhong for kjbank + if(isAsyncSyncPattern()){ + StandardMessage standardMessage = this.resEaiMsg.getStandardMessage(); + standardMessage.setBizData(this.resObject, this.outboundCharset); + + if ("E".equals(resEaiMsg.getRspErrCd().substring(1, 2)) + || "F".equals(resEaiMsg.getRspErrCd().substring(1, 2))) { + this.logPssSno = 900; + } else { + this.logPssSno = 500; + } + logSenderCtrlSendRes(); + } // SA if (isSyncAsyncPattern()) { try { @@ -474,6 +488,19 @@ public abstract class DefaultProcess extends Process { return false; } } + + // jwhong + public boolean isAsyncSyncPattern() { + ServiceMessage firstService = this.reqEaiMsg.getSvcMsg(0); + ServiceMessage secondService = this.reqEaiMsg.getSvcMsg(1); + if (EAIMessageKeys.ASYNC_SVC.equals(this.reqEaiMsg.getSvcTsmtUsgTp()) + && EAIMessageKeys.SYNC_SVC.equals(firstService.getPsvItfTp()) + && EAIMessageKeys.ASYNC_SVC.equals(secondService.getPsvItfTp()) + && this.reqEaiMsg.getCurrentSvcMsg() == secondService){ + return true; + } + return false; + } public boolean isSyncAsyncPattern() { if (!MessageUtil.checkRspErrCd(this.resEaiMsg.getRspErrCd())) { @@ -655,6 +682,11 @@ public abstract class DefaultProcess extends Process { AdapterVO inboundAdapterVO = AdapterManager.getInstance().getAdapterVO(inboudnAdapterGroupName, inboudnAdapterName); String errorResponseHandlerClass = AdapterPropManager.getInstance().getProperty(inboundAdapterVO.getPropGroupName(), "ERR_MSG_HANDLER"); if(StringUtils.isBlank(errorResponseHandlerClass)) { + this.resEaiMsg.setRspErrCd("RECEAIINA001", false); + String errorCode = mapper.getErrorCode(resStandardMessage); + String errorMsg = StringUtils.trim(mapper.getErrorMsg(resStandardMessage)); + String errorDesc = StringUtils.trim(resStandardMessage.findItemValue("Message.Msg_Body.OUTPUT_MSG_DESC")); + this.resEaiMsg.setRspErrMsg(String.format("[%s] %s (%s)", errorCode, errorMsg, errorDesc)); return; } diff --git a/src/main/java/com/eactive/eai/outbound/HTTPProcess.java b/src/main/java/com/eactive/eai/outbound/HTTPProcess.java index dd2c8ac..da67208 100644 --- a/src/main/java/com/eactive/eai/outbound/HTTPProcess.java +++ b/src/main/java/com/eactive/eai/outbound/HTTPProcess.java @@ -54,7 +54,10 @@ public class HTTPProcess extends DefaultProcess { protected final ObjectMapper objectMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL); public void outboundCtrlCallServiceAsync() throws Exception { - // async에서는 인터페이스 값을 설정하지 않고 Adapter의 타임아웃을 쓰기위해서 설정하지 않음 + // 인터페이스에 셋팅된 타임아웃설정 + int iTimeoutValue = getTimeoutCodeToValue(); + this.timeout = iTimeoutValue * 1000; + this.tempProp.put(INTERFACE_TIME_OUT, "" + this.timeout); try { this.tempProp.put(HttpClientAdapterServiceKey.LOG_PROCESS_NO, this.logPssSno); this.resObject = HttpSender.callService(this.adapterGroupName, this.outboundProp, this.reqObject, this.tempProp); diff --git a/src/main/java/com/eactive/eai/outbound/RESTProcess.java b/src/main/java/com/eactive/eai/outbound/RESTProcess.java index 1b2eb51..e05c556 100644 --- a/src/main/java/com/eactive/eai/outbound/RESTProcess.java +++ b/src/main/java/com/eactive/eai/outbound/RESTProcess.java @@ -1,5 +1,5 @@ package com.eactive.eai.outbound; - + import java.net.SocketTimeoutException; import java.util.Properties; @@ -21,6 +21,7 @@ import com.eactive.eai.adapter.AdapterVO; 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.HttpAdapterServiceSupport; import com.eactive.eai.common.EAIKeys; import com.eactive.eai.common.exception.ExceptionUtil; import com.eactive.eai.common.header.HeaderAction; @@ -41,6 +42,11 @@ import com.eactive.eai.common.worker.ResponseMap; import com.eactive.eai.control.HttpSender; import com.eactive.eai.control.LogSender; import com.eactive.eai.control.Transform; +import com.eactive.eai.custom.alarm.AlarmStateManager; +import com.eactive.eai.custom.alarm.condition.AlarmCondition; +import com.eactive.eai.custom.alarm.event.AlarmEvent; +import com.eactive.eai.custom.alarm.key.AlarmKey; +import com.eactive.eai.custom.alarm.key.CoreAlarmKey; import com.eactive.eai.env.ElinkConfig; import com.eactive.eai.inbound.processor.Processor; import com.ext.eai.common.stdmessage.STDMessageKeys; @@ -49,7 +55,10 @@ public class RESTProcess extends HTTPProcess { static final long serialVersionUID = 1L; public void outboundCtrlCallServiceAsync() throws Exception { - // async에서는 인터페이스 값을 설정하지 않고 Adapter의 타임아웃을 쓰기위해서 설정하지 않음 + // 인터페이스에 셋팅된 타임아웃설정 + int iTimeoutValue = getTimeoutCodeToValue(); + this.timeout = iTimeoutValue * 1000; + this.tempProp.put(INTERFACE_TIME_OUT, "" + this.timeout); try { this.tempProp.put(HttpClientAdapterServiceKey.LOG_PROCESS_NO, this.logPssSno); this.resObject = HttpSender.callService(this.adapterGroupName, this.outboundProp, this.reqObject, @@ -92,20 +101,24 @@ public class RESTProcess extends HTTPProcess { String circuitBreakerUseYn = PropManager.getInstance().getProperty("CircuitBreaker", "useYn"); try { - if("Y".equals(circuitBreakerUseYn)){ - String apiId = reqEaiMsg.getEAISvcCd(); - CircuitBreaker circuitBreaker = CircuitBreakerManager.getInstance().getCircuitBreaker(apiId); + if ("Y".equals(circuitBreakerUseYn)) { + String apiId = reqEaiMsg.getEAISvcCd(); + CircuitBreaker circuitBreaker = CircuitBreakerManager.getInstance().getCircuitBreaker(apiId); - // ObjectMapper 인스턴스 생성 - ObjectMapper objectMapper = new ObjectMapper(); + // ObjectMapper 인스턴스 생성 + ObjectMapper objectMapper = new ObjectMapper(); - // 서킷 브레이커의 메트릭 정보와 상태 정보를 직접 Node로 변환 - ObjectNode combinedNode = objectMapper.createObjectNode(); - combinedNode.put("state", circuitBreaker.getState().toString()); - combinedNode.set("metrics", objectMapper.valueToTree(circuitBreaker.getMetrics())); + // 서킷 브레이커의 메트릭 정보와 상태 정보를 직접 Node로 변환 + ObjectNode combinedNode = objectMapper.createObjectNode(); + combinedNode.put("state", circuitBreaker.getState().toString()); + combinedNode.set("metrics", objectMapper.valueToTree(circuitBreaker.getMetrics())); + + logger.info("CircuitBreaker state " + combinedNode.toString()); + this.resObject = circuitBreaker.executeCallable(() -> HttpSender + .callService(this.adapterGroupName, this.outboundProp, this.reqObject, this.tempProp)); + + - logger.info("CircuitBreaker state "+combinedNode.toString()); - this.resObject = circuitBreaker.executeCallable(() -> HttpSender.callService(this.adapterGroupName, this.outboundProp, this.reqObject, this.tempProp)); }else{ this.resObject = HttpSender.callService(this.adapterGroupName, this.outboundProp, this.reqObject, this.tempProp); } @@ -439,7 +452,12 @@ public class RESTProcess extends HTTPProcess { PropertiesUtil.copyPropertyIfPresent(this.callProp, this.tempProp, HttpAdapterServiceKey.INBOUND_PATH_VARIABLES); PropertiesUtil.copyPropertyIfPresent(this.callProp, this.tempProp, HttpAdapterServiceKey.INBOUND_REMOTE_ADDR); PropertiesUtil.copyPropertyIfPresent(this.callProp, this.tempProp, HttpAdapterServiceKey.INBOUND_SCHEME); - + PropertiesUtil.copyPropertyIfPresent(this.callProp, this.tempProp, HttpAdapterServiceKey.INBOUND_REQUESTED_TIME); // jwhong + PropertiesUtil.copyPropertyIfPresent(this.callProp, this.tempProp, HttpAdapterServiceKey.GUID); // jwhong + PropertiesUtil.copyPropertyIfPresent(this.callProp, this.tempProp, HttpAdapterServiceKey.INBOUND_TOKEN); // jwhong + PropertiesUtil.copyPropertyIfPresent(this.callProp, this.tempProp, HttpAdapterServiceSupport.PROPERTIES_NAME_CLIENT_ID); // jwhong + PropertiesUtil.copyPropertyIfPresent(this.callProp, this.tempProp, TransactionContextKeys.X_LOAN_TOKEN); + String svcName = getServiceId(this.reqEaiMsg); if (svcName == null) { svcName = ""; @@ -499,6 +517,7 @@ public class RESTProcess extends HTTPProcess { String url = StringUtils.removeEnd(simAddr, "/") + "/mockapi/" + this.reqEaiMsg.getEAISvcCd(); this.outboundProp.put(HttpClientAdapterServiceKey.URL, url); + this.tempProp.remove(HttpAdapterServiceKey.INBOUND_REWRITE_PATH); logger.debug("simUrl=" + url); } } catch (Exception e) { diff --git a/src/main/java/com/eactive/eai/outbound/SocketProcess.java b/src/main/java/com/eactive/eai/outbound/SocketProcess.java index cb08133..c4fdd29 100644 --- a/src/main/java/com/eactive/eai/outbound/SocketProcess.java +++ b/src/main/java/com/eactive/eai/outbound/SocketProcess.java @@ -32,10 +32,16 @@ import com.eactive.eai.control.SocketSender; import com.eactive.eai.control.Transform; import com.eactive.eai.env.ElinkConfig; 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.parser.StandardReader; +import com.eactive.eai.message.service.InterfaceMapper; import com.ext.eai.common.stdmessage.STDMessageKeys; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.StringUtils; public class SocketProcess extends DefaultProcess { static final long serialVersionUID = 1L; @@ -122,9 +128,10 @@ public class SocketProcess extends DefaultProcess { } public void outboundCtrlCallServiceAsync() throws Exception { - /** - * async에서는 인터페이스 값을 설정하지 않고 Adapter의 타임아웃을 쓰기위해서 설정하지 않음 - */ + // 인터페이스에 셋팅된 타임아웃설정 + int iTimeoutValue = getTimeoutCodeToValue(); + this.timeout = iTimeoutValue * 1000; + this.tempProp.put(INTERFACE_TIME_OUT, "" + this.timeout); try { this.resObject = SocketSender.callService(this.adapterGroupName, this.outboundProp, this.reqObject, this.tempProp); @@ -426,6 +433,8 @@ public class SocketProcess extends DefaultProcess { } if (com.eactive.eai.adapter.Keys.IF_STANDARD.equals(this.adptrMsgPtrnCd)) { + String restOption = this.reqEaiMsg.getCurrentSvcMsg().getRestOption(); + setStandardRouteInfo(restOption); AdapterManager adapterManager = AdapterManager.getInstance(); AdapterGroupVO adptGrpVO = adapterManager.getAdapterGroupVO(adapterGroupName); AdapterVO adptVO = null; @@ -451,8 +460,29 @@ public class SocketProcess extends DefaultProcess { String txTmotTktm = prop.getProperty("timeout", "50"); setTimeout(this.reqEaiMsg, StringUtil.stringFormat(txTmotTktm, true, '0', 3)); + String returnType = getReturnType(this.reqEaiMsg); + + if (STDMessageKeys.SEND_RECV_CD_RECV.equals(returnType)) { // 소켓이고 비동기Outbound인데, 표준메세지 요청구분가 R은 A-S 패턴의 응답 + // 일떄만, 아래 로직(메세지부를 제거하고 보냄.) + + StandardMessage standardMessage = this.reqEaiMsg.getStandardMessage(); + + final String MESSAGE_PART = "Message"; + final String MESSAGE_PART_HEADER_PART = "Message.Msg_Header"; + final String MESSAGE_PART_BODY_PART = "Message.Msg_Body"; + + StandardItem messagePart = standardMessage.findItem(MESSAGE_PART); + messagePart.setHidden(true); + messagePart.setSize(0); + + StandardItem messageHeaderPart = standardMessage.findItem(MESSAGE_PART_HEADER_PART); + messageHeaderPart.setSize(0); + StandardItem messageBodyPart = standardMessage.findItem(MESSAGE_PART_BODY_PART); + messageBodyPart.setSize(0); + } this.reqObject = makeStandardMessageData(this.reqEaiMsg, this.adptrMsgType, this.reqObject, this.outboundCharset); + if(this.reqObject instanceof String) { this.reqObject = ((String) this.reqObject).getBytes(this.outboundCharset); } @@ -680,6 +710,25 @@ public class SocketProcess extends DefaultProcess { } } + + protected void setStandardRouteInfo(String routeOption) throws JsonProcessingException { + if(StringUtils.isBlank(routeOption)) { + return ; + } + JsonNode rootNode = new ObjectMapper().readTree(routeOption); + JsonNode standardCommonFields = rootNode.get("standardCommonFields"); + + if (standardCommonFields != null && standardCommonFields.isObject()) { + standardCommonFields.fields().forEachRemaining(field -> { + String key = field.getKey(); + String value = field.getValue().asText(); + + StandardMessage standardMessage = this.reqEaiMsg.getStandardMessage(); + standardMessage.setData(key, value); + }); + } + } + @Override public void transControlHeaderTrnsformSinglesRes() throws Exception { diff --git a/src/main/java/com/eactive/eai/util/ByteCharSequence.java b/src/main/java/com/eactive/eai/util/ByteCharSequence.java index da287a1..b5e2a05 100644 --- a/src/main/java/com/eactive/eai/util/ByteCharSequence.java +++ b/src/main/java/com/eactive/eai/util/ByteCharSequence.java @@ -52,6 +52,6 @@ public class ByteCharSequence implements CharSequence{ if (m.find()){ index = m.start(); } - System.out.println("index = " + index); + // System.out.println("index = " + index); } } diff --git a/src/main/java/com/eactive/eai/util/CryptoUtil.java b/src/main/java/com/eactive/eai/util/CryptoUtil.java index d7849f1..8e331c0 100644 --- a/src/main/java/com/eactive/eai/util/CryptoUtil.java +++ b/src/main/java/com/eactive/eai/util/CryptoUtil.java @@ -51,20 +51,20 @@ public class CryptoUtil { String key = "ONAuROzlqWB4VuBwO5C/FA=="; String text = "Hello AES 한글"; - System.out.println("Original Text: " + text); + // System.out.println("Original Text: " + text); long startEncryptTime = System.nanoTime(); String enc = encryptAES(key, text); long endEncryptTime = System.nanoTime(); long encryptDuration = endEncryptTime - startEncryptTime; - System.out.println("Encrypted Text: " + enc); - System.out.println("Encryption took: " + encryptDuration + " nanoseconds"); + // System.out.println("Encrypted Text: " + enc); + // System.out.println("Encryption took: " + encryptDuration + " nanoseconds"); long startDecryptTime = System.nanoTime(); String dec = decryptAES(key, enc); long endDecryptTime = System.nanoTime(); long decryptDuration = endDecryptTime - startDecryptTime; - System.out.println("Decrypted Text: " + dec); - System.out.println("Decryption took: " + decryptDuration + " nanoseconds"); + // System.out.println("Decrypted Text: " + dec); + // System.out.println("Decryption took: " + decryptDuration + " nanoseconds"); } } \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/util/IpUtil.java b/src/main/java/com/eactive/eai/util/IpUtil.java index 93c4e5a..a02fbf9 100644 --- a/src/main/java/com/eactive/eai/util/IpUtil.java +++ b/src/main/java/com/eactive/eai/util/IpUtil.java @@ -38,9 +38,9 @@ public class IpUtil { String matchdIps = "192.168.0.1,192.168.0.0/24,192.168.1.*"; String requestIp = "192.168.1.2"; if (IpUtil.isMatchIp(matchdIps, requestIp)) { - System.out.println(true); + // System.out.println(true); } else { - System.out.println(false); + // System.out.println(false); } } diff --git a/src/main/java/com/eactive/eai/util/JsonBeatiUtil.java b/src/main/java/com/eactive/eai/util/JsonBeatiUtil.java index 1066703..8322d15 100644 --- a/src/main/java/com/eactive/eai/util/JsonBeatiUtil.java +++ b/src/main/java/com/eactive/eai/util/JsonBeatiUtil.java @@ -135,7 +135,7 @@ public class JsonBeatiUtil { data += "} "; data = "{\"EAI_UJSON2DEPTHEXT_REQ1\":{\"abc\":\"cba \",\"grid1\":[{\"long1\":1,\"data2\":\" \",\"grid2\":[{\"data3\":\"12345\",\"big4\":\"14.00000\"},{\"data3\":\"13 \",\"big4\":\"14.00001\"}]},{\"long1\":10000,\"data2\":\" \",\"grid2\":[{\"data3\":\"23 \",\"big4\":\"24.00000\"}]},{\"long1\":1000000000,\"data2\":\" \",\"grid2\":[{\"data3\":\"33 \",\"big4\":\"0.00000\"},{\"data3\":\" \",\"big4\":\"0.00034\"},{\"data3\":\"35 \",\"big4\":\"0.00036\"}]}],\"abcd\":\"123\",\"grid3\":[{\"long1\":1,\"data2\":\" \",\"grid4\":[{\"data5\":\"00023\",\"big6\":\"24\"}]},{\"long1\":1000000000,\"data2\":\" \",\"grid4\":[{\"data5\":\"00033\",\"big6\":\"0\"},{\"data5\":\" \",\"big6\":\"34\"},{\"data5\":\"00035\",\"big6\":\"900000003600011\"}]}]}}"; - System.out.println(JsonBeatiUtil.SimpleBeautiful(data)); + // System.out.println(JsonBeatiUtil.SimpleBeautiful(data)); } } diff --git a/src/main/java/com/eactive/eai/util/JsonPathUtil.java b/src/main/java/com/eactive/eai/util/JsonPathUtil.java index 0f3e9b9..845d7af 100644 --- a/src/main/java/com/eactive/eai/util/JsonPathUtil.java +++ b/src/main/java/com/eactive/eai/util/JsonPathUtil.java @@ -104,22 +104,22 @@ public class JsonPathUtil { public static void main(String[] args) { String jsonString = "{ \"person\": { \"name\": \"John\", \"age\": 30, \"groups\": [ { \"id\": 1, \"name\": \"Group A\" }, { \"id\": 2, \"name\": \"Group B\" }, { \"id\": 3, \"name\": \"Group C\" } ] } }"; - System.out.println("Source JSON: \n" + jsonString); + // System.out.println("Source JSON: \n" + jsonString); // 경로를 사용하여 값 가져오기 (반복되는 그룹 포함) String getPath = "/person/groups/1/name"; String secondGroupName = getValueAtPath(jsonString, getPath); - System.out.println("getPath: " + getPath + " -> " + secondGroupName); + // System.out.println("getPath: " + getPath + " -> " + secondGroupName); // 경로를 사용하여 값 설정하기 (반복되는 그룹 포함) 및 Pretty 출력 String putPath = "/person/groups/2/name"; String updatedJsonString = setValueAtPath(jsonString, putPath, "Group Z", true); - System.out.println("putPath: " + putPath); - System.out.println("Updated JSON (Pretty): \n" + updatedJsonString); + // System.out.println("putPath: " + putPath); + // System.out.println("Updated JSON (Pretty): \n" + updatedJsonString); getPath = "/person/name"; - System.out.println("getPath: " + getPath + " -> " + getValueAtPath(jsonString, getPath)); + // System.out.println("getPath: " + getPath + " -> " + getValueAtPath(jsonString, getPath)); getPath = "/person/age"; - System.out.println("getPath: " + getPath + " -> " + getValueAtPath(jsonString, getPath)); + // System.out.println("getPath: " + getPath + " -> " + getValueAtPath(jsonString, getPath)); } } diff --git a/src/main/java/com/eactive/eai/util/json/JsonPathsTransform.java b/src/main/java/com/eactive/eai/util/json/JsonPathsTransform.java index dca2a3d..ca0600e 100644 --- a/src/main/java/com/eactive/eai/util/json/JsonPathsTransform.java +++ b/src/main/java/com/eactive/eai/util/json/JsonPathsTransform.java @@ -47,7 +47,7 @@ public class JsonPathsTransform { String encLog = transformer.getClass().getName() + " : " + String.format("path=%s, orgText[%s] plain[%s] newText[%s]", path, currentValue, transformer.getProperty("PLAIN_VALUE"), newValue); - System.out.println(encLog); + // System.out.println(encLog); logger.debug(encLog); } } catch (Exception e) { diff --git a/src/main/java/com/eactive/eai/util/json/JsonSimplePathsTransform.java b/src/main/java/com/eactive/eai/util/json/JsonSimplePathsTransform.java index 5e16ed9..2af3b2b 100644 --- a/src/main/java/com/eactive/eai/util/json/JsonSimplePathsTransform.java +++ b/src/main/java/com/eactive/eai/util/json/JsonSimplePathsTransform.java @@ -30,7 +30,7 @@ public class JsonSimplePathsTransform { if(logger.isDebug()) { // FIXME : kbank - 로그내용 수정 String encLog = transformer.getClass().getName() +" : "+ String.format("path=%s, orgText[%s] plain[%s] newText[%s]", path, currentValue, transformer.getProperty("PLAIN_VALUE"), newValue); - System.out.println(encLog); + // System.out.println(encLog); logger.debug(encLog); } setNodeValue(getParentNode(rootNode, getParentPath(path)), getFieldName(path), newValue); diff --git a/src/main/java/com/kbstar/eai/common/header/SHINBOHeaderAction.java b/src/main/java/com/kbstar/eai/common/header/SHINBOHeaderAction.java index 3b248db..dee555f 100644 --- a/src/main/java/com/kbstar/eai/common/header/SHINBOHeaderAction.java +++ b/src/main/java/com/kbstar/eai/common/header/SHINBOHeaderAction.java @@ -171,7 +171,7 @@ public class SHINBOHeaderAction extends HeaderActionSupport SHINBOHeaderAction sha = new SHINBOHeaderAction(); byte[] res = sha.addHeaderAD(orgData, message); - System.out.println("res]" +new String(res)); + // System.out.println("res]" +new String(res)); } */ } diff --git a/src/main/java/com/kbstar/eai/common/loader/EAILogFIleLoader.java b/src/main/java/com/kbstar/eai/common/loader/EAILogFIleLoader.java index c0a2b9f..d65885c 100644 --- a/src/main/java/com/kbstar/eai/common/loader/EAILogFIleLoader.java +++ b/src/main/java/com/kbstar/eai/common/loader/EAILogFIleLoader.java @@ -202,7 +202,7 @@ public class EAILogFIleLoader { in = new FileInputStream(configPath); p.load(in); } catch (Exception e){ - System.out.println("환경설정 파일이 없습니다. - 파일명 : " + configPath); + // System.out.println("환경설정 파일이 없습니다. - 파일명 : " + configPath); throw e; } finally{ @@ -211,7 +211,7 @@ public class EAILogFIleLoader { in.close(); } catch(Exception e) { - System.out.println("close error"); + // System.out.println("close error"); } } } @@ -225,16 +225,16 @@ public class EAILogFIleLoader { // String iniKey = p.getProperty("ini.key"); String encpval = p.getProperty("jdbc.pvalue"); - System.out.println("========================================================="); - System.out.println(" EAILogFileLoader Configuration - "+ new Date()); - System.out.println("========================================================="); + // System.out.println("========================================================="); + // System.out.println(" EAILogFileLoader Configuration - "+ new Date()); + // System.out.println("========================================================="); // System.out.println("driver = " + driver); // System.out.println("url = " + url); // System.out.println("ivalue = " + ival); // System.out.println("pvalue = " + encpval); // System.out.println("Table Owner = " + tableOwner); // System.out.println("iniFilePath = " + iniFilePath); - System.out.println("========================================================="); + // System.out.println("========================================================="); // ScpDbAgent agt = new ScpDbAgent(); // try { @@ -256,7 +256,7 @@ public class EAILogFIleLoader { try { date = new SimpleDateFormat("yyyyMMdd").parse(timeStr); // "yyyyMMddHHmmssSSS" } catch (ParseException e) { - System.out.println("getDayOfWeekNum error - "+timeStr); + // System.out.println("getDayOfWeekNum error - "+timeStr); // e.printStackTrace(); } long time = date.getTime(); @@ -281,7 +281,7 @@ public class EAILogFIleLoader { String[] info = null; try { - System.out.println(">> Log Date : " + cDay + ", rows=" + list.size()); + // System.out.println(">> Log Date : " + cDay + ", rows=" + list.size()); if( driver != null ) { Class.forName(driver); @@ -601,7 +601,7 @@ public class EAILogFIleLoader { // conn.commit(); } catch(Exception ex) { - System.out.println("ERROR SKIP INSERT - row : "+ position +", Error : " + ex.toString()); + // System.out.println("ERROR SKIP INSERT - row : "+ position +", Error : " + ex.toString()); // ex.printStackTrace(); if(!isForce) throw ex; } @@ -611,17 +611,17 @@ public class EAILogFIleLoader { catch(SQLException se) { // if(conn != null) conn.rollback(); if(info!=null) { - System.out.println("ERROR : DB 오류 - " + info.toString()); + // System.out.println("ERROR : DB 오류 - " + info.toString()); } else { - System.out.println("ERROR : DB 오류 - " + se.toString()); + // System.out.println("ERROR : DB 오류 - " + se.toString()); } // se.printStackTrace(); throw se; } catch(Exception e) { // if(conn != null) conn.rollback(); - System.out.println(e.toString()); + // System.out.println(e.toString()); // e.printStackTrace(); throw e; } @@ -630,13 +630,13 @@ public class EAILogFIleLoader { if(preparedStatement != null) preparedStatement.close(); } catch (SQLException sqle) { - System.out.println("SQLException was thrown: " + sqle.toString()); + // System.out.println("SQLException was thrown: " + sqle.toString()); } try { if(conn != null) conn.close(); } catch (SQLException sqle) { - System.out.println("SQLException was thrown: " + sqle.toString()); + // System.out.println("SQLException was thrown: " + sqle.toString()); } } } @@ -666,14 +666,14 @@ public class EAILogFIleLoader { } while (!"".equals(subMsgStr) && seq < 99); // TSEAILG02.BzwkDataSerno : NUMBER(2) } catch(Exception e) { - System.out.println("DB Logging[SLAVE] Failed - " + info[0] + "|" + info[1] + "|" + info[2] +"|seq="+seq); + // System.out.println("DB Logging[SLAVE] Failed - " + info[0] + "|" + info[1] + "|" + info[2] +"|seq="+seq); throw e; } finally { if(preparedStatement != null) { try { preparedStatement.close(); } catch (SQLException e) { - System.out.println("SQLException was thrown: " + e.toString()); + // System.out.println("SQLException was thrown: " + e.toString()); } } } @@ -729,21 +729,21 @@ public class EAILogFIleLoader { } } catch(Exception e) { - System.out.println(e.toString()); + // System.out.println(e.toString()); } finally { try { if(br != null) br.close(); } catch(Exception e) { - System.out.println(e.toString()); + // System.out.println(e.toString()); } } if(count > 0) { loadLog(cDay, list, true); } - System.out.println(String.format("## FILE=%s, INSERT ROW COUNTS : (%d/%d)", filePath, insertCount, totalCount)); + // System.out.println(String.format("## FILE=%s, INSERT ROW COUNTS : (%d/%d)", filePath, insertCount, totalCount)); } private String[] split(String data, String deli) { @@ -786,7 +786,7 @@ public class EAILogFIleLoader { String filePath = "C:\\trlog\\tran.log"; //args[1]; try { if(isReal && args.length < 2) { - System.out.println(getUsage()); + // System.out.println(getUsage()); System.exit(-1); } @@ -795,13 +795,13 @@ public class EAILogFIleLoader { filePath = args[1]; } - System.out.println("\n## START LOADING Infomation - " + configPath); + // System.out.println("\n## START LOADING Infomation - " + configPath); loader = new EAILogFIleLoader(); loader.init(configPath); loader.parse(filePath); } catch (Exception e) { - System.out.println("ERROR MAIN"); - System.out.println(e.toString()); + // System.out.println("ERROR MAIN"); + // System.out.println(e.toString()); System.exit(-2); } System.exit(0); diff --git a/src/main/java/com/openbanking/eai/common/token/OAuth2AccessTokenVO.java b/src/main/java/com/openbanking/eai/common/token/OAuth2AccessTokenVO.java index 78d4fb5..920121c 100644 --- a/src/main/java/com/openbanking/eai/common/token/OAuth2AccessTokenVO.java +++ b/src/main/java/com/openbanking/eai/common/token/OAuth2AccessTokenVO.java @@ -24,6 +24,7 @@ public class OAuth2AccessTokenVO implements AccessTokenVO, Serializable private Date expiration; private String scope; private String clientUseCode; + private String clientId; public OAuth2AccessTokenVO() { @@ -35,6 +36,7 @@ public class OAuth2AccessTokenVO implements AccessTokenVO, Serializable this.expiration = oAuth2AccessTokenVO.getExpiration(); this.scope = oAuth2AccessTokenVO.getScope(); this.clientUseCode = oAuth2AccessTokenVO.getClientUseCode(); + this.clientId = oAuth2AccessTokenVO.getClientId(); } public String getAccessToken() { @@ -92,6 +94,14 @@ public class OAuth2AccessTokenVO implements AccessTokenVO, Serializable public void setClientUseCode(String clientUseCode) { this.clientUseCode = clientUseCode; } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } public String toString() { return ReflectionToStringBuilder.toString(this, ToStringStyle.DEFAULT_STYLE);