
package com.eactive.eai.rms.common.util; 

import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.Properties;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.log4j.Logger;

import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.util.CommonLib;


/** 
* 1. 기능 : EAI HTTP OutBound 용 어댑터로 수동 시스템의 HTTP 웹 컴포넌트를 
*           GET/POST 방식으로 호출할 수 있는 기능을 제공한다.
* 2. 처리 개요 : 
* *     - 2009.11.24 retry 로직 제거  : 
* 3. 주의사항 
*
* @author  : 
* @version : v 1.0.0
* @see : WLIAdapterFactory.java, WLIAdapter.java, WLIDefaultAdapter.java
* @since   : 

*/
public class HttpClientAdapter
{ 
	protected final static Logger logger = Logger.getLogger(HttpClientAdapter.class);
    
    public static final String URL = "URL";
    public static final String METHOD = "METHOD";
    public static final String PARAMETER_NAME = "PARAMETER_NAME";
    
    // encode 추가 : 20071207
    public static final String ENCODE = "ENCODE";
    
    public static final String METHOD_GET = "GET";
    public static final String METHOD_POST = "POST";

    /*
     * Http Response Type 이름
     */
    public static final String RESPONSE_TYPE = "RESPONSE_TYPE";
    
    //-------------------------------------------------
    // 전자무역 상태조회 : 
    // 2009.01.09
    public static final String METHOD_SOAP = "SOAP";
    public static final String METHOD_SOAP_ACTION = "SOAPAction";
    //-------------------------------------------------
    
    public static final String HTTP_CONNECTION_STALE_CHECKING_ENABLED = "HTTP_CONNECTION_STALE_CHECKING_ENABLED";
    /*
     * 호스트 마다 최대 연결 수
     */
    public static final String HTTP_MAX_CONNECTION_PER_HOST = "HTTP_MAX_CONNECTION_PER_HOST";
    /*
     * 최대 HTTP 연결 수
     */
    public static final String HTTP_MAX_TOTAL_CONNECTIONS = "HTTP_MAX_TOTAL_CONNECTIONS";
    
    static final String PARAMETER_MESSAGE = "_message_";
    
    static final String URL_ENCODE_YN = "URL_ENCODE_YN";

    static final String REQUEST_BODY_YN = "REQUEST_BODY_YN";
    
    private HttpClient client;
    
    //  2008.01.21 이동훈
    // HttpClient 2.0 Timeout Setting
    public static final String HTTP_TIME_OUT = "HTTP_TIME_OUT";
    public static final int   DEFAULT_TIME_OUT = 30 *1000;
    // HttpClient 2.0 Timeout Setting 
    
    /** 
    * 1. 기능 :  HttpClientAdapter default 생성자
    * 2. 처리 개요 : 
    *     - property 정보를 가져와 MultiThreadedHttpConnectionManager 속성 설정
    *     - HttpClient의 instance 생성
    * 3. 주의사항 
    *
    **/
    public HttpClientAdapter() {
        MultiThreadedHttpConnectionManager cm = new MultiThreadedHttpConnectionManager();
        try {       	  
			cm.getParams().setStaleCheckingEnabled(new Boolean(true).booleanValue());	
			//cm.getParams().setDefaultMaxConnectionsPerHost(new Integer(connPerHost).intValue());
			//cm.getParams().setMaxTotalConnections(new Integer(totalConnections).intValue());
        } catch(Exception e) {        	
        	//e.printStackTrace();
            String errCode = ExceptionUtil.getErrorCode(e, "RECEAIAHA007");
            throw new RuntimeException(errCode);
        }
        this.client = new HttpClient(cm);
        
        
    }
    
    /** 
    * 1. 기능 :  현재 사용중인 Connection 수
    * 2. 처리 개요 : 
    *     - 
    * 3. 주의사항 
    *
    * @return int 사용중인 Connection 수
    **/
    public int getConnectionsInPool() {
        MultiThreadedHttpConnectionManager mgr = (MultiThreadedHttpConnectionManager)this.client.getHttpConnectionManager();
        return mgr.getConnectionsInPool();
    }
    
