Compare commits

..

14 Commits

20 changed files with 573 additions and 224 deletions
@@ -11,7 +11,9 @@ import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException; import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@@ -30,6 +32,7 @@ import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuil
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.TrustAllStrategy; import org.apache.hc.client5.http.ssl.TrustAllStrategy;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpRequestInterceptor; import org.apache.hc.core5.http.HttpRequestInterceptor;
import org.apache.hc.core5.http.HttpResponseInterceptor; import org.apache.hc.core5.http.HttpResponseInterceptor;
@@ -40,6 +43,7 @@ import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.adapter.Keys; import com.eactive.eai.adapter.Keys;
import com.eactive.eai.adapter.http.secure.HttpClient5SSLContextFactory; import com.eactive.eai.adapter.http.secure.HttpClient5SSLContextFactory;
import com.eactive.eai.common.TransactionContextKeys; import com.eactive.eai.common.TransactionContextKeys;
import com.eactive.eai.common.logger.HttpAdapterExtraHeaderVo;
import com.eactive.eai.common.message.EAIMessageKeys; import com.eactive.eai.common.message.EAIMessageKeys;
import com.eactive.eai.common.property.PropManager; import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager; import com.eactive.eai.common.server.EAIServerManager;
@@ -416,8 +420,24 @@ public abstract class HttpClient5AdapterServiceSupport implements HttpClientAdap
logProcessNo = 200; logProcessNo = 200;
} }
Header[] headers = request.getHeaders();
List<HttpAdapterExtraHeaderVo> headerVoList = null;
if ( headers != null && headers.length != 0 ) {
headerVoList = HttpAdapterExtraLogUtil.convertHeaderToListOfHttpAdapterExtraHeaderVo(headers);
} else {
headerVoList = new ArrayList<HttpAdapterExtraHeaderVo>();
}
String trimedPostBody = (String) context.getAttribute(HttpAdapterExtraLogUtil.BODY_FIELD_NAME);
if(StringUtils.isNotEmpty(trimedPostBody)) {
HttpAdapterExtraHeaderVo vo = new HttpAdapterExtraHeaderVo();
vo.setName(HttpAdapterExtraLogUtil.BODY_FIELD_NAME);
vo.setValue(trimedPostBody);
headerVoList.add(vo);
}
HttpAdapterExtraLogUtil.insertHttpAdapterExtraLog(uuid, logProcessNo, HttpAdapterExtraLogUtil.insertHttpAdapterExtraLog(uuid, logProcessNo,
contextAdapterGroupName, contextAdapterName, request.getHeaders(), url, request.getMethod()); contextAdapterGroupName, contextAdapterName, headerVoList, url, request.getMethod(), 0);
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -6,12 +6,9 @@ import java.math.BigDecimal;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
@@ -22,10 +19,6 @@ import java.util.Properties;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
// encrypt test by jwhong
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch; import org.apache.commons.lang3.time.StopWatch;
@@ -58,44 +51,35 @@ import org.json.simple.JSONObject;
import org.json.simple.JSONValue; import org.json.simple.JSONValue;
import org.json.simple.parser.JSONParser; import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException; import org.json.simple.parser.ParseException;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder;
import com.eactive.eai.adapter.AdapterPropManager;
import com.eactive.eai.adapter.http.HttpMemoryLogger; import com.eactive.eai.adapter.http.HttpMemoryLogger;
import com.eactive.eai.adapter.http.HttpMethodType; import com.eactive.eai.adapter.http.HttpMethodType;
import com.eactive.eai.adapter.http.client.HttpClient5AdapterServiceSupport; import com.eactive.eai.adapter.http.client.HttpClient5AdapterServiceSupport;
import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey; import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey;
import com.eactive.eai.adapter.http.client.HttpClientAdapterVO; import com.eactive.eai.adapter.http.client.HttpClientAdapterVO;
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey; import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey;
import com.eactive.eai.authserver.service.OAuth2Manager;
import com.eactive.eai.common.TransactionContextKeys; import com.eactive.eai.common.TransactionContextKeys;
import com.eactive.eai.common.authoutbound.AccessTokenManagerByDB; import com.eactive.eai.common.authoutbound.AccessTokenManagerByDB;
import com.eactive.eai.common.exception.ExceptionUtil; import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.message.MessageType; import com.eactive.eai.common.message.MessageType;
import com.eactive.eai.common.property.PropManager; import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.util.CommonLib; import com.eactive.eai.common.util.CommonLib;
import com.eactive.eai.common.util.JSONUtils; import com.eactive.eai.common.util.HttpAdapterExtraLogUtil;
import com.eactive.eai.common.util.JacksonUtil;
import com.eactive.eai.common.util.RestSendBodyLogUtils;
import com.eactive.eai.common.util.TxFileLogger; import com.eactive.eai.common.util.TxFileLogger;
import com.eactive.eai.common.util.XMLUtils; import com.eactive.eai.common.util.XMLUtils;
import com.eactive.eai.util.JsonPathUtil; import com.eactive.eai.util.JsonPathUtil;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath; 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.AccessTokenManager;
import com.openbanking.eai.common.token.AccessTokenVO; import com.openbanking.eai.common.token.AccessTokenVO;
import com.openbanking.eai.common.token.OAuth2AccessTokenVO; import com.openbanking.eai.common.token.OAuth2AccessTokenVO;
import edu.emory.mathcs.backport.java.util.Arrays;
/** /**
* 1. 기능 : EAI HTTP OutBound 용 어댑터로 수동 시스템의 HTTP 웹 컴포넌트를 GET/POST 방식으로 호출할 수 있는 * 1. 기능 : EAI HTTP OutBound 용 어댑터로 수동 시스템의 HTTP 웹 컴포넌트를 GET/POST 방식으로 호출할 수 있는
* 기능을 제공한다.<br> * 기능을 제공한다.<br>
@@ -128,8 +112,6 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
private boolean useAdapterToken; private boolean useAdapterToken;
private ObjectMapper mapper = new ObjectMapper();
/** /**
* 1. 기능 : REST API 통신에 사용 <br> * 1. 기능 : REST API 통신에 사용 <br>
* 2. 처리 개요 : - 속성 정보를 설정 하고 수동 시스템 서비스를 호출 한다. <br> * 2. 처리 개요 : - 속성 정보를 설정 하고 수동 시스템 서비스를 호출 한다. <br>
@@ -235,7 +217,7 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
} else if(sendData instanceof JSONObject) { } else if(sendData instanceof JSONObject) {
dataObject = sendData; dataObject = sendData;
} else { } else {
dataObject = JsonPathUtil.toTree(sendData); dataObject = JacksonUtil.readTree(sendData);
} }
} else if (MessageType.XML.equals(messageType)) { } else if (MessageType.XML.equals(messageType)) {
Document doc = XMLUtils.convertXmlDocument(sendData); Document doc = XMLUtils.convertXmlDocument(sendData);
@@ -384,23 +366,12 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
configureHttpClient(requestConfigBuilder, vo, method); configureHttpClient(requestConfigBuilder, vo, method);
assignFilterHeaders(method, tempProp); // OutBound PreFilter에서 설정한 Header내용 설정. assignFilterHeaders(method, tempProp); // OutBound PreFilter에서 설정한 Header내용 설정.
String postBody = "";
switch (HttpMethodType.getValue(rmethod)) { switch (HttpMethodType.getValue(rmethod)) {
case GET: case GET:
case DELETE: case DELETE:
HashMap<String, String> h = getParameters(dataObject); assignGetParam(dataObject, uri, method);
URIBuilder uriBuilder = new URIBuilder(uri);
for (Map.Entry<String, String> entry : h.entrySet()) {
uriBuilder.addParameter(entry.getKey(), entry.getValue());
}
URI fullUri = uriBuilder.build();
if (method instanceof HttpGet) {
((HttpGet) method).setUri(fullUri);
} else if (method instanceof HttpDelete) {
((HttpDelete) method).setUri(fullUri);
}
if (logger.isDebug()) {
logger.debug("HttpClientAdapterServiceRest] (get Method) QueryString = [" + fullUri.getQuery() + "]");
}
break; break;
case PUT: case PUT:
case POST: case POST:
@@ -409,13 +380,14 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
//assignPostBody(dataContent, contentType, vo.getEncode(), method); // jwhong commnet //assignPostBody(dataContent, contentType, vo.getEncode(), method); // jwhong commnet
// KJBank API 추적정보를 Header에 제공. jwhong // KJBank API 추적정보를 Header에 제공. jwhong
// String inboundToken= assignRequestKJHeaders(method, prop, tempProp ); // String inboundToken= assignRequestKJHeaders(method, prop, tempProp );
assignPostBody(dataObject, mimeType, charset, method, chunked); postBody = assignPostBody(dataObject, mimeType, charset, method, chunked);
break; break;
default: default:
break; break;
} }
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("HttpClientAdapterServiceRest] Request URI : " + method.getRequestUri());
logger.debug("HttpClientAdapterServiceRest] SEND (" + vo.getAdapterGroupName() + ") method.getParams()=[" logger.debug("HttpClientAdapterServiceRest] SEND (" + vo.getAdapterGroupName() + ") method.getParams()=["
+ method.getEntity() + "] "); + method.getEntity() + "] ");
} }
@@ -424,7 +396,7 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
// 전달 header 셋팅 // 전달 header 셋팅
// Adapter 레벨 header 보다 data로 넘어온 httpHeader를 우선 적용(header명이 같다면 덮어씀) // Adapter 레벨 header 보다 data로 넘어온 httpHeader를 우선 적용(header명이 같다면 덮어씀)
assignRequestHeaders(method, httpHeader, prop); assignRequestHeaders(method, httpHeader, prop, tempProp);
int status = -1; int status = -1;
@@ -468,6 +440,11 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
context.setAttribute(HttpClientAdapterServiceKey.LOG_PROCESS_NO, logProcessNo); context.setAttribute(HttpClientAdapterServiceKey.LOG_PROCESS_NO, logProcessNo);
} }
if (RestSendBodyLogUtils.isBodyLoggingApi(tempProp.getProperty("API_SERVICE_CODE"))) {
String trimmedBody = RestSendBodyLogUtils.getBodyByMaxSize(postBody);
context.setAttribute(HttpAdapterExtraLogUtil.BODY_FIELD_NAME, trimmedBody);
}
// encrypt algorithm type 추출 from adapter property jwhong // encrypt algorithm type 추출 from adapter property jwhong
// Properties properties = AdapterPropManager.getInstance().getProperties(vo.getAdapterName()); // jwhong // Properties properties = AdapterPropManager.getInstance().getProperties(vo.getAdapterName()); // jwhong
// String encryptAlgorithm = properties.getProperty("ENCRYPT_ALGORITHM"); // jwhong // String encryptAlgorithm = properties.getProperty("ENCRYPT_ALGORITHM"); // jwhong
@@ -737,6 +714,24 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
} }
} }
private void assignGetParam(Object dataObject, String uri, HttpUriRequestBase method)
throws Exception, URISyntaxException {
HashMap<String, String> h = getParameters(dataObject);
URIBuilder uriBuilder = new URIBuilder(uri);
for (Map.Entry<String, String> entry : h.entrySet()) {
uriBuilder.addParameter(entry.getKey(), entry.getValue());
}
URI fullUri = uriBuilder.build();
if (method instanceof HttpGet) {
((HttpGet) method).setUri(fullUri);
} else if (method instanceof HttpDelete) {
((HttpDelete) method).setUri(fullUri);
}
if (logger.isDebug()) {
logger.debug("HttpClientAdapterServiceRest] (get Method) QueryString = [" + fullUri.getQuery() + "]");
}
}
private void assignOutboundPropertyMap(Properties tempProp, int status, String responseString, private void assignOutboundPropertyMap(Properties tempProp, int status, String responseString,
Properties responseHeaderProp) { Properties responseHeaderProp) {
Map<String, Object> map = new HashMap<String, Object>(); Map<String, Object> map = new HashMap<String, Object>();
@@ -771,7 +766,6 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
* @return * @return
* @throws Exception * @throws Exception
*/ */
@SuppressWarnings("unchecked")
private Object assignResponseHeaders(HttpUriRequestBase method, byte[] responseMessage, String headerGroupName, private Object assignResponseHeaders(HttpUriRequestBase method, byte[] responseMessage, String headerGroupName,
String encode, String responseContentType, String relayHeaderKeys, int status, Properties responseHeaderProp) throws Exception { String encode, String responseContentType, String relayHeaderKeys, int status, Properties responseHeaderProp) throws Exception {
String messageType = MessageType.JSON; String messageType = MessageType.JSON;
@@ -798,10 +792,11 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
} }
if(StringUtils.equalsAny(messageType, MessageType.JSON)) { if(StringUtils.equalsAny(messageType, MessageType.JSON)) {
JSONObject headerJson = new JSONObject(); ObjectNode headerJson = JacksonUtil.createObjectNode();
if (StringUtils.equalsIgnoreCase(relayHeaderKeys, "ALL")) { if (StringUtils.equalsIgnoreCase(relayHeaderKeys, "ALL")) {
for (Enumeration<Object> e = responseHeaderProp.keys(); e.hasMoreElements(); ) { for (Enumeration<Object> e = responseHeaderProp.keys(); e.hasMoreElements(); ) {
String key = (String)e.nextElement(); String key = (String) e.nextElement();
headerJson.put(StringUtils.lowerCase(key), responseHeaderProp.getProperty(key)); headerJson.put(StringUtils.lowerCase(key), responseHeaderProp.getProperty(key));
} }
} else { } else {
@@ -816,23 +811,31 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
headerJson.put(HTTP_STATUS, String.valueOf(status)); headerJson.put(HTTP_STATUS, String.valueOf(status));
if (headerJson.size() <= 0) { if (headerJson.isEmpty()) {
return new String(responseMessage, charset); return new String(responseMessage, charset);
} }
JSONObject message = null; ObjectNode message;
if (responseMessage == null || responseMessage.length == 0) { if (responseMessage == null || responseMessage.length == 0) {
message = new JSONObject(); message = JacksonUtil.createObjectNode();
} else { } else {
message = parseJson(new String(responseMessage, charset)); JsonNode parsed = null;
if (message == null) { try {
message = new JSONObject(); parsed = JacksonUtil.readTree(new String(responseMessage, charset));
} catch (Exception e) {
logger.warn("response message parse error", e);
}
if (parsed == null || !parsed.isObject()) {
message = JacksonUtil.createObjectNode();
message.put("Malformed_Response_Message", new String(responseMessage, charset)); message.put("Malformed_Response_Message", new String(responseMessage, charset));
} else {
message = (ObjectNode) parsed;
} }
} }
if (StringUtils.isNotBlank(headerGroupName) && message != null) if (StringUtils.isNotBlank(headerGroupName) && message != null) {
message.put(headerGroupName, headerJson); message.set(headerGroupName, headerJson);
}
return message; return message;
} else if (StringUtils.equalsAny(messageType, MessageType.XML)) { } else if (StringUtils.equalsAny(messageType, MessageType.XML)) {
@@ -865,6 +868,8 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
} }
protected void setAuthHeaders(HttpUriRequestBase method, String authorization, String authorizationHeaderName) throws Exception { protected void setAuthHeaders(HttpUriRequestBase method, String authorization, String authorizationHeaderName) throws Exception {
if(StringUtils.isEmpty(authorizationHeaderName))
authorizationHeaderName = "Authorization";
method.setHeader(authorizationHeaderName, method.setHeader(authorizationHeaderName,
String.format("%s", authorization)); String.format("%s", authorization));
} }
@@ -909,7 +914,7 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
return false; return false;
} }
protected void assignRequestHeaders(HttpUriRequestBase method, Object httpHeader, Properties prop) { protected void assignRequestHeaders(HttpUriRequestBase method, Object httpHeader, Properties prop, Properties tempProp) {
if (httpHeader != null) { if (httpHeader != null) {
if ( httpHeader instanceof ObjectNode) { if ( httpHeader instanceof ObjectNode) {
ObjectNode objectNode = (ObjectNode) httpHeader; ObjectNode objectNode = (ObjectNode) httpHeader;
@@ -951,24 +956,31 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
} }
try { try {
JSONObject httpValues = (JSONObject) JSONValue.parse(httpSettingJsonStr); JsonNode httpValues = JacksonUtil.readTree(httpSettingJsonStr);
for (Object key : httpValues.keySet()) { if (httpValues == null || !httpValues.isObject()) {
Object obj = httpValues.get(key); logger.error("HTTP_HEADER_SETTING value is not json Type, skip.");
if ((obj instanceof JSONObject) || (obj instanceof JSONArray)) { } else {
Iterator<String> fieldNames = httpValues.fieldNames();
while (fieldNames.hasNext()) {
String key = fieldNames.next();
JsonNode obj = httpValues.get(key);
if (obj == null || obj.isObject() || obj.isArray()) {
continue; continue;
} }
method.setHeader((String) key, obj); String headerValue = obj.isNull() ? "" : obj.asText();
method.setHeader(key, headerValue);
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Request Header :" + (String) key + "=[" + (String) obj + "]"); logger.debug("Request Header :" + key + "=[" + headerValue + "]");
}
}
} }
} } catch (Exception e) {
logger.error("HTTP_HEADER_SETTING value is not json Type, skip.", e);
}catch (Exception e) {
logger.error("HTTP_HEADER_SETTING value is not JSONObject Type, skip.", e);
} }
} }
@@ -1042,7 +1054,7 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
} else if(eaiBody instanceof JSONObject) { } else if(eaiBody instanceof JSONObject) {
body = ((JSONObject)eaiBody).toJSONString(); body = ((JSONObject)eaiBody).toJSONString();
} else if(eaiBody instanceof ObjectNode) { } else if(eaiBody instanceof ObjectNode) {
body = mapper.writeValueAsString((ObjectNode) eaiBody); body = JacksonUtil.writeAsString((ObjectNode) eaiBody);
} else { } else {
body = eaiBody.toString(); body = eaiBody.toString();
} }
@@ -1170,7 +1182,7 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
uriVariables.add(fieldName); uriVariables.add(fieldName);
} }
if (MessageType.JSON.equals(messageType)) { if (MessageType.JSON.equals(messageType)) {
JsonNode jsonNode = JsonPathUtil.toTree(sendData); JsonNode jsonNode = JacksonUtil.readTree(sendData);
// JSONObject jsonObject; // JSONObject jsonObject;
// if (sendData instanceof JSONObject) { // if (sendData instanceof JSONObject) {
// jsonObject = (JSONObject) sendData; // jsonObject = (JSONObject) sendData;
@@ -0,0 +1,33 @@
package com.eactive.eai.adapter.http.client.impl.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey;
import com.eactive.eai.common.util.Logger;
public class DebugLoggerOutFilter implements HttpClientAdapterFilter, HttpAdapterServiceKey {
protected static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
@Override
public Object doPreFilter(String adptGrpName, String adptName, Properties prop, Object message, Properties tempProp)
throws Exception {
logger.debug("Outbound Filter SND adptGrpName : {}", adptGrpName);
logger.debug("Outbound Filter SND adptName : {}", adptName);
logger.debug("Outbound Filter SND prop : {}", prop);
logger.debug("Outbound Filter SND message : {}", message);
logger.debug("Outbound Filter SND tempProp : {}", tempProp);
return message;
}
@Override
public Object doPostFilter(String adptGrpName, String adptName, Properties prop, Object message,
Properties tempProp) throws Exception {
logger.debug("Outbound Filter RCV adptGrpName : {}", adptGrpName);
logger.debug("Outbound Filter RCV adptName : {}", adptName);
logger.debug("Outbound Filter RCV prop : {}", prop);
logger.debug("Outbound Filter RCV message : {}", message);
logger.debug("Outbound Filter RCV tempProp : {}", tempProp);
return message;
}
}
@@ -99,7 +99,7 @@ public abstract class HttpAdapterServiceSupport implements HttpAdapterService, H
} else if (obj instanceof JSONObject) { } else if (obj instanceof JSONObject) {
return ((JSONObject) obj).toJSONString(); return ((JSONObject) obj).toJSONString();
} else if (obj instanceof JsonNode) { } else if (obj instanceof JsonNode) {
return mapper.writeValueAsString((JsonNode) obj); return (JsonNode) obj;
} else { } else {
throw new Exception("RECEAIAHA001"); throw new Exception("RECEAIAHA001");
} }
@@ -22,10 +22,10 @@ import com.eactive.eai.inbound.error.InboundErrorInfoVO;
import com.eactive.eai.inbound.error.InboundErrorKeys; import com.eactive.eai.inbound.error.InboundErrorKeys;
import com.eactive.eai.util.HexaConverter; import com.eactive.eai.util.HexaConverter;
public class UnkownMessageLogUtils { public class UnknownMessageLogUtils {
static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
private UnkownMessageLogUtils() { private UnknownMessageLogUtils() {
throw new IllegalStateException("Utility class"); throw new IllegalStateException("Utility class");
} }
@@ -49,7 +49,7 @@ public class UnkownMessageLogUtils {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
sb.append(errorMsg).append("\n").append("Remote Addr : ").append(request.getRemoteAddr()).append("\n").append("Request URI : ") sb.append(errorMsg).append("\n").append("Remote Addr : ").append(request.getRemoteAddr()).append("\n").append("Request URI : ")
.append(request.getRequestURI()).append("\n").append("clientId=").append(clientId).append(",hexClientId=").append(hexClientId).append(",txProp=").append(prop).append("\n").append("Exception : ").append(e.getMessage()); .append(request.getRequestURI()).append("\n").append("clientId=").append(clientId).append(",hexClientId=").append(hexClientId).append(",txProp=").append(prop).append("\n").append("Exception : ").append(e.getMessage());
UnkownMessageLogUtils.logUnknownMessage(txId, adptGrpName, adptName, UnknownMessageLogUtils.logUnknownMessage(txId, adptGrpName, adptName,
"", "", false, errCode, sb.toString(), System.currentTimeMillis(), "", "", false, errCode, sb.toString(), System.currentTimeMillis(),
serverName, InboundErrorKeys.IN_UNKNOWN, message); serverName, InboundErrorKeys.IN_UNKNOWN, message);
} catch (Exception ex) { } catch (Exception ex) {
@@ -0,0 +1,33 @@
package com.eactive.eai.adapter.http.dynamic.filter;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.eactive.eai.common.util.Logger;
public class DebugLoggerInFilter implements HttpAdapterFilter {
protected static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
@Override
public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop,
HttpServletRequest request, HttpServletResponse response) throws Exception {
logger.debug("Inbound Filter RCV adptGrpName : {}", adptGrpName);
logger.debug("Inbound Filter RCV adptName : {}", adptName);
logger.debug("Inbound Filter RCV message : {}", message);
logger.debug("Inbound Filter RCV prop : {}", prop);
return message;
}
@Override
public Object doPostFilter(String adptGrpName, String adptName, Object resultMessage, Properties prop,
HttpServletRequest request, HttpServletResponse response) throws Exception {
logger.debug("Inbound Filter SND adptGrpName : {}", adptGrpName);
logger.debug("Inbound Filter SND adptName : {}", adptName);
logger.debug("Inbound Filter SND resultMessage : {}", resultMessage);
logger.debug("Inbound Filter SND prop : {}", prop);
return resultMessage;
}
}
@@ -31,7 +31,7 @@ import com.eactive.eai.adapter.http.HttpMemoryLogger;
import com.eactive.eai.adapter.http.HttpStatusException; import com.eactive.eai.adapter.http.HttpStatusException;
import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey; import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey;
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceSupport; import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceSupport;
import com.eactive.eai.adapter.http.dynamic.UnkownMessageLogUtils; import com.eactive.eai.adapter.http.dynamic.UnknownMessageLogUtils;
import com.eactive.eai.common.TransactionContextKeys; import com.eactive.eai.common.TransactionContextKeys;
import com.eactive.eai.common.exception.ExceptionUtil; import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.util.CommonLib; import com.eactive.eai.common.util.CommonLib;
@@ -213,6 +213,10 @@ public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport
stopWatch.stop(); stopWatch.stop();
String apiInternalErrorCode = prop.getProperty("API_INTERNAL_ERROR_CODE", "");
if(StringUtils.isNotEmpty(apiInternalErrorCode))
response.setStatus(500);
byte[] responseBytes = null; byte[] responseBytes = null;
String responseData = ""; String responseData = "";
if (RESPONSE_TYPE_ASYNC.equals(responseType)){ if (RESPONSE_TYPE_ASYNC.equals(responseType)){
@@ -254,10 +258,10 @@ public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport
responseData = new String((byte[]) result, encode); responseData = new String((byte[]) result, encode);
responseBytes = (byte[]) result; responseBytes = (byte[]) result;
} else if (result instanceof String) { } else if (result instanceof String) {
responseBytes = ((String)result).getBytes(); responseBytes = ((String)result).getBytes(encode);
if ( StringUtils.isBlank((String)result ) ) { if ( StringUtils.isBlank((String)result ) ) {
responseData = ElinkConfig.getAsyncDummyDataForAdapterGroup(adptGrpName, adptName); responseData = ElinkConfig.getAsyncDummyDataForAdapterGroup(adptGrpName, adptName);
responseBytes = responseData.getBytes(); responseBytes = responseData.getBytes(encode);
} }
} }
@@ -337,10 +341,10 @@ public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport
} catch (Exception e) { } catch (Exception e) {
try { try {
UnkownMessageLogUtils.logUnkownMessage(adptGrpName, adptName, requestBytes != null ? new String(requestBytes, encode) : null, prop, request, response, UnknownMessageLogUtils.logUnkownMessage(adptGrpName, adptName, requestBytes != null ? new String(requestBytes, encode) : null, prop, request, response,
"RECEAIIRP202", e); "RECEAIIRP202", e);
} catch (UnsupportedEncodingException e1) { } catch (UnsupportedEncodingException e1) {
UnkownMessageLogUtils.logUnkownMessage(adptGrpName, adptName, requestBytes != null ? new String(requestBytes) : null, prop, request, response, UnknownMessageLogUtils.logUnkownMessage(adptGrpName, adptName, requestBytes != null ? new String(requestBytes) : null, prop, request, response,
"RECEAIIRP202", e); "RECEAIIRP202", e);
} }
if (traceLevel >= 3){ if (traceLevel >= 3){
@@ -242,15 +242,16 @@ public class AccessTokenManagerByDB implements Lifecycle {
@Override @Override
public AccessTokenVO apply(AccessTokenVO accessToken) { public AccessTokenVO apply(AccessTokenVO accessToken) {
long intervalTime = System.currentTimeMillis() + (credential.getIntervalSec() * 1000); long intervalTime = System.currentTimeMillis() + (credential.getIntervalSec() * 1000);
// // 토큰이 없거나, 다음 스케줄 시간 전에 만료될 경우 재발급 // // 토큰이 없거나, 다음 스케줄 시간 전에 만료될 경우 재발급
if (accessToken == null) { if (accessToken == null) {
logger.debug("Token not exists for adapter group: {}", adapterGroupName);
return issueToken(credential); return issueToken(credential);
} else if(accessToken.getExpiration() != null) { } else if(accessToken.getExpiration() != null) {
// 토큰이 있고 만료시간이 설정 된 경우 // 토큰이 있고 만료시간이 설정 된 경우
if(accessToken.getExpiration().before(new Date(intervalTime))){ if(accessToken.getExpiration().before(new Date(intervalTime))){
// 다음 스케줄 전에 토큰이 만료되는 경우 재발급 // 다음 스케줄 전에 토큰이 만료되는 경우 재발급
logger.debug("Token expired : {}, expiration date: {}", adapterGroupName, accessToken.getExpiration());
return issueToken(credential); return issueToken(credential);
} else { } else {
// 토큰이 아직 유효한 경우 // 토큰이 아직 유효한 경우
@@ -263,10 +264,8 @@ public class AccessTokenManagerByDB implements Lifecycle {
return accessToken; return accessToken;
} }
} }
}); });
logger.debug("Token issuance completed for adapter group: {}", adapterGroupName); logger.debug("Token issuance completed for adapter group: {}", adapterGroupName);
} catch (Exception e) { } catch (Exception e) {
logger.error("Token issuance failed for adapter group: {}", adapterGroupName, e); logger.error("Token issuance failed for adapter group: {}", adapterGroupName, e);
@@ -1,9 +1,9 @@
package com.eactive.eai.common.exception; package com.eactive.eai.common.exception;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.json.simple.JSONValue;
import com.eactive.eai.adapter.AdapterGroupVO; import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterManager; import com.eactive.eai.adapter.AdapterManager;
@@ -60,6 +60,9 @@ public class ExceptionHandler {
} }
public static EAIMessage handle(EAIMessage eaiMessage) { public static EAIMessage handle(EAIMessage eaiMessage) {
Properties prop = eaiMessage.getCallProp();
prop.setProperty("API_INTERNAL_ERROR_CODE", eaiMessage.getRspErrCd());
String inAdapterGroupName = eaiMessage.getSngSysItfTp(); String inAdapterGroupName = eaiMessage.getSngSysItfTp();
AdapterManager manager = AdapterManager.getInstance(); AdapterManager manager = AdapterManager.getInstance();
AdapterGroupVO group = manager.getAdapterGroupVO(inAdapterGroupName); AdapterGroupVO group = manager.getAdapterGroupVO(inAdapterGroupName);
@@ -13,6 +13,7 @@ import javax.annotation.PostConstruct;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -44,7 +45,8 @@ public class HsmCryptoService implements PropertyChangeListener {
private static final String PROP_GROUP = "HSM"; private static final String PROP_GROUP = "HSM";
private static final String PROP_CACHE_RELOAD_YN = "CACHE_RELOAD_YN"; private static final String PROP_CACHE_RELOAD_YN = "CACHE_RELOAD_YN";
private static final long CACHE_TTL_MS = 10 * 60 * 1000; // 10분, 필요시 PropManager로 외부화 private static final String PROP_CACHE_TTL_SEC = "CACHE_TTL_SEC";
private static long CACHE_TTL_MS = 10 * 60 * 1000; // 10분, 필요시 PropManager로 외부화
private static class CachedKey<T> { private static class CachedKey<T> {
final T key; final T key;
@@ -86,6 +88,9 @@ public class HsmCryptoService implements PropertyChangeListener {
if ("Y".equalsIgnoreCase(reloadYn)) { if ("Y".equalsIgnoreCase(reloadYn)) {
clearKeyCache(); clearKeyCache();
} }
String propCacheTtlSec = propManager.getProperty(PROP_GROUP, PROP_CACHE_TTL_SEC, "600");
CACHE_TTL_MS = (Integer.parseInt(propCacheTtlSec.trim())) * 1000; // 10분, 필요시 PropManager로 외부화
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@@ -94,13 +99,17 @@ public class HsmCryptoService implements PropertyChangeListener {
/** /**
* HSM KeyStore 에서 공개키를 반환합니다. 최초 1회만 HSM 통신하고 이후 캐시를 반환합니다. * HSM KeyStore 에서 공개키를 반환합니다. 최초 1회만 HSM 통신하고 이후 캐시를 반환합니다.
* HSM 장애 시 만료된 캐시가 있으면 그것을 반환하여 서비스 연속성을 유지합니다.
*/ */
public PublicKey getPublicKey(String keyAlias) throws HsmException { public PublicKey getPublicKey(String keyAlias) throws HsmException {
checkReady(); // 1. 유효한 캐시 즉시 반환 (HSM 상태 무관)
CachedKey<PublicKey> cached = publicKeyCache.get(keyAlias); CachedKey<PublicKey> cached = publicKeyCache.get(keyAlias);
if (cached != null && !cached.isExpired()) { if (cached != null && !cached.isExpired()) {
return cached.key; return cached.key;
} }
// 2. 캐시 미스 또는 만료 → HSM 갱신 시도
if (HsmManager.getInstance().isReady()) {
try { try {
Certificate cert = HsmManager.getInstance().getKeyStore().getCertificate(keyAlias); Certificate cert = HsmManager.getInstance().getKeyStore().getCertificate(keyAlias);
if (cert == null) { if (cert == null) {
@@ -113,27 +122,56 @@ public class HsmCryptoService implements PropertyChangeListener {
} catch (HsmException e) { } catch (HsmException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
throw new HsmException("공개키 조회 실패: " + e.getMessage(), e); logger.warn("HsmCryptoService] 공개키 HSM 조회 실패: " + e.getMessage());
} }
} }
// 3. HSM 조회 불가 → 만료 캐시 fallback
if (cached != null) {
logger.warn("HsmCryptoService] HSM 장애, 만료 공개키 캐시 fallback: alias=" + keyAlias);
return cached.key;
}
throw new HsmException("공개키 조회 불가: HSM 장애이며 캐시도 없습니다. alias=" + keyAlias);
}
/** /**
* HSM KeyStore 에서 AES 대칭키를 반환합니다. 최초 1회만 HSM 통신하고 이후 캐시를 반환합니다. * HSM KeyStore 에서 AES 대칭키를 반환합니다. 최초 1회만 HSM 통신하고 이후 캐시를 반환합니다.
* HSM 키 생성 시 CKA_EXTRACTABLE=true (ctkmu -x 플래그) 로 생성된 키만 반환됩니다. * HSM 키 생성 시 CKA_EXTRACTABLE=true (ctkmu -x 플래그) 로 생성된 키만 반환됩니다.
*
* [캐싱 전략]
* HSM 에서 가져온 P11SecretKey(PKCS11 핸들 래퍼)를 그대로 캐싱하면, HSM Provider 가
* 재초기화될 때 세션 무효화로 인해 캐시된 키를 사용한 Cipher 연산이 실패한다.
* 따라서 getEncoded() 로 키 바이트를 추출하여 SecretKeySpec(JVM 메모리 키) 으로 변환 후
* 캐싱한다. encryptAes/decryptAes 는 이미 JVM 소프트웨어 Cipher 를 사용하므로,
* HSM Provider 상태와 완전히 독립적으로 동작한다.
*
* HSM 장애 시 만료된 캐시가 있으면 그것을 반환하여 서비스 연속성을 유지합니다.
*/ */
public SecretKey getSecretKey(String keyAlias) throws HsmException { public SecretKey getSecretKey(String keyAlias) throws HsmException {
checkReady(); // 1. 유효한 캐시 즉시 반환 (HSM 상태 무관)
CachedKey<SecretKey> cached = secretKeyCache.get(keyAlias); CachedKey<SecretKey> cached = secretKeyCache.get(keyAlias);
if (cached != null && !cached.isExpired()) { if (cached != null && !cached.isExpired()) {
return cached.key; return cached.key;
} }
// 2. 캐시 미스 또는 만료 → HSM 갱신 시도
if (HsmManager.getInstance().isReady()) {
try { try {
KeyStore keyStore = HsmManager.getInstance().getKeyStore(); KeyStore keyStore = HsmManager.getInstance().getKeyStore();
java.security.Key key = keyStore.getKey(keyAlias, null); java.security.Key key = keyStore.getKey(keyAlias, null);
if (key == null) { if (key == null) {
throw new HsmException("인증서를 찾을 수 없습니다. alias=" + keyAlias); throw new HsmException("를 찾을 수 없습니다. alias=" + keyAlias);
} }
SecretKey secretKey = (SecretKey) key; SecretKey secretKey = (SecretKey) key;
// P11SecretKey → SecretKeySpec 변환: HSM Provider 의존성 제거
// getEncoded() 가 null 이면 non-extractable 키이므로 원본 유지
byte[] keyBytes = secretKey.getEncoded();
if (keyBytes != null) {
secretKey = new SecretKeySpec(keyBytes, secretKey.getAlgorithm());
}
secretKeyCache.put(keyAlias, new CachedKey<>(secretKey)); secretKeyCache.put(keyAlias, new CachedKey<>(secretKey));
logger.warn("HsmCryptoService] 대칭키 캐시 등록(갱신): alias=" + keyAlias); logger.warn("HsmCryptoService] 대칭키 캐시 등록(갱신): alias=" + keyAlias);
return secretKey; return secretKey;
@@ -141,10 +179,19 @@ public class HsmCryptoService implements PropertyChangeListener {
} catch (HsmException e) { } catch (HsmException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
throw new HsmException("AES 키 조회 실패: " + e.getMessage(), e); logger.warn("HsmCryptoService] 대칭키 HSM 조회 실패: " + e.getMessage());
} }
} }
// 3. HSM 조회 불가 → 만료 캐시 fallback
if (cached != null) {
logger.warn("HsmCryptoService] HSM 장애, 만료 대칭키 캐시 fallback: alias=" + keyAlias);
return cached.key;
}
throw new HsmException("키 조회 불가: HSM 장애이며 캐시도 없습니다. alias=" + keyAlias);
}
/** 캐시를 비웁니다. HSM 키 교체 후 재로드가 필요할 때 호출합니다. */ /** 캐시를 비웁니다. HSM 키 교체 후 재로드가 필요할 때 호출합니다. */
public void clearKeyCache() { public void clearKeyCache() {
secretKeyCache.clear(); secretKeyCache.clear();
@@ -271,13 +318,4 @@ public class HsmCryptoService implements PropertyChangeListener {
return decryptAes(secretKey, iv, ciphertext, null); return decryptAes(secretKey, iv, ciphertext, null);
} }
// -------------------------------------------------------------------------
// Private helpers
// -------------------------------------------------------------------------
private void checkReady() throws HsmException {
if (!HsmManager.getInstance().isReady()) {
throw new HsmException("HsmManager 가 초기화되지 않았습니다.");
}
}
} }
@@ -5,10 +5,13 @@ import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.nio.file.Files; import java.nio.file.Files;
import java.security.AuthProvider;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider; import java.security.Provider;
import java.security.Security; import java.security.Security;
import java.util.Base64; import java.security.UnrecoverableKeyException;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
@@ -43,6 +46,18 @@ import com.eactive.eai.common.util.Logger;
* name = SoftHSM * name = SoftHSM
* library = C:/SoftHSM2/lib/softhsm2-x64.dll * library = C:/SoftHSM2/lib/softhsm2-x64.dll
* slotListIndex = 0 * slotListIndex = 0
*
* ---------------------------------------------------------------------
* [세션 누적 방지 / 회로차단 로직 추가]
* 기존 구현은 재로드마다 KeyStore.getInstance(...).load(null, pin) 을 새로
* 호출하여 PKCS11 세션(C_OpenSession)이 계속 누적되고, 결국 HSM 파티션의
* 최대 세션 수를 초과하면서 reload 가 영구적으로 실패하는 문제가 있었다.
* 이를 방지하기 위해:
* 1) 정상 상황에서는 "기존 keyStore 인스턴스"에 다시 load() 하여 세션 재사용
* 2) 실제 키 조회(probe)로 세션이 살아있는지 검증
* 3) 연속 실패가 임계치를 넘으면 Provider 자체를 logout 후 완전히 재생성
* 4) 재생성마저 실패하면 마지막으로 성공한 keyStore 를 유지 (서비스 연속성 우선)
* ---------------------------------------------------------------------
*/ */
@Component @Component
public class HsmManager implements Lifecycle { public class HsmManager implements Lifecycle {
@@ -52,6 +67,7 @@ public class HsmManager implements Lifecycle {
private static final String GROUP_NAME = "HSM"; private static final String GROUP_NAME = "HSM";
private static final String PROP_CONFIG = "PKCS11_CONFIG"; private static final String PROP_CONFIG = "PKCS11_CONFIG";
private static final String PROP_PIN = "PIN"; private static final String PROP_PIN = "PIN";
private static final String PROP_RELOAD_INTERVAL_MINUTES = "RELOAD_INTERVAL_MINUTES";
private Provider pkcs11Provider; private Provider pkcs11Provider;
private volatile KeyStore keyStore; private volatile KeyStore keyStore;
@@ -62,7 +78,7 @@ public class HsmManager implements Lifecycle {
private volatile char[] pin; private volatile char[] pin;
// 재로드 주기 (분 단위). 필요시 PropManager로 외부화 가능. // 재로드 주기 (분 단위). 필요시 PropManager로 외부화 가능.
private static final long RELOAD_INTERVAL_MINUTES = 1; private static long RELOAD_INTERVAL_MINUTES = 1;
private ScheduledExecutorService scheduler; private ScheduledExecutorService scheduler;
private ScheduledFuture<?> reloadFuture; private ScheduledFuture<?> reloadFuture;
@@ -92,6 +108,9 @@ public class HsmManager implements Lifecycle {
} }
private void init() throws Exception { private void init() throws Exception {
String reloadIntervalStr = PropManager.getInstance().getProperty(GROUP_NAME, PROP_RELOAD_INTERVAL_MINUTES, "10");
RELOAD_INTERVAL_MINUTES = Long.parseLong(reloadIntervalStr);
EncryptionManager encManager = EncryptionManager.getInstance(); EncryptionManager encManager = EncryptionManager.getInstance();
String configContent = encManager.decryptDBData(PropManager.getInstance().getProperty(GROUP_NAME, PROP_CONFIG)); String configContent = encManager.decryptDBData(PropManager.getInstance().getProperty(GROUP_NAME, PROP_CONFIG));
@@ -117,6 +136,10 @@ public class HsmManager implements Lifecycle {
logger.warn("HsmManager] 초기화 완료. Provider=" + pkcs11Provider.getName()); logger.warn("HsmManager] 초기화 완료. Provider=" + pkcs11Provider.getName());
logKeyStore(this.keyStore);
}
private void logKeyStore(KeyStore keyStore) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
java.util.Enumeration<String> aliases = keyStore.aliases(); java.util.Enumeration<String> aliases = keyStore.aliases();
StringBuilder aliasList = new StringBuilder(); StringBuilder aliasList = new StringBuilder();
while (aliases.hasMoreElements()) { while (aliases.hasMoreElements()) {
@@ -128,11 +151,8 @@ public class HsmManager implements Lifecycle {
java.security.Key key = keyStore.getKey(alias, null); java.security.Key key = keyStore.getKey(alias, null);
if (key instanceof SecretKey) { if (key instanceof SecretKey) {
SecretKey secretKey = (SecretKey) key; SecretKey secretKey = (SecretKey) key;
if(secretKey.getEncoded() != null) { if (secretKey.getEncoded() == null) {
String encBase64 = Base64.getEncoder().encodeToString(secretKey.getEncoded()); logger.warn("HsmManager] HSM - secretKey null {} : [{}]", alias, secretKey);
logger.debug("HsmManager] HSM - {} : [{}]", alias, encBase64);
} else {
logger.debug("HsmManager] HSM - secretKey null {} : [{}]", alias, secretKey);
} }
} }
} }
@@ -140,7 +160,7 @@ public class HsmManager implements Lifecycle {
} }
/** /**
* 별도 스레드에서 주기적으로 KeyStore.load() 를 다시 호출하여 * 별도 스레드에서 주기적으로 KeyStore 를 다시 로드하여
* HSM 에 새로 생성/추가된 키를 인식하도록 한다. * HSM 에 새로 생성/추가된 키를 인식하도록 한다.
*/ */
private void startReloadScheduler() { private void startReloadScheduler() {
@@ -168,35 +188,85 @@ public class HsmManager implements Lifecycle {
try { try {
reloadKeyStoreIfNeeded(); reloadKeyStoreIfNeeded();
} catch (Throwable t) { } catch (Throwable t) {
logger.warn("HsmManager] KeyStore 주기적 재로드 실패: " + t.getMessage()); logger.warn("HsmManager] KeyStore 주기적 재로드 실패: " + t.getMessage(), t);
} }
} }
/** /**
* KeyStore 를 다시 로드한다. 외부(getSecretKey 등)에서 키 미스 발생 시 * KeyStore 를 다시 로드한다. 외부(getSecretKey 등)에서 키 미스 발생 시
* 즉시 재시도용으로 직접 호출할 수도 있다. * 즉시 재시도용으로 직접 호출할 수도 있다.
*
* 세션 누적 방지를 위해 새 KeyStore 인스턴스를 만들지 않고,
* 기존 keyStore 객체에 다시 load() 하여 기존 PKCS11 세션을 재사용한다.
* 연속 실패가 임계치를 넘으면 Provider 자체를 재생성한다.
*/ */
public synchronized void reloadKeyStoreIfNeeded() throws Exception { public synchronized void reloadKeyStoreIfNeeded() throws Exception {
if (pkcs11Provider == null) { if (pkcs11Provider == null) {
return; // HSM 비활성화 상태 return; // HSM 비활성화 상태
} }
try {
if (keyStore != null) {
keyStore.load(null, pin);
logger.warn("HsmManager] KeyStore 재로드 완료 (기존 세션 재사용).");
} else {
KeyStore ks = KeyStore.getInstance("PKCS11", pkcs11Provider); KeyStore ks = KeyStore.getInstance("PKCS11", pkcs11Provider);
ks.load(null, pin); ks.load(null, pin);
this.keyStore = ks; // volatile 필드 교체 - 다른 스레드에서 즉시 가시성 확보 this.keyStore = ks;
logger.warn("HsmManager] KeyStore 신규 생성 완료.");
logger.warn("HsmManager] KeyStore 재로드 완료.");
logAliases(ks);
} }
private void logAliases(KeyStore ks) throws Exception { logKeyStore(keyStore);
java.util.Enumeration<String> aliases = ks.aliases();
StringBuilder aliasList = new StringBuilder(); } catch (Exception e) {
while (aliases.hasMoreElements()) { logger.warn("HsmManager] KeyStore 재로드 실패:" + e.getMessage(), e);
if (aliasList.length() > 0) aliasList.append(", "); logger.warn("HsmManager] Provider 전체 재초기화를 시도합니다.");
aliasList.append(aliases.nextElement()); fullReinitialize();
}
}
/**
* 세션 누적, 네트워크 단절 등으로 일반 재로드가 더 이상 복구되지 않을 때
* 기존 세션을 정리하고 Provider 를 완전히 새로 생성한다.
*
* 신규 Provider/KeyStore 준비가 완전히 성공한 후에만 기존 Provider 를 제거하고 교체한다.
* 재초기화 중 예외가 발생하면 기존 Provider 와 keyStore 를 그대로 유지한다
* (서비스 중단보다 마지막 정상 상태 보존을 우선).
*/
private void fullReinitialize() throws Exception {
Provider oldProvider = this.pkcs11Provider;
try {
// 1. 신규 Provider 인스턴스 생성 (Security 미등록 상태)
String configContent = EncryptionManager.getInstance()
.decryptDBData(PropManager.getInstance().getProperty(GROUP_NAME, PROP_CONFIG));
Provider newProvider = createProvider(configContent.trim().replace("\\n", "\n"));
// 2. 신규 Provider 로 KeyStore 로드 테스트
// KeyStore.getInstance(type, providerInstance) 는 Security 등록 없이도 동작하므로
// 여기서 실패해도 oldProvider/keyStore 는 변경되지 않은 상태를 유지함
KeyStore ks = KeyStore.getInstance("PKCS11", newProvider);
ks.load(null, pin);
// 3. 신규 연결 성공 → 기존 Provider 정리 후 교체
if (oldProvider instanceof AuthProvider) {
try {
((AuthProvider) oldProvider).logout();
} catch (Exception logoutEx) {
logger.warn("HsmManager] 기존 세션 logout 실패(무시하고 진행): " + logoutEx.getMessage());
}
}
Security.removeProvider(oldProvider.getName());
Security.addProvider(newProvider);
this.pkcs11Provider = newProvider;
this.keyStore = ks;
logger.warn("HsmManager] Provider 전체 재초기화 성공.");
} catch (Exception e) {
logger.warn("HsmManager] Provider 전체 재초기화 실패. 이전 keyStore 를 그대로 유지합니다: " + e.getMessage(), e);
throw e;
} }
logger.warn("HsmManager] HSM 키 목록: [" + aliasList + "]");
} }
/** /**
@@ -242,6 +312,13 @@ public class HsmManager implements Lifecycle {
} }
if (pkcs11Provider != null) { if (pkcs11Provider != null) {
if (pkcs11Provider instanceof AuthProvider) {
try {
((AuthProvider) pkcs11Provider).logout();
} catch (Exception e) {
logger.warn("HsmManager] 종료 시 logout 실패(무시): " + e.getMessage());
}
}
Security.removeProvider(pkcs11Provider.getName()); Security.removeProvider(pkcs11Provider.getName());
} }
pkcs11Provider = null; pkcs11Provider = null;
@@ -282,4 +359,20 @@ public class HsmManager implements Lifecycle {
public boolean isReady() { public boolean isReady() {
return started && pkcs11Provider != null && keyStore != null; return started && pkcs11Provider != null && keyStore != null;
} }
/**
* isReady() 와 달리 실제 HSM 호출로 세션 생존 여부까지 확인하는 헬스체크.
* 모니터링/헬스체크 엔드포인트에서 사용을 권장한다.
*/
public boolean isHealthy() {
if (!isReady()) {
return false;
}
try {
logKeyStore(keyStore);
return true;
} catch (Exception e) {
return false;
}
}
} }
@@ -1,6 +1,7 @@
package com.eactive.eai.common.logger; package com.eactive.eai.common.logger;
import com.eactive.eai.common.logger.mapper.HttpAdapterExtraLogMapper; import com.eactive.eai.common.logger.mapper.HttpAdapterExtraLogMapper;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.data.entity.onl.logger.HttpAdapterExtraLog; import com.eactive.eai.data.entity.onl.logger.HttpAdapterExtraLog;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -10,6 +11,8 @@ import org.springframework.stereotype.Service;
@Service @Service
public class HttpLoggingService { public class HttpLoggingService {
static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
@Autowired @Autowired
private HttpAdapterExtraLogMapper mapper; private HttpAdapterExtraLogMapper mapper;
@@ -24,6 +27,7 @@ public class HttpLoggingService {
if (EAIDBLogControl.isEnable()) { if (EAIDBLogControl.isEnable()) {
try { try {
dbLogger.save(httpAdapterExtraLog); dbLogger.save(httpAdapterExtraLog);
logger.debug("inserted to DB");
} catch(Exception e){ } catch(Exception e){
String message = e.getMessage(); String message = e.getMessage();
// 오류 메시지 추가 - Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection // 오류 메시지 추가 - Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
@@ -33,9 +37,11 @@ public class HttpLoggingService {
EAIDBLogControl.setEnable(false); EAIDBLogControl.setEnable(false);
} }
fileLogger.writeFileLog(httpAdapterExtraLog); fileLogger.writeFileLog(httpAdapterExtraLog);
logger.debug("wrote to File");
} }
} else { } else {
fileLogger.writeFileLog(httpAdapterExtraLog); fileLogger.writeFileLog(httpAdapterExtraLog);
logger.debug("wrote to File");
} }
} }
} }
@@ -2,24 +2,25 @@ package com.eactive.eai.common.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.hc.core5.http.Header;
import com.eactive.eai.common.logger.HttpAdapterExtraHeaderVo; import com.eactive.eai.common.logger.HttpAdapterExtraHeaderVo;
import com.eactive.eai.common.logger.HttpAdapterExtraLogVo; import com.eactive.eai.common.logger.HttpAdapterExtraLogVo;
import com.eactive.eai.common.logger.HttpLoggingService; import com.eactive.eai.common.logger.HttpLoggingService;
import com.eactive.eai.common.logger.async.AsyncHttpLoggingPoolManager; import com.eactive.eai.common.logger.async.AsyncHttpLoggingPoolManager;
import com.eactive.eai.env.ElinkConfig; import com.eactive.eai.env.ElinkConfig;
import org.apache.hc.core5.http.Header;
import org.apache.commons.lang3.StringUtils;
public class HttpAdapterExtraLogUtil { public class HttpAdapterExtraLogUtil {
public static final int MAX_HEADER_VALUE_SIZE = 400;
public static final String BODY_FIELD_NAME = "eapim-adapter-send-body";
static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
public static boolean isHttpHeaderMode() { public static boolean isHttpHeaderMode() {
@@ -62,14 +63,19 @@ public class HttpAdapterExtraLogUtil {
httpAdapterExtraLogVo.setHttpMethod(httpMethod); httpAdapterExtraLogVo.setHttpMethod(httpMethod);
for (HttpAdapterExtraHeaderVo httpAdapterExtraHeaderVo : headerVoList) { for (HttpAdapterExtraHeaderVo httpAdapterExtraHeaderVo : headerVoList) {
// String name = httpAdapterExtraHeaderVo.getName();
// if(StringUtils.isNotBlank(name) && "authorization".equals(name.toLowerCase())) {
// httpAdapterExtraHeaderVo.setValue("{hidden}");
// }
String value = httpAdapterExtraHeaderVo.getValue(); String value = httpAdapterExtraHeaderVo.getValue();
if(StringUtils.isNotBlank(value) && value.length() > MAX_HEADER_VALUE_SIZE) {
if (value == null) { value = value.substring(0, 400) + "...";
httpAdapterExtraHeaderVo.setValue(value);
}else if(value == null){
httpAdapterExtraHeaderVo.setValue(" "); httpAdapterExtraHeaderVo.setValue(" ");
} }
} }
httpAdapterExtraLogVo.setHeaderList(headerVoList); httpAdapterExtraLogVo.setHeaderList(headerVoList);
httpAdapterExtraLogVo.setHttpStatus(httpStatus); httpAdapterExtraLogVo.setHttpStatus(httpStatus);
@@ -35,6 +35,10 @@ public final class JacksonUtil {
private static final Pattern TOKEN_PATTERN = Pattern.compile("([^\\[\\]]*)((?:\\[\\d+\\])*)"); private static final Pattern TOKEN_PATTERN = Pattern.compile("([^\\[\\]]*)((?:\\[\\d+\\])*)");
private static final Pattern INDEX_PATTERN = Pattern.compile("\\[(\\d+)\\]"); private static final Pattern INDEX_PATTERN = Pattern.compile("\\[(\\d+)\\]");
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private JacksonUtil() { private JacksonUtil() {
// 인스턴스화 방지 // 인스턴스화 방지
} }
@@ -76,6 +80,18 @@ public final class JacksonUtil {
return objectMapper.readTree(jsonStr); return objectMapper.readTree(jsonStr);
} }
public static JsonNode readTree(Object jsonData) throws JsonMappingException, JsonProcessingException {
return readTree(jsonData, OBJECT_MAPPER);
}
public static String writeAsString(JsonNode node) throws JsonProcessingException {
return OBJECT_MAPPER.writeValueAsString(node);
}
public static ObjectNode createObjectNode() {
return OBJECT_MAPPER.createObjectNode();
}
/** /**
* path 표현식으로 JsonNode를 탐색한다. * path 표현식으로 JsonNode를 탐색한다.
* 경로가 존재하지 않으면 null을 반환한다 (MissingNode가 아닌 진짜 null). * 경로가 존재하지 않으면 null을 반환한다 (MissingNode가 아닌 진짜 null).
@@ -258,4 +274,6 @@ public final class JacksonUtil {
} }
return indices; return indices;
} }
} }
@@ -0,0 +1,49 @@
package com.eactive.eai.common.util;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.util.HttpAdapterExtraLogUtil;
public class RestSendBodyLogUtils {
private static final String PROP_LOG_MAX_DATA_SIZE = "log.max.data.size";
private static final String PROP_GROUP = "RestSendBodyLog";
private RestSendBodyLogUtils() {
throw new IllegalStateException("Utility class");
}
/**
* API ID 별 어댑터 body 로그 남기는 지 여부
*
* @param apiId
* @return
*/
public static boolean isBodyLoggingApi(String apiId) {
if (StringUtils.isEmpty(apiId))
return false;
String logging = PropManager.getInstance().getProperty(PROP_GROUP, apiId, "N");
return StringUtils.equals("Y", logging);
}
/**
* body 로그에 남길 만큼 자르기
*
* @param body
* @return
*/
public static String getBodyByMaxSize(String body) {
String maxDataSize = PropManager.getInstance().getProperty(PROP_GROUP, PROP_LOG_MAX_DATA_SIZE);
int imaxDataSize = HttpAdapterExtraLogUtil.MAX_HEADER_VALUE_SIZE;
if (maxDataSize != null)
imaxDataSize = Integer.parseInt(maxDataSize);
if (body.length() > imaxDataSize)
return StringUtils.substring(body, 0, imaxDataSize) + "...";
return body;
}
}
@@ -6,6 +6,9 @@ import java.lang.reflect.Method;
import java.net.InetAddress; import java.net.InetAddress;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.rmi.RemoteException; import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.ExportException;
import java.security.Security; import java.security.Security;
import java.util.Arrays; import java.util.Arrays;
@@ -24,6 +27,7 @@ import com.eactive.eai.common.dao.Keys;
import com.eactive.eai.common.exception.ExceptionUtil; import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.lifecycle.LifecycleException; import com.eactive.eai.common.lifecycle.LifecycleException;
import com.eactive.eai.common.lifecycle.LifecycleManager; import com.eactive.eai.common.lifecycle.LifecycleManager;
import com.eactive.eai.common.logger.async.AsyncHttpLoggingPoolManager;
import com.eactive.eai.common.logger.async.AsyncLoggingPoolManager; import com.eactive.eai.common.logger.async.AsyncLoggingPoolManager;
import com.eactive.eai.common.property.PropManager; import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.routing.rmi.RemoteProxy; import com.eactive.eai.common.routing.rmi.RemoteProxy;
@@ -36,7 +40,6 @@ import com.eactive.eai.common.util.ServiceLocator;
import com.eactive.eai.common.util.ServiceLocatorException; import com.eactive.eai.common.util.ServiceLocatorException;
import com.eactive.eai.env.ConfigKeys; import com.eactive.eai.env.ConfigKeys;
import com.eactive.eai.env.ElinkConfig; import com.eactive.eai.env.ElinkConfig;
import com.eactive.eai.common.logger.async.AsyncHttpLoggingPoolManager;
/** /**
* eLink FrameWork이 초기화(Deploy)될 때 실행되어야 할 작업을 정의 * eLink FrameWork이 초기화(Deploy)될 때 실행되어야 할 작업을 정의
@@ -180,14 +183,25 @@ public class AppInitializer implements InitializingBean, DisposableBean {
this.shutdownWaitIntervalMs = shutdownWaitIntervalMs; this.shutdownWaitIntervalMs = shutdownWaitIntervalMs;
} }
private Registry rmiRegistry;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private void initRmiServer(int registryPort, int servicePort) throws RemoteException { private void initRmiServer(int registryPort, int servicePort) throws RemoteException {
try {
rmiRegistry = LocateRegistry.createRegistry(registryPort);
} catch (ExportException e) {
// 혹시 이전 정리 실패로 이미 떠있다면 재사용 시도
Logger.getLogger(Logger.LOGGER_DEFAULT)
.warn("Registry already exists on port " + registryPort + ", reusing", e);
rmiRegistry = LocateRegistry.getRegistry(registryPort);
}
rmiServiceExporter.setServiceName("RemoteProxy"); rmiServiceExporter.setServiceName("RemoteProxy");
rmiServiceExporter.setService(remoteProxy); rmiServiceExporter.setService(remoteProxy);
rmiServiceExporter.setServiceInterface(serviceInterface); rmiServiceExporter.setServiceInterface(serviceInterface);
rmiServiceExporter.setRegistryPort(registryPort); rmiServiceExporter.setRegistryPort(registryPort);
rmiServiceExporter.setServicePort(servicePort); rmiServiceExporter.setServicePort(servicePort);
rmiServiceExporter.setAlwaysCreateRegistry(true); rmiServiceExporter.setAlwaysCreateRegistry(false);
rmiServiceExporter.afterPropertiesSet(); rmiServiceExporter.afterPropertiesSet();
} }
@@ -11,6 +11,7 @@ import org.springframework.http.HttpStatus;
import com.eactive.eai.adapter.AdapterGroupVO; import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterManager; import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.adapter.http.HttpStatusException; import com.eactive.eai.adapter.http.HttpStatusException;
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey;
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException; import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException;
import com.eactive.eai.common.exception.ExceptionHandler; import com.eactive.eai.common.exception.ExceptionHandler;
import com.eactive.eai.common.message.EAIMessage; import com.eactive.eai.common.message.EAIMessage;
@@ -111,7 +112,13 @@ public abstract class RequestProcessorSupport implements Processor
**/ **/
public Object execute(Object message, Properties prop) throws HttpStatusException public Object execute(Object message, Properties prop) throws HttpStatusException
{ {
long msgRcvTm = System.currentTimeMillis(); String receivedTimestamp = prop.getProperty(HttpAdapterServiceKey.INBOUND_REQUESTED_TIME);
long msgRcvTm = 0L;
if(receivedTimestamp == null)
msgRcvTm = System.currentTimeMillis();
else
msgRcvTm = Long.parseLong(receivedTimestamp);
increaseRcvCount(); increaseRcvCount();
local.set(new Long(msgRcvTm)); local.set(new Long(msgRcvTm));
@@ -140,7 +140,7 @@ reader.FLAT=com.eactive.eai.message.parser.FlatReader
lifecycle.fireLifecycleEvent(STOPING_EVENT, this); lifecycle.fireLifecycleEvent(STOPING_EVENT, this);
readerMap.clear(); readerMap.clear();
readerMap = null; // readerMap = null;
started = false; started = false;
lifecycle.fireLifecycleEvent(STOPPED_EVENT, this); lifecycle.fireLifecycleEvent(STOPPED_EVENT, this);
} }
@@ -208,6 +208,10 @@ reader.FLAT=com.eactive.eai.message.parser.FlatReader
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
private void initReaderFactory(Properties config) { private void initReaderFactory(Properties config) {
if (readerMap == null) {
readerMap = new ConcurrentHashMap<>();
}
Class cl = null; Class cl = null;
StandardReader reader = null; StandardReader reader = null;
@@ -684,11 +684,17 @@ public abstract class DefaultProcess extends Process {
AdapterVO inboundAdapterVO = AdapterManager.getInstance().getAdapterVO(inboudnAdapterGroupName, inboudnAdapterName); AdapterVO inboundAdapterVO = AdapterManager.getInstance().getAdapterVO(inboudnAdapterGroupName, inboudnAdapterName);
String errorResponseHandlerClass = AdapterPropManager.getInstance().getProperty(inboundAdapterVO.getPropGroupName(), "ERR_MSG_HANDLER"); String errorResponseHandlerClass = AdapterPropManager.getInstance().getProperty(inboundAdapterVO.getPropGroupName(), "ERR_MSG_HANDLER");
if(StringUtils.isBlank(errorResponseHandlerClass)) { if(StringUtils.isBlank(errorResponseHandlerClass)) {
if ((com.eactive.eai.adapter.Keys.IF_STANDARD.equals(this.adptrMsgPtrnCd)
||com.eactive.eai.adapter.Keys.IF_SUBSTANDARD.equals(this.adptrMsgPtrnCd))) {
String errorCode = mapper.getErrorCode(resStandardMessage); String errorCode = mapper.getErrorCode(resStandardMessage);
String errorMsg = StringUtils.trim(mapper.getErrorMsg(resStandardMessage)); String errorMsg = StringUtils.trim(mapper.getErrorMsg(resStandardMessage));
String errorDesc = StringUtils.trim(resStandardMessage.findItemValue("MSG.MAIN_MSG.outp_msg_desc")); String errorDesc = StringUtils.trim(resStandardMessage.findItemValue("MSG.MAIN_MSG.outp_msg_desc"));
this.resEaiMsg.setRspErr("RECEAIINA001", String.format("[%s] %s (%s)", errorCode, errorMsg, errorDesc)); this.resEaiMsg.setRspErr("RECEAIINA001", String.format("[%s] %s (%s)", errorCode, errorMsg, errorDesc));
return; return;
} else {
this.resEaiMsg.setRspErr("RECEAIINA001", "비표준 오류 응답 수신");
return;
}
} }
logger.info(inboudnAdapterName+", Handle Error Message Class-"+errorResponseHandlerClass); logger.info(inboudnAdapterName+", Handle Error Message Class-"+errorResponseHandlerClass);
@@ -98,6 +98,10 @@ public class RESTProcess extends HTTPProcess {
this.timeout = iTimeoutValue * 1000; this.timeout = iTimeoutValue * 1000;
this.tempProp.put(INTERFACE_TIME_OUT, "" + this.timeout); this.tempProp.put(INTERFACE_TIME_OUT, "" + this.timeout);
this.tempProp.put("API_SERVICE_CODE", this.reqEaiMsg.getEAISvcCd());
this.tempProp.put("OUT_REQ_EAI_MSG", this.reqEaiMsg);
this.tempProp.put("OUT_REQ_STD_MSG", this.reqEaiMsg.getStandardMessage());
try { try {
// API별 이용 // API별 이용
String apiId = reqEaiMsg.getEAISvcCd(); String apiId = reqEaiMsg.getEAISvcCd();