/*********************************************************************
*	 All Rights reserved,Copyright (c) K-Opticom 
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：JCHBatKssaidkHttpsBase
*   ソースファイル名：JCHBatKssaidkHttpsBase.java
*   作成者          ：富士通
*   日付            ：2017年04月08日
*＜機能概要＞
*   主処理(共通)<BR>
*   決済代行会社HTTPSリクエスト処理部品（基底）です。
*   呼び出し元にてエラーハンドリングしてください。
*＜修正履歴＞
*   バージョン  修正日      修正者      修正内容
*   v1.00       2017/04/08  富士通      新規作成
*
**********************************************************************/

package eo.business.common;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.HashMap;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.xml.ws.http.HTTPException;

import eo.common.constant.JPCBatchMessageConstant;
import eo.framework.application.JBSbatBusinessException;
import eo.framework.item.JBSbatCommonItem;
import eo.framework.log.JBSbatLogPrintControl;

/**
 * <p>
 * 決済代行会社HTTPSリクエスト独自処理部品（基底）クラスです。
 * </p>
 * @author 富士通
 */
public abstract class JCHBatKssaidkHttpsBase
{
	/** 部品ID*/
	private static final String PGID = "JCHBatKssaidkHttpsBase";
	
	/** パラメータセパレート文字:=*/
	protected static final String S_SEP_EQ = "=";
	
	/** パラメータセパレート文字:&*/
	protected static final String S_SEP_AN = "&";
	
	/** パラメータキー文字列*/
	protected static final String S_KEY_HEAD = "CR_";
	
	/** 通信方式パラメータ*/
	protected static final String S_SSL = "SSL";
	
	/** リクエスト種別パラメータ*/
	protected static final String S_POST = "POST";
	
	/** 文字コード*/
	protected static final String S_CHR_CODE = "Shift_JIS";
	
	/** 決済代行会社APIシステムエラー*/
	protected static final String S_AUTH_SYSERR = "9000000";
	
	/** 通信方式SSL*/
	protected static final String S_HTTPS = "https";
	
	/** 決済代行会社実行結果 */
	public static final String EXE_STATUS = "status";

	/** ログ用インスタンス */
	protected JBSbatLogPrintControl log = null;
	
	/**レスポンス格納key */
	public static final String RESPONSE = "response";

	/**
	 * ロガー設定
	 * 
	 * @param commonItem
	 */
	protected void setlogger(JBSbatCommonItem commonItem)
	{
		log = commonItem.getLogPrint();
	}
	