    /** 
    * 1. 기능 :  생성된 총 Connection 수
    * 2. 처리 개요 : 
    *     - 
    * 3. 주의사항 
    *
    * @return int 총 Connection 수
    **/
    public int getMaxTotalConnections() {
        MultiThreadedHttpConnectionManager mgr = (MultiThreadedHttpConnectionManager)this.client.getHttpConnectionManager();
        return mgr.getParams().getMaxTotalConnections();
    }
    
    /** 
    * 1. 기능 :  호스트 당 할당된 총 Connection 수
    * 2. 처리 개요 : 
    *     - 
    * 3. 주의사항 
    *
    * @return int 총 Connection 수
    **/
    public int getMaxConnectionsPerHost() {
        MultiThreadedHttpConnectionManager mgr = (MultiThreadedHttpConnectionManager)this.client.getHttpConnectionManager();
        return mgr.getParams().getDefaultMaxConnectionsPerHost();
    }
    
    /** 
    * 1. 기능 :  전문과 같은 Raw Data 통신에 사용
    * 2. 처리 개요 : 
    *     - 속성 정보를 설정 하고 수동 시스템 서비스를 호출 한다.
    * 3. 주의사항 
    *
    * @param    prop    Http Adapter 속성 정보
    * @param    message 송신 전문
    * @return   반환 된 byte[] Object
    * @exception    Exception 수동 시스템 간 통신 중 발생
    **/
    public Object execute(Properties prop, Object message) throws Exception
    {
     
    	byte[] data = null;
        if(message instanceof byte[]) {
            data = (byte[])message;
        } else if( message instanceof String) {
            data = ((String)message).getBytes();
        } else {
            throw new Exception("RECEAIAHA011");
        }
        String url = prop.getProperty(URL);
        String parameterName = prop.getProperty(PARAMETER_NAME,PARAMETER_MESSAGE);
        String httpMethod = prop.getProperty(METHOD);
        String encode = prop.getProperty(ENCODE);
        String httpTimeOut = prop.getProperty(HTTP_TIME_OUT);
        String soapAction = prop.getProperty(METHOD_SOAP_ACTION);


        //-------------------------------------------
        // trim 처리 : 2009.03.27
        //-------------------------------------------
        if(url != null) {
        	url = url.trim();
        }
        if(parameterName != null) {
        	parameterName = parameterName.trim();
        }
        
        if(httpMethod != null) {
        	httpMethod = httpMethod.trim();
        }
        
        if(encode != null) {
        	encode = encode.trim();
        }
        
        if(soapAction != null) {
        	soapAction = soapAction.trim();
        }
 
        
        //----------------------------------
        // 2008.02.15 이동훈
        // 설정값이 없을 경우 무한대로 기다리도록 
        // 0 으로 설정하도록 함 
        //----------------------------------
        if(httpTimeOut == null) {
            httpTimeOut = "0";
        }
        else {
        	httpTimeOut = httpTimeOut.trim();
        }

        int timeout = -1;
        try {
        	timeout = new Integer(httpTimeOut).intValue();
            if(logger.isDebugEnabled()){
                logger.debug("HttpClientAdapter] HTTP TIMEOUT SET ["+httpTimeOut+"]");
            }
        } catch(Exception e) {        	
            logger.warn("HttpClientAdapter] HTTP TIMEOUT 설정값을 확인하세요. ["+httpTimeOut+"]");            
        }
        
        
        if(logger.isDebugEnabled()){
            logger.debug("HttpClientAdapter] SEND ("+httpMethod+") ");
        }
        
        if(httpMethod!=null && httpMethod.equals(METHOD_POST)) {
            return callPostService(url, parameterName, data, encode, timeout, prop);
        } 
        else {
            return callGetService(url, parameterName, data, encode, timeout, prop);
        }        
    }
    
