package com.eactive.eai.adapter.http.dynamic.impl;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.*;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey;
import com.eactive.eai.common.TransactionContextKeys;
import com.eactive.eai.common.util.HttpAdapterExtraLogUtil;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
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 org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.util.AntPathMatcher;

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.HttpMethodType;
import com.eactive.eai.adapter.http.HttpStatusException;
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceSupport;
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException;
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.common.util.MessageUtil;
import com.eactive.eai.env.ElinkConfig;
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;

public class HttpAdapterServiceRest extends HttpAdapterServiceSupport {
	public static final String HEADER_GROUP = "HEADER_GROUP";
	// HEADER_GROUP JSON에 추가할 항목 정의, 없으면 전체 header 추가
	public static final String HEADER_KEYS = "HEADER_KEYS";
	public static final String HTTP_STATUS = "HTTP_STATUS";
	public static final String PROPERTIES_NAME_HTTP_REQUEST_METHOD = "httpRequestMethod";

	static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
	private String logPrefix = "HttpAdapterServiceRest] ";

	private static final String JSON_CONTENT_TYPE = "application/json";
	private static final String JSON_FIELD_NAME = "json-body";
	private static final String FILE_GROUP_NAME = "image-file";
	private static final String UPLOAD_ROOT_PATH = "UPLOAD_ROOT_PATH";

	private String readMultipartBody(HttpServletRequest request) throws Exception {
		String jsonString = null;
		// Create a factory for disk-based file items
		DiskFileItemFactory factory = new DiskFileItemFactory();

		// Set the maximum size of the files to be uploaded
		factory.setSizeThreshold(1024 * 1024);

		// Set the temporary directory to store uploaded files
		File tempDir = (File) request.getSession().getServletContext().getAttribute("javax.servlet.context.tempdir");
		factory.setRepository(tempDir);

		ServletFileUpload upload = new ServletFileUpload(factory);
		Map<String, String> fileMap = new HashMap<>();

		InputStream fin = null;
		try {
			byte[] buffer = new byte[1024];
			int read = 0;

			List<FileItem> items = upload.parseRequest(request);
			for (FileItem item : items) {
				if (!item.isFormField()) {
					// file
					String fieldName = item.getFieldName();
					String fileName = item.getName();
					fin = item.getInputStream();
					ByteArrayOutputStream fo = new ByteArrayOutputStream();
					while ((read = fin.read(buffer)) > 0) {
						fo.write(buffer, 0, read);
					}
					int fileSize = fo.size();
					byte[] fileBytes = fo.toByteArray();
					String fileContents = new String(fileBytes);
					if (logger.isInfo()) {
						logger.info("[FILE]-------------------------------------------------->");
						logger.info("Field name = " + fieldName);
						logger.info("File name = " + fileName + " contents length = " + fileSize);
						logger.info("File Contents [" + fileContents + "]");
						logger.info("[FILE]<--------------------------------------------------");
					}
					fileMap.put(fileName, fileContents);
					fin.close();
				} else {
					// regular form field
					String fieldName = item.getFieldName();
					String fieldValue = item.getString();
					if (logger.isInfo()) {
						logger.info("[FIELD] " + fieldName + " [" + fieldValue + "]");
					}
					if (JSON_CONTENT_TYPE.equalsIgnoreCase(item.getContentType())
							|| JSON_FIELD_NAME.equals(fieldName)) {
						jsonString = fieldValue;
					}
				}
			}

			if (logger.isInfo()) {
				logger.info("Json body [" + jsonString + "]");
			}

			if (jsonString == null) {
				jsonString = "{}";
			} else {
				// parsing json & add file contents
				JSONObject jsonObject = (JSONObject) JSONValue.parse(jsonString);
				if (jsonObject == null) {
					jsonString = "{}";
				} else {
					JSONObject fileGroup = new JSONObject();

					for (Map.Entry<String, String> entry : fileMap.entrySet()) {
						fileGroup.put("fileName", entry.getKey());
						fileGroup.put("fileContents", entry.getValue());
					}
					jsonObject.put(FILE_GROUP_NAME, fileGroup);
					jsonString = jsonObject.toJSONString();
				}
			}

			if (logger.isInfo()) {
				logger.info("Json with file [" + jsonString + "]");
			}
			return jsonString;
		} catch (Exception e) {
			logger.error("Read multipart body error.", e);
			throw e;
		} finally {
			if (fin != null) {
				try {
					fin.close();
				} catch (Exception ex) {
					// empty
				}
			}
		}
	}