	/**
	 * 決済代行会社HTTPSリクエスト独自処理部品です。
	 * @param inMap 
	 * @param outmap 
	 * @throws Exception エラー全般
	 */
	protected void execute(HashMap<String, String> inMap, HashMap<String, ArrayList<String>> outmap) throws Exception
	{
		log.printDebugLog(PGID + "#execute start");
		
		HttpURLConnection conn = null;
		BufferedReader reader = null;
		URL url = null;
		String strUrl = null;
		String strApiNm = null;
		int timeout = 0;
		
		/*-----------------------------
		 * パラメータ設定
		 *----------------------------*/
		
		//system.properties設定値取得
		strUrl = JCCBatCommon.getApplicationConst("CH_KSSAIDAIKO_URL");
		strApiNm = JCCBatCommon.getApplicationConst("CH_KSSAIDAIKO_APINAME");
		timeout = Integer.parseInt(JCCBatCommon.getApplicationConst("CH_KSSAIDAIKO_TIMEOUT"));

		/*-----------------------------
		 * ＳＳＬ通信設定
		 *----------------------------*/
		// 通信方式判定
		boolean bSslFlg = false;
		if(strUrl.startsWith(S_HTTPS))
		{
			bSslFlg = true;
		}
		
		// SSL通信の場合、キーマネージャを生成
		if(bSslFlg)
		{
			KeyManager[] km = null;
			TrustManager[] tm = { new X509TrustManager() {

				/**
				 * X509Certificateスタブメソッド
				 * @return null
				 */
				public java.security.cert.X509Certificate[] getAcceptedIssuers() 
				{
					return null;
				}

				/**
				 * checkClientTrustedスタブメソッド
				 * @param arg0
				 * @param arg1
				 * @throws CertificateException
				 */
				public void checkClientTrusted(
						java.security.cert.X509Certificate[] arg0, String arg1)
						throws CertificateException 
				{
					// 自動生成されたメソッドスタブ
				}

				/**
				 * checkServerTrustedスタブメソッド
				 * @param arg0
				 * @param arg1
				 * @throws CertificateException
				 */
				public void checkServerTrusted(
						java.security.cert.X509Certificate[] arg0, String arg1)
						throws CertificateException 
				{
					// 自動生成されたメソッドスタブ
				}
			} };
			SSLContext sslcontext = SSLContext.getInstance(S_SSL);
			sslcontext.init(km, tm, new SecureRandom());
			HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
				
				/**
				 * verifyスタブメソッド
				 * @param aHostname
				 * @param aSession
				 * @return 決済代行会社APIへのリクエストパラメータ
				 */
				public boolean verify(String aHostname, SSLSession aSession) 
				{
					return true;
				}
			});
			HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext.getSocketFactory());
		}
		
		/*-----------------------------
		 * 決済代行会社呼び出し
		 *----------------------------*/
		// URL生成
		url = new URL(strUrl + strApiNm);
		log.printDebugLog(PGID + "#送信URLパラメータ" + url);
		InputStream is = null;

			try
			{
				// アプリケーションプロパティよりProxy設定値を取得
				String strPrxyHost = JCCBatCommon.getApplicationConst("CH_KSSAIDAIKO_HTTPS_PROXY_HOST");
				String strPrxyPort = JCCBatCommon.getApplicationConst("CH_KSSAIDAIKO_HTTPS_PROXY_PORT");
				
				int intProxyPort = 0;
				if(strPrxyHost != null && !"".equals(strPrxyHost))
				{
					intProxyPort = Integer.parseInt(strPrxyPort);
				}
				
				// SSLの場合、HttpsURLConnectionへキャスト
				if(bSslFlg)
				{
					// Proxy設定値がある場合はProxyをセットしてコネクションをオープン
					if(strPrxyHost != null && !"".equals(strPrxyHost)
							&& strPrxyPort != null && !"".equals(strPrxyPort))
					{
						Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(strPrxyHost, intProxyPort));
						conn = (HttpsURLConnection)url.openConnection(proxy);
					}
					else
					{
						conn = (HttpsURLConnection)url.openConnection();
					}
					log.printDebugLog(PGID + "#HttpsURLConnection openConnection");
				}
				else
				{
					conn = (HttpURLConnection)url.openConnection();
					log.printDebugLog(PGID + "#HttpURLConnection openConnection");
				}
				
				// リクエスト設定
				conn.setRequestMethod(S_POST);
				conn.setDoOutput(true);
				conn.setInstanceFollowRedirects(true);
				
				//タイムアウト設定
				conn.setReadTimeout(timeout);
				
				//POSTパラメータストリームの生成
				OutputStream os = conn.getOutputStream();
				PrintStream ps = new PrintStream(os);

				/*
				 * 送信パラメータ作成
				 */
				String reqStr = requestParamMake(inMap);
				log.printDebugLog(PGID + "#reqParam=" + reqStr);
				ps.print(reqStr);
				ps.close();
				
				// 接続開始ログ
				log.printDebugLog(PGID + "#connect start");
				/*
				 * 接続実行
				 */
				conn.connect();
				
				// 接続終了ログ
				log.printDebugLog(PGID + "#connect end");

				int statusCode = 500;
				statusCode = conn.getResponseCode();
				/*
				 * HTTP 応答メッセージから状態コードを取得する。 
				 * HTTP/1.0 200 OK
				 * HTTP/1.0 401 Unauthorized
				 */
				switch (statusCode) 
				{
				case HttpsURLConnection.HTTP_OK:	// HTTP OK
				
					// リクエスト結果読み出し
					is = conn.getInputStream();
					reader = new BufferedReader(new InputStreamReader(is, S_CHR_CODE));
					String str = null;
					//レスポンス格納用リスト作成
					ArrayList<String> strList = new ArrayList<String>();
				
					for(str = reader.readLine() ; null != str ; str = reader.readLine())
					{
						strList.add(str);
					}
					
					//レスポンス格納処理
					outmap.put(RESPONSE, strList);
					//ステータスコード返却
					inMap.put(EXE_STATUS, Integer.toString(statusCode));
				default:
					//ステータスコード返却
					inMap.put(EXE_STATUS, Integer.toString(statusCode));
				}
			}
			catch(SocketTimeoutException he)
			{
					throw he;
			}
			finally
			{
				if (reader != null)
				{
					reader.close();
				}
				if (conn != null)
				{
					conn.disconnect();
					conn = null;
				}
				log.printDebugLog(PGID + "#execute end");
			}
	}

	/**
	 * 決済代行会社APIに対して送信するリクエストパラメータを作成する。
	 * @param inMap メッセージキャリア
	 * @return 決済代行会社APIへのリクエストパラメータ
	 */
	@SuppressWarnings("unchecked")
	protected abstract String requestParamMake(HashMap inMap);

	
	/**
	 * ＮＵＬＬ、空文字の場合はtrueを返却します。
	 * 
	 * @param str
	 * @return boolean
	 */
	protected boolean isNullBlunk(String str)
	{
		if (str == null || "".equals(str))
		{
			return true;
		}
		return false;
	}
}
