/*********************************************************************
*	 All Rights reserved,Copyright (c) K-Opticom 
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：JECKA9020001TPMA
*   ソースファイル名：JECKA9020001TPMA.java
*   作成者          ：富士通
*   日付            ：2011年12月02日
*＜機能概要＞
*   主処理(共通)<BR>
*   PMP連携用排他制御顧客独自処理部品クラス.
*＜修正履歴＞
*   バージョン  修正日      修正者      修正内容
*   v1.00.00    2011/12/02  富士通      新規作成
*   v7.00.00    2014/02/01  富士通      OM-2013-0005307 配送スキーマ削除対応
*   v32.00.00   2017/05/26  FJ)河邊    【OM-2017-0000488】オープンカーソルエラー
*   v73.00.00   2025/01/22  FJ)丸田    【ANK-4570-00-00】コンテンツ新規同時申込み時契約仕様見直し対応
**********************************************************************/

package eo.ejb.cbs.mainproc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.fujitsu.futurity.common.JCMTraceLog;
import com.fujitsu.futurity.model.base.CAANConnectionMgr;
import com.fujitsu.futurity.model.base.CAANFinderException;
import com.fujitsu.futurity.model.base.CAANLog;
import com.fujitsu.futurity.model.base.CAANMsg;
import com.fujitsu.futurity.model.base.CAANRuntimeException;
import com.fujitsu.futurity.model.ejb.common.JSYejbConnection;
import com.fujitsu.futurity.model.ejb.common.JSYejbLog;
import com.fujitsu.futurity.model.ejb.common.fw.AgentDispatchContext;
import com.fujitsu.futurity.model.ejb.common.fw.AgentSystemEnv;
import com.fujitsu.futurity.model.ejb.common.fw.TemplateMainHandler;

import eo.ejb.cbs.cbsmsg.ECKA9020001CBSMsg;


/**
 * <p>
 * PMP連携用排他制御顧客独自処理部品クラスです。
 * </p>
 * @author 富士通
 */
public class JECKA9020001TPMA implements TemplateMainHandler
{
	/**
	 * コンストラクタ.
	 */
	public JECKA9020001TPMA()
	{
		super();
	}