	private String checkRootPath(String path) {
		if (StringUtils.isEmpty(path)) {
			logger.info("upload dir not set(UPLOAD_ROOT_PATH), use system temp " + path);
			return System.getProperty("java.io.tmpdir");
		}
		File file = new File(path);
		if (!file.exists()) {
			file.mkdirs();
		}
		return path;
	}

	private String uploadMultipartBody(HttpServletRequest request, String uploadRootPath) throws Exception {
		String jsonString = null;
		// Create a factory for disk-based file items
		DiskFileItemFactory factory = new DiskFileItemFactory();

		// Set the maximum size of the files to be uploaded
		factory.setSizeThreshold(1024 * 1024);

		// Set the temporary directory to store uploaded files
		File tempDir = (File) request.getSession().getServletContext().getAttribute("javax.servlet.context.tempdir");
		factory.setRepository(tempDir);

		ServletFileUpload upload = new ServletFileUpload(factory);
		try {
			// if not exist, create folders
			String uploadDir = checkRootPath(uploadRootPath);
			List<FileItem> items = upload.parseRequest(request);
			for (FileItem item : items) {
				if (!item.isFormField()) {
					// file
					String fieldName = item.getFieldName();
					String fileName = item.getName();
					String uploadFilePath = uploadDir + File.separator + fileName;
					File uploadFile = new File(uploadFilePath);
					item.write(uploadFile);

					if (logger.isInfo()) {
						logger.info("[FILE]-------------------------------------------------->");
						logger.info("Field name = " + fieldName);
						logger.info("File name = " + fileName + " path = " + uploadFile.getAbsolutePath());
						logger.info("[FILE]<--------------------------------------------------");
					}
				} else {
					// regular form field
					String fieldName = item.getFieldName();
					String fieldValue = item.getString();
					if (logger.isInfo()) {
						logger.info("[FIELD] " + fieldName + " [" + fieldValue + "]");
					}
					if (JSON_CONTENT_TYPE.equalsIgnoreCase(item.getContentType())
							|| JSON_FIELD_NAME.equals(fieldName)) {
						jsonString = fieldValue;
					}
				}
			}

			if (logger.isInfo()) {
				logger.info("Json body [" + jsonString + "]");
			}
			return jsonString;
		} catch (Exception e) {
			logger.error("Read multipart body error.", e);
			throw e;
		}
	}

