package com.eactive.eai.adapter.service; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.StopWatch; import org.apache.mina.common.ByteBuffer; import org.json.simple.JSONObject; import org.json.simple.JSONValue; import org.springframework.context.annotation.Primary; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.util.AntPathMatcher; import com.eactive.eai.adapter.AdapterGroupVO; import com.eactive.eai.adapter.AdapterVO; import com.eactive.eai.adapter.Keys; import com.eactive.eai.adapter.http.HttpMemoryLogger; import com.eactive.eai.adapter.http.HttpMethodType; import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceSupport; import com.eactive.eai.common.context.ElinkTransactionContext; import com.eactive.eai.common.exception.ExceptionUtil; import com.eactive.eai.common.message.MessageType; import com.eactive.eai.common.util.CommonLib; import com.eactive.eai.common.util.Logger; import com.eactive.eai.inbound.action.ActionFactory; import com.eactive.eai.inbound.action.RequestAction; import com.eactive.eai.inbound.processor.Processor; import com.eactive.eai.message.StandardMessageUtil; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @Primary @Service public class DJErpApiAdapterService extends HttpAdapterServiceSupport { static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER); public static final String HEADER_GROUP = "HEADER_GROUP"; public static final String HTTP_STATUS = "HTTP_STATUS"; public static final String HEADER_KEYS = "HEADER_KEYS"; public static final String PROPERTIES_NAME_HTTP_REQUEST_METHOD = "httpRequestMethod"; public String callApi(HttpServletRequest request, HttpServletResponse response, Properties httpProp, AdapterGroupVO adapterGroupVO, AdapterVO adapterVO, Properties transactionProp) throws Exception { int traceLevel = 0; String adptGrpName = adapterGroupVO.getName(); String adptName = adapterVO.getName(); String urlDecodeYn = httpProp.getProperty(URL_DECODE_YN, "N"); String encode = StringUtils.defaultIfBlank(adapterGroupVO.getMessageEncode(), "UTF-8"); String traceLevelTemp = httpProp.getProperty(TRACE_LEVEL, "0"); String relayRequestHeaderKeys = httpProp.getProperty(HEADER_KEYS); String headerGroupName = httpProp.getProperty(HEADER_GROUP); boolean isParameterType = false; String message = null; String paramValue = null; String adptMsgType = null; transactionProp.put(INBOUND_METHOD, request.getMethod()); transactionProp.put(INBOUND_URI, request.getRequestURI()); transactionProp.put(INBOUND_QUERY_STRING, StringUtils.defaultString(request.getQueryString())); transactionProp.put(INBOUND_HEADER, getHeaders(request)); transactionProp.put(INBOUND_EXTPARAMS, StringUtils.defaultString(request.getQueryString())); if (StringUtils.equals(adapterVO.getAdapterGroupVO().getType(), Keys.TYPE_REST) || StringUtils.equals(adapterVO.getAdapterGroupVO().getType(), Keys.TYPE_HTTP_CUSTOM)) { // /api/v1/public/getUserInfo.svc String extUrl = StringUtils.removeStart(request.getRequestURI(), request.getContextPath()); transactionProp.put(INBOUND_EXTURI, extUrl); } else { transactionProp.put(INBOUND_EXTURI, getExtUri(request)); } transactionProp.put(INBOUND_CLIENT_IP, getClientIp(request)); transactionProp.put(Processor.REQUEST_ACTION, adapterVO.getAdapterGroupVO().getRefClass()); transactionProp.put(API_PATH, httpProp.getProperty(API_PATH, "")); transactionProp.put(INBOUND_REWRITE_PATH, getRewritePath(transactionProp.getProperty(INBOUND_EXTURI), transactionProp.getProperty(API_PATH))); transactionProp.put(INBOUND_REMOTE_ADDR, request.getRemoteAddr()); transactionProp.put(INBOUND_SCHEME, request.getScheme()); transactionProp.put(PRE_FILTERS, httpProp.getProperty(PRE_FILTERS, "")); transactionProp.put(POST_FILTERS, httpProp.getProperty(POST_FILTERS, "")); transactionProp.put(PROPERTIES_NAME_HTTP_REQUEST_METHOD, request.getMethod()); transactionProp.put(ALLOW_IP, httpProp.getProperty(ALLOW_IP, "")); transactionProp.put("BLOCK_IP", httpProp.getProperty("BLOCK_IP", "")); Map pathVariables = assignPathVariables(request, adptGrpName, adptName, null, transactionProp); if (pathVariables != null) { transactionProp.put(INBOUND_PATH_VARIABLES, pathVariables); } transactionProp.put(ENC_PATHS, httpProp.getProperty(ENC_PATHS, "")); transactionProp.put(ENCRYPT_ALGORITHM, httpProp.getProperty(ENCRYPT_ALGORITHM, "")); if (getHeaders(request).get(HEADER_NAME_CLIENT_ID) != null) { transactionProp.put(HEADER_NAME_CLIENT_ID, getHeaders(request).get(HEADER_NAME_CLIENT_ID)); } transactionProp.put(ENCRYPT_BASE_TYPE, httpProp.getProperty(ENCRYPT_BASE_TYPE, "")); String inboundToken = getHeaders(request).getOrDefault(INBOUND_TOKEN, "").toString(); if (StringUtils.isNotBlank(inboundToken) && StringUtils.startsWith(inboundToken, "Bearer ")) { inboundToken = inboundToken.substring(7); } transactionProp.put(INBOUND_TOKEN, inboundToken); transactionProp.put(ENCRYPT_AES256_IV, httpProp.getProperty(ENCRYPT_AES256_IV, "")); transactionProp.put(ENCRYPT_AES256_KEY, httpProp.getProperty(ENCRYPT_AES256_KEY, "")); // SEED 컬럼암호화 시 Key로 사용함 String seedkey = getHeaders(request).getOrDefault("x-obp-partnercode", "").toString(); ElinkTransactionContext.setSeedKey(seedkey); try { traceLevel = Integer.parseInt(traceLevelTemp); } catch (Exception e) { traceLevel = 0; } StopWatch stopWatch = new StopWatch(); stopWatch.start(); logger.debug("시작 >> encode = [" + encode + "]"); switch (HttpMethodType.getValue(request.getMethod())) { case GET: case DELETE: isParameterType = true; break; case POST: case PUT: if (StringUtils.contains(request.getContentType(), "application/x-www-form-urlencoded")) { isParameterType = true; } else if (StringUtils.isNoneBlank(request.getQueryString())) { isParameterType = true; } else { isParameterType = false; } break; default: break; } if (isParameterType) { paramValue = request.getQueryString(); transactionProp.put(INBOUND_QUERY_STRING, StringUtils.defaultString(paramValue)); if (paramValue == null) paramValue = ""; if (traceLevel >= 3) { HttpMemoryLogger.txlog(adptGrpName + adptName, "RECV " + "[" + paramValue + "]" + CommonLib.getDumpMessage(paramValue)); } // json으로 변환 StringBuilder sb = new StringBuilder(); sb.append("{"); Map paramMap = assignParameterMap(request, adptGrpName, adptName, null, transactionProp); int i = 0; for (Map.Entry entry : paramMap.entrySet()) { if (i > 0) { sb.append(","); } sb.append("\"").append(entry.getKey()).append("\":"); String[] values = entry.getValue(); if (values.length > 1) { // ["111", "222"] sb.append("["); for (int j = 0; j < values.length; j++) { if (j > 0) { sb.append(","); } sb.append("\"").append(JSONValue.escape(values[j])).append("\""); } sb.append("]"); } else { sb.append("\"").append(JSONValue.escape(values[0])).append("\""); } i++; } sb.append("}"); paramValue = sb.toString(); if (logger.isDebug()) { logger.debug("HttpAdapterServiceRest] RECV (" + adptGrpName + ") = [" + paramValue + "]\n" + CommonLib.getDumpMessage(paramValue.getBytes(encode))); } } else { if (request.getContentLength() > 0) { ServletInputStream sis = request.getInputStream(); ByteBuffer bb = ByteBuffer.allocate(1024).setAutoExpand(true); int i = 0; byte[] cbuf = new byte[1024]; while ((i = sis.read(cbuf, 0, 1024)) != -1) { if (i == 1024) { bb.put(cbuf); } else { byte[] tail = new byte[i]; System.arraycopy(cbuf, 0, tail, 0, i); bb.put(tail); } } byte[] data = new byte[bb.position()]; bb.position(0); bb.get(data); String bodyEncode = encode; String contentTypeHeader = request.getContentType(); if (StringUtils.isNotBlank(contentTypeHeader)) { try { MediaType mediaType = MediaType.parseMediaType(contentTypeHeader); if (mediaType.getCharset() != null) { bodyEncode = mediaType.getCharset().name(); } } catch (Exception ignored) {} } paramValue = new String(data, bodyEncode); if (traceLevel >= 3) { HttpMemoryLogger.txlog(adptGrpName + adptName, "RECV " + "[" + paramValue + "]" + CommonLib.getDumpMessage(data)); } if (logger.isDebug()) { logger.debug("HttpAdapterServiceRest] RECV (" + adptGrpName + ") = [" + paramValue + "]\n" + CommonLib.getDumpMessage(data)); } } } if (paramValue == null) { paramValue = ""; } transactionProp.put(INBOUND_REQUEST_MESSAGE, paramValue); if ("Y".equals(urlDecodeYn) && isParameterType) { message = URLDecoder.decode(paramValue); } else { message = paramValue; } if (logger.isDebug()) { String[] msgArgs = new String[2]; msgArgs[0] = adptGrpName; msgArgs[1] = message; String resMsg = ExceptionUtil.make("RICEAIAHA005", msgArgs); logger.debug(resMsg); } adptMsgType = adapterVO.getAdapterGroupVO().getMessageType(); // HEADER_GROUP 셋팅 if (MessageType.JSON.equals(adptMsgType) && StringUtils.isNotBlank(headerGroupName) && StringUtils.isNotBlank(relayRequestHeaderKeys)) { JSONObject jsonMessage = (JSONObject) JSONValue.parse(message); JSONObject headerJson = new JSONObject(); if (StringUtils.equalsIgnoreCase(relayRequestHeaderKeys, "ALL")) { for (Enumeration e = request.getHeaderNames(); e.hasMoreElements(); ) { String key = e.nextElement(); headerJson.put(key, request.getHeader(key)); } } else { String[] relayKeyArr = org.springframework.util.StringUtils .tokenizeToStringArray(relayRequestHeaderKeys, ","); for (String key : relayKeyArr) { String headerValue = request.getHeader(key); if (StringUtils.isNotBlank(headerValue)) { headerJson.put(key, headerValue); } } } if (headerJson.size() > 0) { jsonMessage.put(headerGroupName, headerJson); message = jsonMessage.toJSONString(); } } if (message == null) { message = ""; } String result = (String) service(adptGrpName, adptName, message, transactionProp, request, response); applyOutboundResponseHeaders(transactionProp, response); if (logger.isDebug()) { logger.debug("HttpAdapterServiceRest] result " + encode + " (" + adptGrpName + ") = [" + result + "]"); } stopWatch.stop(); String syncAsyncType = transactionProp.getProperty(INBOUND_SYNC_ASYNC_TYPE); if (!"ASYN".equals(syncAsyncType) && MessageType.JSON.equals(adptMsgType) && StringUtils.isNotBlank(headerGroupName)) { ObjectMapper mapper = new ObjectMapper(); ObjectNode rootNode = (ObjectNode) mapper.readTree(result); JsonNode headerGroup = rootNode.get(headerGroupName); if(headerGroup != null) { for(Iterator it = headerGroup.fieldNames(); it.hasNext();) { String name = it.next(); String value = headerGroup.get(name).asText(); response.addHeader(name, value); } rootNode.remove(headerGroupName); result = mapper.writeValueAsString(rootNode); } } return result; } /** * HttpClientAdapterServiceBypass.assignRelayDataToInbound() 에서 * transactionProp에 저장한 OUTBOUND_RESPONSE_HEADERS를 response에 적용한다. */ @SuppressWarnings("unchecked") private void applyOutboundResponseHeaders(Properties transactionProp, HttpServletResponse response) { Map outboundPropertyMap = (Map) transactionProp.get(OUTBOUND_PROPERTY_MAP); if (outboundPropertyMap == null) { return; } Properties headerProp = (Properties) outboundPropertyMap.get(OUTBOUND_RESPONSE_HEADERS); if (headerProp == null) { return; } String[] hopByHopHeaders = { "Connection", "Keep-Alive", "Proxy-Authenticate", "Proxy-Authorization", "TE", "Trailers", "Transfer-Encoding", "Upgrade" }; for (Map.Entry entry : headerProp.entrySet()) { String key = (String) entry.getKey(); String value = (String) entry.getValue(); if (StringUtils.equalsAnyIgnoreCase(key, hopByHopHeaders)) { continue; } if (StringUtils.equalsIgnoreCase(key, HttpHeaders.CONTENT_LENGTH)) { continue; } if (StringUtils.equalsIgnoreCase(key, HTTP_STATUS)) { if (StringUtils.isNotBlank(value)) { try { response.setStatus(Integer.parseInt(value)); } catch (NumberFormatException ex) { // ignore } } continue; } response.addHeader(key, value); } } private Map assignParameterMap(HttpServletRequest request, String adptGrpName, String adptName, Object requestBytes, Properties prop) { // PathVariable 체크 if (StringUtils.equalsAnyIgnoreCase(request.getMethod(), HttpMethod.GET.name(), HttpMethod.DELETE.name()) && StringUtils.isBlank(request.getQueryString())) { try { String actionName = prop.getProperty(Processor.REQUEST_ACTION); RequestAction action = ActionFactory.createAction(actionName); action.setAdapterInfo(adptGrpName, adptName, prop); String[] keys = action.perform(requestBytes); String requestPath = keys[0]; // PathVariable 지원 추가 String ruledPath = StandardMessageUtil.getMatchedKey(requestPath, actionName); if (!StringUtils.equals(requestPath, ruledPath) && StringUtils.contains(ruledPath, "{")) { Map paramMap = new AntPathMatcher().extractUriTemplateVariables(ruledPath, requestPath); if (paramMap != null && paramMap.size() > 0) { Map returnMap = new HashMap<>(); for (String key : paramMap.keySet()) { if (StringUtils.equalsIgnoreCase(key, "method")) { continue; } returnMap.put(key, new String[] { paramMap.get(key) }); } return returnMap; } } } catch (Exception e) { logger.error(e.getMessage()); } } return request.getParameterMap(); } private String getRewritePath(String extUri, String basePath) { return StringUtils.removeStart(extUri, StringUtils.removeEnd(basePath, "/")); } private Map assignPathVariables(HttpServletRequest request, String adptGrpName, String adptName, Object requestBytes, Properties prop) { Map variablesMap = null; // QueryString 있을때는 체크(X) if (StringUtils.isBlank(request.getQueryString())) { try { String actionName = prop.getProperty(Processor.REQUEST_ACTION); RequestAction action = ActionFactory.createAction(actionName); action.setAdapterInfo(adptGrpName, adptName, prop); String[] keys = action.perform(requestBytes); String requestPath = keys[0]; // PathVariable 지원 추가 String ruledPath = StandardMessageUtil.getMatchedKey(requestPath, actionName); if (!StringUtils.equals(requestPath, ruledPath) && StringUtils.contains(ruledPath, "{")) { variablesMap = new AntPathMatcher().extractUriTemplateVariables(ruledPath, requestPath); } } catch (Exception e) { logger.error(e.getMessage()); } } return variablesMap; } private Properties getHeaders(HttpServletRequest request) { Properties prop = new Properties(); Enumeration headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String key = headerNames.nextElement(); // 동일 이름의 헤더가 여러 개인 경우 콤마로 합침 (RFC 7230) Enumeration values = request.getHeaders(key); StringBuilder sb = new StringBuilder(); while (values.hasMoreElements()) { if (sb.length() > 0) sb.append(", "); sb.append(values.nextElement()); } prop.setProperty(key, sb.toString()); } return prop; } private String getExtUri(HttpServletRequest request) { String orgUri = request.getRequestURI().replaceAll(request.getContextPath(), ""); String uri = getExtUri(orgUri, 3); if (uri != null && uri.trim().length() > 0) { return "/" + uri; } else { return ""; } } private static String getExtUri(String url, int length) { String[] urls = url.split("/"); List newUrls = new ArrayList<>(); Collections.addAll(newUrls, urls); return StringUtils.join(newUrls.subList(length, urls.length).toArray(), "/"); } @Override @Deprecated public void service(String adptGrpName, String adptName, HttpServletRequest request, HttpServletResponse response) { } private String getClientIp(HttpServletRequest request) { String ipAddress = request.getHeader("X-Forwarded-For"); if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("HTTP_CLIENT_IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); } return ipAddress; } }