    /** 
    * 1. 기능 :  수동 시스템에 Post 방식으로 서비스 호출
    * 2. 처리 개요 : 
    *     - 수동 시스템에 서비스 요청 하고 결과를 리턴 한다.
    * 3. 주의사항 
    *
    * @param    url 수동 시스템 웹 컴포넌트 URL
    * @param    parameterName   URL 파리미터 이름
    * @param    data    송신 전문
    * @return   반환 된 byte[] Object
    * @exception    Exception 수동 시스템 간 통신 중 발생
    **/
    private byte[] callPostService(String url, String parameterName, byte[] data, String encode, int timeout, Properties prop)
    throws Exception {
    	
		String responseType = prop.getProperty(RESPONSE_TYPE,"SYNC");
		String urlEncodeYn = prop.getProperty(URL_ENCODE_YN,"N");
		String adapterGroupName = prop.getProperty("AdapterGroupName");    	
    	String requestBodyYn = prop.getProperty(REQUEST_BODY_YN,"N");
    	
    	
        PostMethod method = new PostMethod(url);

        //2008.02.15 : Timeout 처리로직 변경 (0 : 무한대 설정가능하게 함)
        if(timeout > -1) {
        	method.getParams().setSoTimeout(timeout);
        }
        
        //method.setRequestHeader("Content-Type","text/html; charset=utf-8");
        
        String sendData = null;
        HttpClient mclient = new HttpClient(new MultiThreadedHttpConnectionManager());
    	
        if(logger.isDebugEnabled()){
        	logger.debug("HttpClientAdapter] ENCODE("+encode+") ");
        }
        if(encode != null && encode.length() > 0) {
            try {
            	mclient.getParams().setContentCharset(encode);
            	sendData = new String(data,encode);                    
            } catch(Exception e) {
                logger.error("HttpClientAdapter] ENCODE("+encode+") ERROR : "+ e.toString());
                logger.error("HttpClientAdapter] ENCODE("+encode+") SKIP ");
                sendData = new String(data); 
            }
        }else{
        	sendData = new String(data);
        }
        
        
        if ("Y".equals(urlEncodeYn)){
        	sendData = java.net.URLEncoder.encode(sendData);
        }
        
        if ("Y".equals(requestBodyYn)){
        	method.setRequestBody(sendData);//신보기보관련  old parameterName으로 했음
        }else{
        	method.addParameter(parameterName, sendData);
        }
        
        int status = -1;
        
        
        try {
    
            if(logger.isDebugEnabled()){
                logger.debug("HttpClientAdapter] SEND ("+adapterGroupName+") = ["+sendData+"]");
                logger.debug("HttpClientAdapter] SEND ("+adapterGroupName+") = "+CommonLib.getDumpMessage(sendData.getBytes()));
            }            
            
            status = mclient.executeMethod(method);
            
            //status 200(정상) 이외에는 error 처리 
            if (status !=200){
            	throw new Exception ("http receive status fail value= " + status);
            }
            
            //----------------------------------------------------------
            // 2008.01.23 : 응답이 깨지는 것 수정
            //----------------------------------------------------------
            //String responseMessage = method.getResponseBodyAsString();
            String responseMessage = new String(method.getResponseBody());
            //----------------------------------------------------------
            if (logger.isDebugEnabled()){
            	logger.debug("HttpClientAdapter] responseType ="+ responseType);
                logger.debug("HttpClientAdapter] RECV ("+adapterGroupName+") = ["+responseMessage+"]");
                logger.debug("HttpClientAdapter] RECV ("+adapterGroupName+") = "+CommonLib.getDumpMessage(responseMessage.getBytes()));
            }
            if ("ASYNC".equals(responseType)){
            	if (!"dummy".equals(responseMessage)){
            		throw new Exception ("http return fail value= " + responseMessage);
            	}
            	return null;
            }
            return responseMessage.getBytes();
            
        } catch(SocketTimeoutException ste) { // Read Timeout :: HttpClient 3.1일 경우
            //ste.printStackTrace();
        	logger.error("HttpClientAdapter] SocketTimeoutException : " + ste.toString() );
            throw ste;
        } catch(ConnectException ce) {
            //ce.printStackTrace();
        	logger.error("HttpClientAdapter] Connection Exception : " + ce.toString() );
            throw ce;
        } catch(Exception e) {
            //e.printStackTrace();
            throw e;
        } finally {
            method.releaseConnection();
            if(status != HttpStatus.SC_OK) {
                String[] msgArgs = new String[1];
                msgArgs[0] = String.valueOf(status);
                String resMsg = ExceptionUtil.make("RDCEAIAHA013", msgArgs);
                if(logger.isDebugEnabled()){
                    logger.debug(resMsg);
                }
            }
        }
    }
    