	@SuppressWarnings({ "unchecked", "deprecation" })
	public void service(String adptGrpName, String adptName, HttpServletRequest request, HttpServletResponse response) {
		int traceLevel = 0;

		AdapterVO adptVO = null;
		AdapterPropManager manager = null;

		Properties httpProp = null;
		String responseType = null;
		String urlDecodeYn = null;
		String encode = null;

		String traceLevelTemp = null;
		String relayRequestHeaderKeys = null;
		String headerGroupName = null;

		boolean isParameterType = false;
		String message = null;

		StopWatch stopWatch = null;
		Properties prop = null;
		String paramValue = null;
		String adptMsgType = null;
		String errorResponseFormat = null;
		String uploadRootPath = null;
		try {
			AdapterManager adapterManager = AdapterManager.getInstance();
			adptVO = adapterManager.getAdapterVO(adptGrpName, adptName);
			if (adptVO == null) {
				throw new Exception("Adapter not found error");
			}

			manager = AdapterPropManager.getInstance();

			httpProp = manager.getProperties(adptVO.getPropGroupName());
			responseType = httpProp.getProperty(RESPONSE_TYPE, "SYNC");
			urlDecodeYn = httpProp.getProperty(URL_DECODE_YN, "N");
			// encode = httpProp.getProperty(ENCODE, "UTF-8");
			encode = StringUtils.defaultIfBlank(adapterManager.getAdapterGroupVO(adptGrpName).getMessageEncode(),
					"UTF-8");
			traceLevelTemp = httpProp.getProperty(TRACE_LEVEL, "0");
			relayRequestHeaderKeys = httpProp.getProperty(HEADER_KEYS);
			headerGroupName = httpProp.getProperty(HEADER_GROUP);
			errorResponseFormat = httpProp.getProperty(ERROR_RESPONSE_FORMAT);
			uploadRootPath = httpProp.getProperty(UPLOAD_ROOT_PATH);
			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)) {
				// /api/v1/public/getUserInfo.svc
				String extUrl = StringUtils.removeStart(request.getRequestURI(), request.getContextPath());
				prop.put(INBOUND_EXTURI, extUrl);
			} else {
				prop.put(INBOUND_EXTURI, getExtUri(request));
			}
			prop.put(Processor.REQUEST_ACTION, adptVO.getAdapterGroupVO().getRefClass());
			prop.put(API_PATH, httpProp.getProperty(API_PATH, ""));
			prop.put(PRE_FILTERS, httpProp.getProperty(PRE_FILTERS, ""));
			prop.put(POST_FILTERS, httpProp.getProperty(POST_FILTERS, ""));
			prop.put(PROPERTIES_NAME_HTTP_REQUEST_METHOD, request.getMethod());
			prop.put(ALLOW_IP, httpProp.getProperty(ALLOW_IP, ""));