	/**
	 * 名寄せ連携用排他制御顧客独自処理部品です。
	 * @param inCBSMsg CAANメッセージ
	 * @param inContext コンテキスト
	 * @throws CAANFinderException 
	 */
	public void invoke(CAANMsg inCBSMsg, AgentDispatchContext inContext) throws CAANFinderException
	{
		JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), "JECKA9020001TPMA#invoke start");
		boolean res = lockTargetRecord(inCBSMsg);
		inCBSMsg.set(ECKA9020001CBSMsg.LOCK_ERR_FLG, (res) ? "0" : "1");
		JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), "JECKA9020001TPMA#invoke end");
	}

	/**
	 * 対象データの排他ロックを行います。
	 * @param inCBSMsg CAANメッセージ
	 * @return 処理結果(true:成功、false:失敗)
	 * @throws CAANFinderException
	 */
	protected boolean lockTargetRecord(CAANMsg inCBSMsg) throws CAANFinderException {

		boolean result = true;

		CAANLog.println(CAANLog.LEVEL_FW, "CALL: JECKA9020001TPMA#lockTargetRecord");
		JCMTraceLog.logging("JECKA9020001TPMA#lockTargetRecord");

		String sysid = inCBSMsg.getString(ECKA9020001CBSMsg.SYSID);
		String funcCd = inCBSMsg.getString(ECKA9020001CBSMsg.FUNC_CODE);

		Connection cnct = null;
		PreparedStatement pstmt = null;
		ResultSet rslt = null;

		try
		{
			int retryCount = AgentSystemEnv.getInt("LOCK_RETRY_COUNT");
			int retryInterval = AgentSystemEnv.getInt("LOCK_RETRY_INTERVAL");

			cnct = JSYejbConnection.getConnection("DUAL");

			String[] sqlAll = null;

			if ("1".equals(funcCd))
			{
				sqlAll = new String[]{
					// お客様
					"SELECT UPD_DTM FROM CK_T_CUST WHERE SYSID = ? FOR UPDATE NOWAIT"
				};
			}
			else if ("2".equals(funcCd))
			{
				sqlAll = new String[]
				{
					// お客様
					"SELECT UPD_DTM FROM CK_T_CUST WHERE SYSID = ? FOR UPDATE NOWAIT",
					// 申込
					"SELECT UPD_DTM FROM KK_T_MSKM WHERE SYSID = ? FOR UPDATE NOWAIT",
					// アンケート回答
					"SELECT UPD_DTM FROM KK_T_ENQUETE_ANS WHERE SYSID = ? FOR UPDATE NOWAIT",
					// サービス契約排他制御
					"SELECT LAST_UPD_DTM AS UPD_DTM FROM KK_T_SVKEI_EXC_CTRL WHERE SVC_KEI_NO IN (SELECT SVC_KEI_NO FROM KK_T_SVC_KEI WHERE SYSID = ?) FOR UPDATE NOWAIT",
					// 紹介
					"SELECT UPD_DTM FROM KK_T_INTR WHERE SYSID = ? FOR UPDATE NOWAIT",
					// 請求契約
					"SELECT UPD_DTM FROM KK_T_SEIKY_KEI WHERE SYSID = ? FOR UPDATE NOWAIT",
					// 通知書
					"SELECT UPD_DTM FROM KK_T_TCHISHO WHERE SYSID = ? FOR UPDATE NOWAIT",
					// はぴeポイント契約
					"SELECT UPD_DTM FROM KK_T_HAPIE_POINT_KEI WHERE SYSID = ? FOR UPDATE NOWAIT",
					// オーダ設定
					"SELECT UPD_DTM FROM KK_T_ODR_SET WHERE SPOT_LOGIN_SYSID = ? FOR UPDATE NOWAIT",
					// 審査
					"SELECT UPD_DTM FROM KK_T_JUDGE WHERE SYSID = ? FOR UPDATE NOWAIT",
					// オーダ発行条件
					"SELECT UPD_DTM FROM KK_T_ODR_HAKKO_JOKEN WHERE SPOT_LOGIN_SYSID = ? FOR UPDATE NOWAIT",
					// メール情報
					"SELECT UPD_DTM FROM KK_T_MAIL_INFO WHERE SYSID = ? FOR UPDATE NOWAIT",
					// 加入御礼書発行
					"SELECT UPD_DTM FROM KK_T_KANUORESO_HAKKO WHERE SYSID = ? FOR UPDATE NOWAIT",
					// PMPお客様情報変更依頼
					"SELECT UPD_DTM FROM KK_T_PMP_CSIF_CHGREQ WHERE SYSID = ? FOR UPDATE NOWAIT",
// ANK-4570-00-00 MOD START
					// データ抽出項目設定
//					"SELECT UPD_DTM FROM KK_M_DCHSKM WHERE DCHSKM_CD IN (SELECT DCHSKM_CD FROM KK_T_DCHSKMST WHERE SYSID = ?) FOR UPDATE NOWAIT",
					"SELECT UPD_DTM FROM KK_T_DCHSKMST WHERE SYSID = ? FOR UPDATE NOWAIT",
// ANK-4570-00-00 MOD END
					// 異動予約
					"SELECT UPD_DTM FROM KK_T_IDO_RSV WHERE SYSID = ? or BUNKATSU_SK_SYSID = ? or HEIGO_SK_SYSID = ? FOR UPDATE NOWAIT",
					// 工事案件
					"SELECT UPD_DTM FROM KU_T_KOJIAK WHERE SYSID = ? FOR UPDATE NOWAIT"
				};
			}

			for (String sql : sqlAll) {
				CAANLog.println(CAANLog.LEVEL_FW, "sql = [" + sql + "]");
				int retryCounter = 0;
				boolean bRetry = true;
				while (bRetry){
					try
					{
						pstmt = cnct.prepareStatement(sql);
						int pos = 0;
						for (int i = 1; i <= 100; i++)
						{
							pos = sql.indexOf("?", pos + 1);
							if (pos < 0)
							{
								break;
							}
							pstmt.setString(i, sysid);
						}
						rslt = pstmt.executeQuery();
						bRetry = false;
					}
					catch (SQLException ex)
					{
						if (isDBLockException(ex))
						{
							CAANLog.println(CAANLog.LEVEL_FW, "JECKA9020001TPMA#lockTargetRecord:DBロック中...");
							if (retryCounter >= retryCount)
							{
								CAANLog.println(CAANLog.LEVEL_FW, "JECKA9020001TPMA#lockTargetRecord:リトライオーバー");
								result = false;
								break;
								//throw ex;
							}
							++retryCounter;
							bRetry = true;
							if (pstmt != null)
							{
								pstmt.close();
								pstmt = null;
							}
							try
							{
								Thread.sleep(retryInterval * 1000);
							}
							catch (Exception localException)
							{
							}
							CAANLog.println(CAANLog.LEVEL_FW, "JECKA9020001TPMA#lockTargetRecord:リトライ中(" + retryCounter + "回目)");
						}
						else
						{
							throw ex;
						}
					}
				}

				if ((rslt != null) && (!(rslt.next())))
				{
					// 対象データがない場合もありえる為、何もしない
				}

				if (rslt != null)
				{
					rslt.close();
					rslt = null;
				}

				if (pstmt != null)
				{
					pstmt.close();
					pstmt = null;
				}

				if (!result)
				{
					break;
				}
			}

		} catch (SQLException e)
		{
			throw new CAANRuntimeException(e);
		}
		finally
		{
// OM-2017-0000488 2017/05/26 MOD START
//			if (cnct != null)
//			{
//				CAANConnectionMgr.getInstance().close(cnct);
//			}
			// 資源の解放
			try
			{
				if (rslt != null)
				{
					rslt.close();
				}
				if (pstmt != null)
				{
					pstmt.close();
				}
				if (cnct != null)
				{
					CAANConnectionMgr.getInstance().close(cnct);
				}
			} catch (Exception e) {
				throw new CAANRuntimeException(e);
			}
// OM-2017-0000488 2017/05/26 MOD END
		}

		return result;
	}

	/**
	 * 例外がＤＢロックエラーに起因するものかどうかを判定する
	 * @param e 例外
	 * @return true:DBロックエラーに起因、false:それ以外
	 */
	private boolean isDBLockException(Exception e)
	{
		boolean bLockError = false;

		if (e instanceof SQLException)
		{
			String codes = AgentSystemEnv.getString("LOCK_ERROR_CODE");
			String[] code = codes.trim().split(",");
			String message = e.getMessage();
			for (int i = 0; i < code.length; ++i)
			{
				if (message.indexOf(code[i]) < 0) continue;
				bLockError = true;
				break;
			}
		}
		return bLockError;
	}
}