    /** 
    * 1. 기능 :  수동 시스템에 Get 방식으로 서비스 호출
    * 2. 처리 개요 : 
    *     - 수동 시스템에 서비스 요청 하고 결과를 리턴 한다.
    * 3. 주의사항 
    *
    * @param    url 수동 시스템 웹 컴포넌트 URL
    * @param    parameterName   URL 파리미터 이름
    * @param    data    송신 전문
    * @return   반환 된 byte[] Object
    * @exception    Exception 수동 시스템 간 통신 중 발생
    **/
    private byte[] callGetService(String url, String parameterName, byte[] data, String encode, int timeout, Properties prop )
    throws Exception {
    	
    	String responseType = prop.getProperty(RESPONSE_TYPE,"SYNC");
        GetMethod method = new GetMethod(url);

        //2008.02.15 : Timeout 처리로직 변경 (0 : 무한대 설정가능하게 함)
        if(timeout > -1) {
        	method.getParams().setSoTimeout(timeout);
        }
        
        String sendData = null;
        
        if(logger.isDebugEnabled()){
            logger.debug("HttpClientAdapter] GET Method URLEncoder");
        }
        sendData = java.net.URLEncoder.encode(new String(data));
        
        method.setQueryString(parameterName+"=" + sendData);
        
        int status = -1;
        try {
            status = client.executeMethod(method);
            //----------------------------------------------------------
            // 2008.01.23 : 응답이 깨지는 것 수정
            //----------------------------------------------------------
            //String responseMessage = method.getResponseBodyAsString();
            String responseMessage = new String(method.getResponseBody());
            //----------------------------------------------------------
            if ("ASYNC".equals(responseType)){
            	return "".getBytes();
            }else{
            	return responseMessage.getBytes(); 
            }
        } catch(SocketTimeoutException ste) { // Read Timeout :: HttpClient 3.1일 경우
            //ste.printStackTrace();
        	logger.error("HttpClientAdapter] SocketTimeoutException : " + ste.toString() );
            throw ste;
        } catch(ConnectException ce) {
            //ce.printStackTrace();
        	logger.error("HttpClientAdapter] Connection Exception : " + ce.toString() );
            throw ce;
        } catch(Exception e) {
            //e.printStackTrace();
            throw e;
        } finally {
            method.releaseConnection();
            if(status!=HttpStatus.SC_OK) {
                String[] msgArgs = new String[1];
                msgArgs[0] = String.valueOf(status);
                String resMsg = ExceptionUtil.make("RDCEAIAHA014", msgArgs);
                if(logger.isDebugEnabled()){
                    logger.debug(resMsg);
                }
            }
        }  
    }
    
//    public static void main (String[] args){ //취약점소스 수정 2020.08.26
//    	HttpClientAdapter hc = new HttpClientAdapter();
//    	String message = "00001170 000DEVCHAP_0120120509140619000002002S                                          FEP               000000                                      000IFWCD950111IFWCD950112ELB0200400000       S2   D Y                                       0000        0000  0000000000000000000000000000000                              KOR000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000                                                                                                                                                                                                                                                          IO00000245TTASKEL3 ELB02003000002000   200612071230110000000120061207209900000112202074100400000072960200125930  0000000000001000출금인                              0800                                1234567890123456                                      @@";
//    	
//    	Properties p = new Properties();
//    	                            //http://192.168.120.139:30511/ESBWeb/EAIHttpCoreSyncAdapter
//    	p.put(HttpClientAdapter.URL, "http://192.168.120.139:30511/ESBWeb/EAIHttpRmsSyncAdapter");
//    	//p.put(HttpClientAdapter.URL, "http://192.168.120.139:30511/ESBWeb/EAIHttpCoreSyncAdapter");
//    	p.put(HttpClientAdapter.METHOD, HttpClientAdapter.METHOD_POST);
//    	p.put(HttpClientAdapter.ENCODE, "MS949");
//    	
//    	p.put(HttpClientAdapter.PARAMETER_NAME, "_message_");
//    	//p.put(HttpClientAdapter.ENCODE, "N");
//    	//p.put(HttpClientAdapter.HTTP_TIME_OUT, 30 *1000 );
//    	
//    	try {
//			Object obj2 = hc.execute(p,message.getBytes());
//		} catch (Exception e) {
//			//취약점소스 수정 2020.08.24
//        	logger.error(" error", e); 
//			// TODO Auto-generated catch block
//			//e.printStackTrace();
//		}
//    }    	
} 