			isParameterType = false;
			try {
				traceLevel = Integer.parseInt(traceLevelTemp);
			} catch (Exception e) {
				traceLevel = 0;
			}

			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 {
					isParameterType = false;
				}
				break;
			default:
				break;
			}

			if (isParameterType) {
				paramValue = request.getQueryString();
				if (paramValue == null)
					paramValue = "";
				if (traceLevel >= 3) {
					HttpMemoryLogger.txlog(adptGrpName + adptName,
							"RECV " + "[" + paramValue + "]" + CommonLib.getDumpMessage(paramValue));
				}

				// json으로 변환
				StringBuilder sb = new StringBuilder();
				sb.append("{");
				Map<String, String[]> paramMap = assignParameterMap(request, adptGrpName, adptName, null, prop);
				int i = 0;
				for (Map.Entry<String, String[]> 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();
			} else {
				if (ServletFileUpload.isMultipartContent(request)) {
					// TODO : 아래의 로직은 업무에 맞게 수정이 필요함.
					// 불필요할 경우 제거
//					if(StringUtils.isEmpty(uploadRootPath)) {
//						uploadRootPath = System.getProperty("java.io.tmpdir");
//					}

					// 임시로직 : UPLOAD_ROOT_PATH 가 없는 경우에는 JSON에 추가
					if (StringUtils.isEmpty(uploadRootPath)) {
						paramValue = readMultipartBody(request);
					} else {
						paramValue = uploadMultipartBody(request, uploadRootPath);
					}
					// TEST : 테스트용 임시코드
//					response.setCharacterEncoding(encode);
//					response.getWriter().print(paramValue);
//					return;
				} else {
					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);
					paramValue = new String(data, encode);

					if (traceLevel >= 3) {
						HttpMemoryLogger.txlog(adptGrpName + adptName,
								"RECV " + "[" + paramValue + "]" + CommonLib.getDumpMessage(paramValue));
					}
				}
			}

			if (paramValue == null) { // parameter가 없는 경우때문에 처리
				paramValue = "";
			}

			if (logger.isDebug()) {
				logger.debug("HttpAdapterServiceRest] RECV (" + adptGrpName + ") = [" + paramValue + "]\n"
						+ CommonLib.getDumpMessage(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(logPrefix + resMsg);
			}

			adptMsgType = adptVO.getAdapterGroupVO().getMessageType();
			if (StringUtils.equals(adptMsgType, MessageType.JSON)) {
				response.setContentType(JSON_CONTENT_TYPE+"; charset="+encode);
			}

			// HEADER_GROUP 셋팅
			if (MessageType.JSON.equals(adptMsgType) && StringUtils.isNotBlank(headerGroupName)
					&& StringUtils.isNotBlank(relayRequestHeaderKeys)) {
				JSONObject jsonMessage = (JSONObject) JSONValue.parse(message);
				JSONObject headerJson = new JSONObject();
				if (StringUtils.equalsIgnoreCase(relayRequestHeaderKeys, "ALL")) {
					for (Enumeration<String> e = request.getHeaderNames(); e.hasMoreElements();) {
						String key = e.nextElement();
						headerJson.put(key, request.getHeader(key));
					}
				} else {
					String[] relayKeyArr = org.springframework.util.StringUtils
							.tokenizeToStringArray(relayRequestHeaderKeys, ",");

					for (String key : relayKeyArr) {
						String headerValue = request.getHeader(key);
						if (StringUtils.isNotBlank(headerValue)) {
							headerJson.put(key, headerValue);
						}
					}
				}

				if (headerJson.size() > 0) {
					jsonMessage.put(headerGroupName, headerJson);
					message = jsonMessage.toJSONString();
				}
			}

			if (message == null) {
				message = "";
			}

			// 로컬 서비스 호출 ,encoding 처리 추가
			String result = (String) service(adptGrpName, adptName, message, prop, request, response);

			if (logger.isDebug()) {
				logger.debug("HttpAdapterServiceRest] result " + encode + " (" + adptGrpName + ") = [" + result + "]");
			}

			stopWatch.stop();

			String responseData = "";
			if (RESPONSE_TYPE_ASYNC.equals(responseType)) {
				if (stopWatch.getTime() > slowTranTime && (logger.isInfo())) {
					logger.info("HttpAdapterServiceRest] dummy response time = " + stopWatch.toString() + ", message = "
							+ message);

				}
				if (result == null) {
					responseData = ElinkConfig.getAsyncDummyDataForAdapterGroup(adptGrpName);
				} else {
					responseData = result;
				}
				response.setCharacterEncoding(encode);
				response.getWriter().print(responseData);
				if (traceLevel >= 3) {
					HttpMemoryLogger.txlog(adptGrpName + adptName,
							"SEND " + "[" + responseData + "]" + CommonLib.getDumpMessage(responseData));
				}
			} else {
				responseData = result;
				logger.info("종료 >> encode = [" + encode + "]");

				JSONObject dataObject = null;
				if (MessageType.JSON.equals(adptMsgType)) {
					dataObject = (JSONObject) JSONValue.parse(responseData);
				}

				// HEADER_GROUP 하위 필드를 response Header에 세팅한다.
				HashMap<String, String> header = new HashMap<>();
				boolean redirect = assignHttpHeaders(header, dataObject, headerGroupName);

				if (logger.isDebug()) {
					logger.debug("HttpAdapterServiceRest] response header field (" + adptGrpName + ") = ["
							+ header.toString() + "]");
				}

				if (redirect) {
					response.setStatus(302);
					logger.debug("HttpAdapterServiceRest] set response status_code: 302");
				} else {
					String httpStatus = header.get(HTTP_STATUS);
					if (httpStatus != null && !"".equals(httpStatus))
						response.setStatus(Integer.parseInt(httpStatus));
					header.remove(HTTP_STATUS);
				}

				// response header 셋팅
				for (Map.Entry<String, String> entry : header.entrySet()) {
					response.setHeader(entry.getKey(), entry.getValue());
				}

				if (dataObject != null) {
					responseData = dataObject.toJSONString();
				}

				// UI와 통신시(UTF-8) 변환오류로 ENCODE 제거
				response.setCharacterEncoding(encode);
				response.getWriter().print(responseData);
				if (logger.isDebug()) {
					logger.debug("HttpAdapterServiceRest] SEND (" + adptGrpName + ") = [" + responseData + "]");
					logger.debug("HttpAdapterServiceRest] SEND (" + adptGrpName + ") = "
							+ CommonLib.getDumpMessage(responseData));
				}
				if (traceLevel >= 3) {
					HttpMemoryLogger.txlog(adptGrpName + adptName,
							"SEND " + "[" + responseData + "]" + CommonLib.getDumpMessage(responseData));
				}
			}
		} catch (HttpStatusException e) {
			if (traceLevel >= 3) {
				HttpMemoryLogger.error(adptGrpName + adptName, e.toString(), e);
			}
			logger.warn("HttpAdapter] " + adptGrpName + "-" + adptName + ">>" + e.getMessage());
			response.setStatus(e.getStatus());
			try {
				String errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode, e.getCode(),
						e.getMessage(), errorResponseFormat);
				response.getWriter().println(errorMsg);
			} catch (Exception ex) {
				// IGNORE
			}
		} catch (JwtAuthException e) {
			if (traceLevel >= 3) {
				HttpMemoryLogger.error(adptGrpName + adptName, e.toString(), e);
			}
			logger.error(logPrefix + adptGrpName + "-" + adptName + ">>" + e.getMessage(), e);
			response.setStatus(HttpStatus.UNAUTHORIZED.value());
			try {
				String errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode, e.getCode(),
						e.getMessage(), errorResponseFormat);
				response.getWriter().println(errorMsg);
			} catch (Exception ex) {
				// IGNORE
			}
		} catch (Exception e) {
			if (traceLevel >= 3) {
				HttpMemoryLogger.error(adptGrpName + adptName, e.toString(), e);
			}
			logger.error(logPrefix + adptGrpName + "-" + adptName + ">>" + e.getMessage(), e);
			response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
			try {
				response.getWriter().println(e.getMessage());
				String errCode = ExceptionUtil.getErrorCode(e, "RECEAIAHA003");
				throw new Exception(errCode);
			} catch (Exception ex) {
				// IGNORE
				logger.warn(logPrefix + adptGrpName + "-" + adptName + ">>" + e.getMessage(), e);
			}
		} 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<Object, Object> 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);
		}
	}

	private Map<String, String[]> 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<String, String> paramMap = new AntPathMatcher().extractUriTemplateVariables(ruledPath,
							requestPath);
					if (paramMap != null && paramMap.size() > 0) {
						Map<String, String[]> 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 void validateServiceAndAdapter(String adptGrpName, String adptName, byte[] requestBytes, Properties prop)
			throws JwtAuthException {
//		try {
//			String actionName = prop.getProperty(Processor.REQUEST_ACTION);
//			RequestAction action = ActionFactory.createAction(actionName);
//			action.setAdapterInfo(adptGrpName, adptName, prop);
//			String[] keys = action.perform(requestBytes);
//			String apiId = keys[0];
//
//			// PathVariable 지원 추가
//			apiId = StandardMessageUtil.getMatchedKey(apiId, actionName);
//			if (apiId == null) {
//				throw new Exception("apiId");
//			}
//
////			STDMessageManager stdheaderManager = STDMessageManager.getInstance();
////			STDMessage stdmessage = stdheaderManager.getSTDMessage(apiId);
////			if (stdmessage == null) {
////				throw new Exception("stdMsg");
////			}
//
//			long msgRcvTm = System.currentTimeMillis();
//			AdapterManager adapterManager = AdapterManager.getInstance();
//			AdapterGroupVO adptGrpVO = adapterManager.getAdapterGroupVO(adptGrpName);
//			ProcessVO processVO = setProcessVO(apiId, adptGrpVO.getOsidInstiNo(), msgRcvTm, adptGrpName, adptName);
//			ExtMessage extMessage = ExtMessageConverter.getExtMessageForNonStandard(requestBytes, requestBytes, processVO);
//
//			EAIMessageManager eaiMsgManager = EAIMessageManager.getInstance();
////			String eaiSvcCd = stdmessage.getEAITranName() + stdmessage.getSTDHeader().getMesgDvcd();
//			String eaiSvcCd = extMessage.getEAIServiceCode();
//			if (eaiSvcCd == null) {
//				eaiSvcCd = extMessage.getInterfaceId() + extMessage.getSendRecv() + extMessage.getDirection();
//			}
//			EAIMessage eaiMsg = eaiMsgManager.getEAIMessage(eaiSvcCd);
//			logger.warn("adptGrpName=[" + adptGrpName + "],eaiSvcCd=[" + eaiSvcCd + "],eaiMsg=[" + eaiMsg
//					+ "],getSngSysItfTp=[" + "]");
//			if (eaiMsg == null) {
//				throw new Exception("eaiMsg");
//			}
//
//			if (!StringUtils.equals(eaiMsg.getSngSysItfTp(), adptGrpName)) {
//				throw new Exception("adapter");
//			}
//		} catch (Exception e) {
//			String msg = String.format("The resource does not exist or does not have permissions(%s): %s",
//					e.getMessage(), prop.get(INBOUND_EXTURI));
//			throw new JwtAuthException(JwtAuthFilter.ERROR_AUTHORIZATION_FAIL, msg);
//		}
	}

//	private ProcessVO setProcessVO(String apiId, String osidInstiNo, long msgRcvTm, String adptGrpName,
//			String adptName) {
//		ProcessVO vo = new ProcessVO();
//		vo.setSelectedKey(apiId);
//		vo.setAdapterGroupName(adptGrpName);
//		vo.setAdapterName(adptName);
//		vo.setInAdapterOsidInstiNo(osidInstiNo);
//		vo.setErrTm(msgRcvTm);
//		return vo;
//	}

	/**
	 * request header 를 hashmap으로 조립
	 * 
	 * @param request
	 * @return
	 */
	private Properties getHeaders(HttpServletRequest request) {
		Properties prop = new Properties();

		Enumeration<String> headerNames = request.getHeaderNames();
		while (headerNames.hasMoreElements()) {
			String key = headerNames.nextElement();
			String value = request.getHeader(key);
			prop.setProperty(key, value);
		}

		return prop;
	}

	/**
	 * adapter property의 HEADER_GROUP으로 정의된 (MFE_HEADER) 그룹의 하위 필드를 http Header에
	 * 세팅한다.
	 * 
	 * @param header
	 * @param object
	 */
	private boolean assignHttpHeaders(HashMap<String, String> header, Object msg, String headerGroupName) {
		boolean redirect = false;

		if (msg == null || StringUtils.isBlank(headerGroupName)) {
			return false;
		}

		if (msg instanceof JSONObject) {
			JSONObject headerObject = (JSONObject) ((JSONObject) msg).get(headerGroupName);

			if (headerObject == null) {
				return false;
			}

			// List<String> headerKeys = new ArrayList<>();
			for (Object key : headerObject.keySet()) {

				Object obj = headerObject.get(key);
				if ((obj instanceof JSONObject) || (obj instanceof JSONArray)) {
					continue;
				}

				header.put((String) key, (String) obj);

				if (StringUtils.equalsIgnoreCase((String) key, "Location")) {
					redirect = true;
				}
			}

			((JSONObject) msg).remove(headerGroupName);
		}

		return redirect;
	}

	/**
	 * 어댑터 명 이후의 URI값을 가져온다.
	 * 
	 * @param request
	 * @return
	 */
	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<String> newUrls = new ArrayList<>();
		Collections.addAll(newUrls, urls);
		return StringUtils.join(newUrls.subList(length, urls.length).toArray(), "/");
	}

//	public static void main(String[] args) throws Exception {
//		String orgUri = "/HTT/CbsInNetSys/abcd/123456";
//		String result = "";
//		result = getExtUri(orgUri, 3);
//		System.out.println(result);
//	}
}
