/*******************************************************************************
 *	All Rights reserved,Copyright (c) K-Opticom
 ********************************************************************************
 *＜プログラム内容＞
 *	システム名		：eo顧客基幹システム
 *	モジュール名	：JKKejbExclusiveProcKK2811
 *	ソースファイル名：JKKejbExclusiveProcKK2811.java
 *	作成者			：富士通
 *	日付			：2011年11月28日
 *＜機能概要＞
 *	機器オプションサービス契約を起点とするルートの排他処理部品。
 *＜修正履歴＞
 *	バージョン	修正日		修正者		修正内容
 *	v7.00.00	2013/11/11	富士通		新規作成
 *	v7.00.01	2013/12/18	FJ)大山		IT1-2013-0001703
 *	v9.00.00	2014/04/28	FJ)大山		ANK-2054-00-00
 *
 ********************************************************************************/

package eo.ejb.common.db;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;

import com.fujitsu.futurity.model.base.CAANMsg;
import com.fujitsu.futurity.model.base.CAANRuntimeException;
import com.fujitsu.futurity.model.ejb.common.JSYejbDBAccess;
import com.fujitsu.futurity.model.ejb.common.JSYejbLog;

import eo.ejb.cbm.entity.KK0251ETMsg;
import eo.ejb.cbm.entity.KK0341ETMsg;
import eo.ejb.cbm.entity.KK2111ETMsg;
import eo.ejb.cbm.entity.KK2811ETMsg;
import eo.ejb.common.JKKModelCommon;
import eo.ejb.common.JKKModelConst;

/**
 * <p>
 * 機器オプションサービス契約を起点とするルートの排他処理部品です。
 * </p>
 * @author 富士通
 *
 */
public class JKKejbExclusiveProcKK2811
{
	/** データ取得結果設定項目名（プライマリキー） */
	private static final String SET_PRIMARY = "SET_PRIMARY";

	/** データ取得結果設定項目名（更新年月日時分秒） */
	private static final String SET_UPD_DTM = "SET_UPD_DTM";
	
	/** サービス契約排他制御取得項目（サービス契約番号） */
	private static final String SVC_KEI_NO = "SVC_KEI_NO";

	/** サービス契約排他制御取得項目（最終更新年月日時分秒） */
	private static final String UPD_DTM = "UPD_DTM";

	/**
	 * 更新系インターフェイス使用時の処理を行います（機器オプションサービス契約番号指定）。
	 * レコードのロック、タイムスタンプの実施、ロック対象レコードの更新を行います。
	 * @param inETMsg 処理内で使用する項目を保持しているメッセージ
	 * @param key 機器オプションサービス契約番号
	 * @param updDtmBf タイムスタンプチェック用更新年月日時分秒（更新前）
	 * @param funcCd 機能コード
	 * @return ロック失敗の場合、タイムスタンプ不一致の場合はfalseを返却する。
	 */
	public boolean isExProcKkopSvcKeiNo(CAANMsg inETMsg, String key, String updDtmBf, String funcCd)
	{
		JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), "call:JKKejbExclusiveProcKK2811#isExProcKkopSvcKeiNo");

		// 機器オプションサービス契約番号が設定されていない場合はtrueを返却する
		if (null == key)
		{
			return true;
		}

		// 更新年月日時分秒（更新前）が設定されていない場合はtrueを返却する
		if (null == updDtmBf)
		{
			return true;
		}

		// データ設定用MAP
		HashMap<String, ArrayList<String>> retMap = new HashMap<String, ArrayList<String>>();

		// レコードロック、データ取得の実行
		try 
		{
			retMap = execSQLForLockKkopSvcKeiNo(inETMsg, key);
		}
		catch (CAANRuntimeException ce)
		{
			// レコードロックに失敗した場合はfalseを返却する
			return false;
		}
		
		// 取得結果からそれぞれのリストを取り出す
		ArrayList<String> keyArray = retMap.get(SET_PRIMARY);
		ArrayList<String> updArray = retMap.get(SET_UPD_DTM);
		
		// データが取得できなかった場合はtrueを返却する
		if(keyArray.size() < 1)
		{
			return true;
		}

		// 共通処理のインスタンスを生成
		JKKejbExclusiveProcCommon epc = new JKKejbExclusiveProcCommon();

		// タイムスタンプチェックを行い、チェックエラーの場合はfalseを返却する。
		if (!epc.isTimeStampCheck(updArray, updDtmBf))
		{
			return false;
		}

		// 機能コードが実行モードの場合はロック対象レコード更新処理を行う
		if (!epc.isFuncMode(funcCd))
		{
			epc.updateKK2111(inETMsg, keyArray);
		}

		return true;
	}

	/**
	 * 照会系インターフェイス使用時の処理を行います（機器オプションサービス契約番号指定）。
	 * 指定されたキーに紐付く親テーブルを各ルートから検索し、
	 * その中で最大の更新年月日時分秒を取得します。
	 * @param inMsg 処理対象のメッセージ
	 * @param key 機器オプションサービス契約番号
	 * @return 指定したキーに紐付く最終更新年月日時分秒。
	 */
	public String getLastUpdDtmKkopSvcKeiNo(CAANMsg inMsg, String key)
	{
		JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), "call:JKKejbExclusiveProcKK2811#getLastUpdDtmKkopSvcKeiNo");
		JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), "call:JKKejbExclusiveProcKK2811#key=" + key);

		CAANMsg kkopSvcKei = new JKKejbKK2811DBABase().getKK2811Current(key, JKKModelCommon.getOpeDate(inMsg));
		String kktkSvcKeiNo = kkopSvcKei.getString(KK2811ETMsg.KKTK_SVC_KEI_NO);
		
		CAANMsg kktkSvcKei = new JKKejbKK0341DBABase().getKK0341Current(kktkSvcKeiNo, JKKModelCommon.getOpeDate(inMsg));

		String oyaKeiSkbtCd  = kktkSvcKei.getString(KK0341ETMsg.OYA_KEI_SKBT_CD);
		
		if(oyaKeiSkbtCd == null) {
			return null;
		}
		
		
		if(JKKModelConst.OYA_KEI_SKBT_CD_SVC_KEI.equals(oyaKeiSkbtCd) || JKKModelConst.OYA_KEI_SKBT_CD_SVC_KEI_UCWK.equals(oyaKeiSkbtCd)) {
			
			String svcKeiNo = kktkSvcKei.getString(KK0341ETMsg.SVC_KEI_NO);
			
			// 最終更新年月日候補レコードの取得
			return  new JKKejbExclusiveProcKK2111().getLastUpdDtmSvcKeiNo(inMsg, svcKeiNo);
		} 
		else {
		
			// 最終更新年月日候補レコードの取得
			HashMap<String, ArrayList<String>> retMap = execSQLForSelectKkopSvcKeiNo(inMsg, key);

			// 取得結果から更新年月日時分秒のリストを取り出す
			ArrayList<String>updArray = retMap.get(SET_UPD_DTM);
	
			// データが取得できなかった場合はnullを返却する
			if(updArray.size() < 1)
			{
				return null;
			}

			// 最終更新年月日時分秒を取得する
			String maxUpdDtm = new JKKejbExclusiveProcCommon().getLastUpdDtm(updArray);

			return maxUpdDtm;
		}
	}

	/**
	 * 機器オプションサービス契約番号に紐付く
	 * 各ルートから導き出される親契約のロックとデータの取得を行います。
	 * @param inMsg バインド変数に設定するための情報を保持しているメッセージ
	 * @param key 機器オプションサービス契約番号
	 * @return 実行結果を保持したリスト
	 * 			┣サービス契約番号
	 * 			┗更新年月日時分秒（という名称の最終更新年月日時分秒）
	 */
	private HashMap<String, ArrayList<String>> execSQLForLockKkopSvcKeiNo(CAANMsg inMsg, String key)
	{
		// データベースアクセス機能インスタンスを生成
		JSYejbDBAccess jsydba = new JSYejbDBAccess(KK2111ETMsg.getTableName());

		try
		{
			// 初期化処理を行う
			jsydba.initialize();

			// プリコンパイルするSQL文を設定（データ取得用SQL文）
			jsydba.prepareStatement(creSQLKkopSvcKeiNo());

			// バインド変数リストの取得
			ArrayList<String> strBind = creBindKkopSvcKeiNo(inMsg, key);

			// パラメータの設定
			for (int i = 0; i < strBind.size(); i++)
			{
				jsydba.setParam(strBind.get(i));
			}

			// PreparedStatementオブジェクトのSQLクエリを実行
			jsydba.executeQuery();

			// 結果設定用ArrayList
			ArrayList<String> setKey = new ArrayList<String>();
			ArrayList<String> setUpd = new ArrayList<String>();

			// 取得結果をメッセージキャリアに格納
			while (jsydba.next())
			{
				// ArrayListに取得結果を設定
				setKey.add(jsydba.getString(SVC_KEI_NO));
				setUpd.add(jsydba.getString(UPD_DTM));
			}
			
			//ロック処理を行う
			for (int i = 0; i< setKey.size(); i++)
			{
				CAANMsg inETMsg = new CAANMsg(KK2111ETMsg.class.getName());
				inETMsg.set(KK2111ETMsg.SVC_KEI_NO, setKey.get(i));
				
				new JKKejbDBAUtil(inMsg).findByKeyForUpdate(inETMsg);
			}

			// 返却用HashMap
			HashMap<String, ArrayList<String>> retMap = new HashMap<String, ArrayList<String>>();

			// 設定したArrayListをHashMapに格納
			retMap.put(SET_PRIMARY, setKey);
			retMap.put(SET_UPD_DTM, setUpd);

			return retMap;
		}
		catch(SQLException se)
		{
			throw new CAANRuntimeException(se);
		}
		finally
		{
			// リソースの開放処理を行う
			jsydba.terminal();
		}
	}

	/**
	 * 機器オプションサービス契約番号に紐付く
	 * 各ルートから導き出される親契約のデータの取得を行います。
	 * @param inMsg バインド変数に設定するための情報を保持しているメッセージ
	 * @param key 機器オプションサービス契約番号
	 * @return 実行結果を保持したリスト
	 * 			┣サービス契約番号
	 * 			┗更新年月日時分秒（という名称の最終更新年月日時分秒）
	 */
	private HashMap<String, ArrayList<String>> execSQLForSelectKkopSvcKeiNo(CAANMsg inMsg, String key)
	{
		// データベースアクセス機能インスタンスを生成
		JSYejbDBAccess jsydba = new JSYejbDBAccess(KK2111ETMsg.getTableName());

		try
		{
			// 初期化処理を行う
			jsydba.initialize();

			// プリコンパイルするSQL文を設定（データ取得用SQL文）
			jsydba.prepareStatement(creSQLKkopSvcKeiNo());

			// バインド変数リストの取得
			ArrayList<String> strBind = creBindKkopSvcKeiNo(inMsg, key);

			// パラメータの設定
			for (int i = 0; i < strBind.size(); i++)
			{
				jsydba.setParam(strBind.get(i));
			}

			// PreparedStatementオブジェクトのSQLクエリを実行
			jsydba.executeQuery();

			// 結果設定用ArrayList
			ArrayList<String> setKey = new ArrayList<String>();
			ArrayList<String> setUpd = new ArrayList<String>();

			// 取得結果をメッセージキャリアに格納
			while (jsydba.next())
			{
				// ArrayListに取得結果を設定
				setKey.add(jsydba.getString(SVC_KEI_NO));
				setUpd.add(jsydba.getString(UPD_DTM));
			}			

			// 返却用HashMap
			HashMap<String, ArrayList<String>> retMap = new HashMap<String, ArrayList<String>>();

			// 設定したArrayListをHashMapに格納
			retMap.put(SET_PRIMARY, setKey);
			retMap.put(SET_UPD_DTM, setUpd);

			return retMap;
		}
		catch(SQLException se)
		{
			throw new CAANRuntimeException(se);
		}
		finally
		{
			// リソースの開放処理を行う
			jsydba.terminal();
		}
	}

	/**
	 * 機器オプションサービス契約番号に紐付く、各ルートから親契約を取得するためのSQL文を作成します。
	 * @return データ取得用のSQL文。
	 */
	private String creSQLKkopSvcKeiNo()
	{
		StringBuffer buff = new StringBuffer();

		buff.append(" SELECT ");
		buff.append(" 	KK2111.SVC_KEI_NO, ");
		buff.append(" 	KK2111.LAST_UPD_DTM AS UPD_DTM ");
		buff.append(" FROM ");
		buff.append(" 	KK_T_SVKEI_EXC_CTRL KK2111 ");
		buff.append(" 	INNER JOIN KK_T_SVC_KEI KK0081 ");
		buff.append(" 	ON KK2111.SVC_KEI_NO = KK0081.SVC_KEI_NO ");
		buff.append(" 	INNER JOIN KK_T_KAISEN_TG_SVKEI KK0241 ");
		buff.append(" 	ON KK2111.SVC_KEI_NO = KK0241.SVC_KEI_NO ");
		buff.append(" 	INNER JOIN KK_T_SVKEI_KAISEN_UW KK0251 ");
		buff.append(" 	ON KK0241.SVC_KEI_KAISEN_UCWK_NO = KK0251.SVC_KEI_KAISEN_UCWK_NO ");
		buff.append(" 	INNER JOIN KK_T_KKTK_SVC_KEI KK0341 ");
		buff.append(" 	ON KK0251.SVC_KEI_KAISEN_UCWK_NO = KK0341.SVC_KEI_KAISEN_UCWK_NO ");
		buff.append(" 	INNER JOIN KK_T_KKOP_SVC_KEI KK2811 ");
		buff.append(" 	ON KK2811.KKTK_SVC_KEI_NO = KK0341.KKTK_SVC_KEI_NO ");
		buff.append(" 	INNER JOIN KK_M_EO_BRAND_KKOSV KK2851 ");
		buff.append(" 	ON KK2811.KKOP_SVC_CD = KK2851.KKOP_SVC_CD ");	
		buff.append(" WHERE KK2811.KKOP_SVC_KEI_NO = ?  ");
		buff.append("       AND    KK2851.EO_BRAND_CD = '01' ");
		buff.append(" 		AND    (KK2811.KKOP_SVC_KEI_NO, KK2811.RSV_APLY_YMD || KK2811.GENE_ADD_DTM) = ");
		buff.append(" 	(SELECT KK2811_GENE.KKOP_SVC_KEI_NO, MAX(KK2811_GENE.RSV_APLY_YMD || KK2811_GENE.GENE_ADD_DTM) AS KK2811_MAX ");
		buff.append(" 	FROM   KK_T_KKOP_SVC_KEI KK2811_GENE ");
		buff.append(" 	WHERE  KK2811_GENE.KKOP_SVC_KEI_NO = KK2811.KKOP_SVC_KEI_NO ");
		buff.append(" 		AND    KK2811_GENE.RSV_APLY_YMD <= ? ");
		buff.append(" 		AND    KK2811_GENE.RSV_APLY_CD = '2' ");
		buff.append(" 		AND    KK2811_GENE.MK_FLG = '0' ");
		buff.append(" 		GROUP BY KK2811_GENE.KKOP_SVC_KEI_NO) ");
		buff.append(" 		AND    (KK0081.SVC_KEI_NO, KK0081.RSV_APLY_YMD || KK0081.GENE_ADD_DTM) = ");
		buff.append(" 	(SELECT KK0081_GENE.SVC_KEI_NO, MAX(KK0081_GENE.RSV_APLY_YMD || KK0081_GENE.GENE_ADD_DTM) AS KK0081_MAX ");
		buff.append(" 	FROM   KK_T_SVC_KEI KK0081_GENE ");
		buff.append(" 	WHERE  KK0081_GENE.SVC_KEI_NO = KK0081.SVC_KEI_NO ");
		buff.append(" 		AND    KK0081_GENE.RSV_APLY_YMD <= ? ");
		buff.append(" 		AND    KK0081_GENE.RSV_APLY_CD = '2' ");
		buff.append(" 		AND    KK0081_GENE.MK_FLG = '0' ");
		buff.append(" 		GROUP BY KK0081_GENE.SVC_KEI_NO) ");
		buff.append(" 		AND    (KK0341.KKTK_SVC_KEI_NO, KK0341.RSV_APLY_YMD || KK0341.GENE_ADD_DTM) = ");
		buff.append(" 	(SELECT KK0341_GENE.KKTK_SVC_KEI_NO, MAX(KK0341_GENE.RSV_APLY_YMD || KK0341_GENE.GENE_ADD_DTM) AS KK0341_MAX ");
		buff.append(" 	FROM   KK_T_KKTK_SVC_KEI KK0341_GENE ");
		buff.append(" 	WHERE  KK0341_GENE.KKTK_SVC_KEI_NO = KK0341.KKTK_SVC_KEI_NO ");
		buff.append(" 		AND    KK0341_GENE.RSV_APLY_YMD <= ? ");
		buff.append(" 		AND    KK0341_GENE.RSV_APLY_CD = '2' ");
		buff.append(" 		AND    KK0341_GENE.MK_FLG = '0' ");
		buff.append(" 		GROUP BY KK0341_GENE.KKTK_SVC_KEI_NO) ");
		buff.append(" 	AND    (KK0251.SVC_KEI_KAISEN_UCWK_NO, KK0251.GENE_ADD_DTM) = ");
		buff.append(" 		(SELECT KK0251_GENE.SVC_KEI_KAISEN_UCWK_NO, MAX(KK0251_GENE.GENE_ADD_DTM) AS KK0251_MAX ");
		buff.append(" 		FROM   KK_T_SVKEI_KAISEN_UW KK0251_GENE ");
		buff.append(" 		WHERE  KK0251_GENE.SVC_KEI_KAISEN_UCWK_NO = KK0251.SVC_KEI_KAISEN_UCWK_NO ");
		buff.append(" 		AND    KK0251_GENE.MK_FLG = '0' ");
		buff.append(" 		GROUP BY KK0251_GENE.SVC_KEI_KAISEN_UCWK_NO) ");
		buff.append(" 	AND    KK2851.EO_BRAND_KKOP_SVC_TSTAYMD <=  ? ");
		buff.append(" 	AND    KK2851.EO_BRAND_KKOP_SVC_TENDYMD >=  ? ");
		buff.append(" 	AND    KK0081.SVC_CD = '01' ");
		buff.append(" 	AND    KK0241.MK_FLG = '0' ");
		buff.append(" 	AND    KK2851.MK_FLG = '0' ");
		buff.append(" UNION ");
		buff.append(" SELECT ");
		buff.append(" 	KK2111.SVC_KEI_NO, ");
		buff.append(" 	KK2111.LAST_UPD_DTM AS UPD_DTM ");
		buff.append(" FROM ");
		buff.append(" 	KK_T_SVKEI_EXC_CTRL KK2111 ");
		buff.append(" 	INNER JOIN KK_T_SVC_KEI KK0081 ");
		buff.append(" 	ON KK2111.SVC_KEI_NO = KK0081.SVC_KEI_NO ");
		buff.append(" 	INNER JOIN KK_T_KAISEN_TG_SVKEI KK0241 ");
		buff.append(" 	ON KK2111.SVC_KEI_NO = KK0241.SVC_KEI_NO ");
		buff.append(" 	INNER JOIN KK_T_SVKEI_KAISEN_UW KK0251 ");
		buff.append(" 	ON KK0241.SVC_KEI_KAISEN_UCWK_NO = KK0251.SVC_KEI_KAISEN_UCWK_NO ");
		buff.append(" 	INNER JOIN KK_T_KKTK_SVC_KEI KK0341 ");
		buff.append(" 	ON KK0251.SVC_KEI_KAISEN_UCWK_NO = KK0341.SVC_KEI_KAISEN_UCWK_NO ");
		buff.append(" 	INNER JOIN KK_T_KKOP_SVC_KEI KK2811 ");
		buff.append(" 	ON KK2811.KKTK_SVC_KEI_NO = KK0341.KKTK_SVC_KEI_NO ");
		buff.append(" 	INNER JOIN KK_M_EO_BRAND_KKOSV KK2851 ");
		buff.append(" 	ON KK2811.KKOP_SVC_CD = KK2851.KKOP_SVC_CD ");	
		buff.append(" WHERE KK2811.KKOP_SVC_KEI_NO = ?  ");
		buff.append("       AND    KK2851.EO_BRAND_CD = '02' ");
		buff.append(" 		AND    (KK2811.KKOP_SVC_KEI_NO, KK2811.RSV_APLY_YMD || KK2811.GENE_ADD_DTM) = ");
		buff.append(" 	(SELECT KK2811_GENE.KKOP_SVC_KEI_NO, MAX(KK2811_GENE.RSV_APLY_YMD || KK2811_GENE.GENE_ADD_DTM) AS KK2811_MAX ");
		buff.append(" 	FROM   KK_T_KKOP_SVC_KEI KK2811_GENE ");
		buff.append(" 	WHERE  KK2811_GENE.KKOP_SVC_KEI_NO = KK2811.KKOP_SVC_KEI_NO ");
		buff.append(" 		AND    KK2811_GENE.RSV_APLY_YMD <= ? ");
		buff.append(" 		AND    KK2811_GENE.RSV_APLY_CD = '2' ");
		buff.append(" 		AND    KK2811_GENE.MK_FLG = '0' ");
		buff.append(" 		GROUP BY KK2811_GENE.KKOP_SVC_KEI_NO) ");
		buff.append(" 		AND    (KK0081.SVC_KEI_NO, KK0081.RSV_APLY_YMD || KK0081.GENE_ADD_DTM) = ");
		buff.append(" 	(SELECT KK0081_GENE.SVC_KEI_NO, MAX(KK0081_GENE.RSV_APLY_YMD || KK0081_GENE.GENE_ADD_DTM) AS KK0081_MAX ");
		buff.append(" 	FROM   KK_T_SVC_KEI KK0081_GENE ");
		buff.append(" 	WHERE  KK0081_GENE.SVC_KEI_NO = KK0081.SVC_KEI_NO ");
		buff.append(" 		AND    KK0081_GENE.RSV_APLY_YMD <= ? ");
		buff.append(" 		AND    KK0081_GENE.RSV_APLY_CD = '2' ");
		buff.append(" 		AND    KK0081_GENE.MK_FLG = '0' ");
		buff.append(" 		GROUP BY KK0081_GENE.SVC_KEI_NO) ");
		buff.append(" 		AND    (KK0341.KKTK_SVC_KEI_NO, KK0341.RSV_APLY_YMD || KK0341.GENE_ADD_DTM) = ");
		buff.append(" 	(SELECT KK0341_GENE.KKTK_SVC_KEI_NO, MAX(KK0341_GENE.RSV_APLY_YMD || KK0341_GENE.GENE_ADD_DTM) AS KK0341_MAX ");
		buff.append(" 	FROM   KK_T_KKTK_SVC_KEI KK0341_GENE ");
		buff.append(" 	WHERE  KK0341_GENE.KKTK_SVC_KEI_NO = KK0341.KKTK_SVC_KEI_NO ");
		buff.append(" 		AND    KK0341_GENE.RSV_APLY_YMD <= ? ");
		buff.append(" 		AND    KK0341_GENE.RSV_APLY_CD = '2' ");
		buff.append(" 		AND    KK0341_GENE.MK_FLG = '0' ");
		buff.append(" 		GROUP BY KK0341_GENE.KKTK_SVC_KEI_NO) ");
		buff.append(" 	AND    (KK0251.SVC_KEI_KAISEN_UCWK_NO, KK0251.GENE_ADD_DTM) = ");
		buff.append(" 		(SELECT KK0251_GENE.SVC_KEI_KAISEN_UCWK_NO, MAX(KK0251_GENE.GENE_ADD_DTM) AS KK0251_MAX ");
		buff.append(" 		FROM   KK_T_SVKEI_KAISEN_UW KK0251_GENE ");
		buff.append(" 		WHERE  KK0251_GENE.SVC_KEI_KAISEN_UCWK_NO = KK0251.SVC_KEI_KAISEN_UCWK_NO ");
		buff.append(" 		AND    KK0251_GENE.MK_FLG = '0' ");
		buff.append(" 		GROUP BY KK0251_GENE.SVC_KEI_KAISEN_UCWK_NO) ");
		buff.append(" 	AND    KK2851.EO_BRAND_KKOP_SVC_TSTAYMD <=  ? ");
		buff.append(" 	AND    KK2851.EO_BRAND_KKOP_SVC_TENDYMD >=  ? ");
		buff.append(" 	AND    KK0081.SVC_CD = '02' ");
		buff.append(" 	AND    KK0241.MK_FLG = '0' ");
		buff.append(" 	AND    KK2851.MK_FLG = '0' ");

		
		return buff.toString();
	}

	/**
	 * 機器オプションサービス契約番号指定時のSQL文に設定するためのバインド変数リストの作成を行います。
	 * @param inMsg バインド変数に設定するための情報を保持しているメッセージ
	 * @param key 機器オプションサービス契約番号
	 * @return SQLに設定するためのバインド変数のリスト。
	 */
	private ArrayList<String> creBindKkopSvcKeiNo(CAANMsg inMsg, String key)
	{
		ArrayList<String> retList = new ArrayList<String>();

		// バインド変数の設定
		retList.add(key);
		retList.add(JKKModelCommon.getOpeDate(inMsg));
		retList.add(JKKModelCommon.getOpeDate(inMsg));
		retList.add(JKKModelCommon.getOpeDate(inMsg));
		retList.add(JKKModelCommon.getOpeDate(inMsg));
		retList.add(JKKModelCommon.getOpeDate(inMsg));
		retList.add(key);
		retList.add(JKKModelCommon.getOpeDate(inMsg));
		retList.add(JKKModelCommon.getOpeDate(inMsg));
		retList.add(JKKModelCommon.getOpeDate(inMsg));
		retList.add(JKKModelCommon.getOpeDate(inMsg));
		retList.add(JKKModelCommon.getOpeDate(inMsg));

		return retList;
	}

	/**
	 * 取得限定処理を行います（機器オプションサービス契約番号指定）。
	 * 機器オプションサービス契約番号に紐付く
	 * 各ルートから導き出される親契約のデータの取得を行います。
	 * @param inETMsg 処理内で使用する項目を保持しているメッセージ
	 * @param key 機器オプションサービス契約番号
	 * @return 実行結果を保持したリスト
	 * 			┣サービス契約番号
	 * 			┗更新年月日時分秒（という名称の最終更新年月日時分秒）
	 */
	public HashMap<String, ArrayList<String>> getRecordKkopSvcKeiNo(CAANMsg inETMsg, String key)
	{
		JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), "call:JKKejbExclusiveProcKK2811#getRecordKkopSvcKeiNo");
		JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), "call:JKKejbExclusiveProcKK2811#key=" + key);

		// 指定されたキーに紐付くデータを取得して返却する
		return execSQLForLockKkopSvcKeiNo(inETMsg, key);
	}
	
	/**
	 * 更新系インターフェイス使用時の処理を行います（サービス契約回線内訳番号指定）。
	 * レコードのロック、タイムスタンプの実施、ロック対象レコードの更新を行います。
	 * @param inETMsg 処理内で使用する項目を保持しているメッセージ
	 * @param key サービス契約回線内訳番号
	 * @param updDtmBf タイムスタンプチェック用更新年月日時分秒（更新前）
	 * @param funcCd 機能コード
	 * @param kkop_svc_cd 機器オプションサービスコード
	 * @return ロック失敗の場合、タイムスタンプ不一致の場合はfalseを返却する。
	 */
	public boolean isExProcKaisenUcwkNo(CAANMsg inETMsg, String key, String updDtmBf, String funcCd, String kkop_svc_cd)
	{
		JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), "call:JKKejbExclusiveProcKK0251#isExProcKaisenUcwkNo");

		// サービス契約回線内訳番号が設定されていない場合はtrueを返却する
		if(null == key)
		{
			return true;
		}
		
		// 更新年月日時分秒（更新前）が設定されていない場合はtrueを返却する
		if(null == updDtmBf)
		{
			return true;
		}

		// データ設定用MAP
		HashMap<String, ArrayList<String>> retMap = new HashMap<String, ArrayList<String>>();

		// レコードロック、データ取得の実行
		try 
		{
			retMap = execSQLForLockKaisenUcwkNo(inETMsg, key , kkop_svc_cd);
		}
		catch (CAANRuntimeException ce)
		{
			// レコードロックに失敗した場合はfalseを返却する
			return false;
		}

		// 取得結果からそれぞれのリストを取り出す
		ArrayList<String> keyArray = retMap.get(SET_PRIMARY);
		ArrayList<String> updArray = retMap.get(SET_UPD_DTM);

		// データが取得できなかった場合はtrueを返却する
		if(keyArray.size() < 1)
		{
			return true;
		}

		// 共通処理のインスタンスを生成
		JKKejbExclusiveProcCommon epc = new JKKejbExclusiveProcCommon();

		// タイムスタンプチェックを行い、チェックエラーの場合はfalseを返却する。
		if (!epc.isTimeStampCheck(updArray, updDtmBf))
		{
			return false;
		}

		// 機能コードが実行モードの場合はロック対象レコード更新処理を行う
		if (!epc.isFuncMode(funcCd))
		{
			epc.updateKK2111(inETMsg, keyArray);
		}

		return true;
	}
	
	/**
	 * 照会系インターフェイス使用時の処理を行います（機器オプションサービス契約番号）。
	 * 指定されたキーに紐付く親テーブルを各ルートから検索し、
	 * その中で最大の更新年月日時分秒を取得します。
	 * @param inMsg 処理対象のメッセージ
	 * @param key 機器オプションサービス契約番号
	 * @return 指定したキーに紐付く最終更新年月日時分秒。
	 */
	public String getLastUpdDtmKaisenUcwkNo(CAANMsg inMsg, String key , String kkop_svc_cd)
	{
		JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), "call:JKKejbExclusiveLockKK0251#getLastUpdDtmSvcKeiKaiUcwkNo");
		JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), "call:JKKejbExclusiveLockKK0251#key=" + key);
		


		CAANMsg kkopSvcKei = new JKKejbKK2811DBABase().getKK2811Current(key, JKKModelCommon.getOpeDate(inMsg));
		String kktkSvcKeiNo = kkopSvcKei.getString(KK2811ETMsg.KKTK_SVC_KEI_NO);
		
		CAANMsg kktkSvcKei = new JKKejbKK0341DBABase().getKK0341Current(kktkSvcKeiNo, JKKModelCommon.getOpeDate(inMsg));

		String oyaKeiSkbtCd  = kktkSvcKei.getString(KK0341ETMsg.OYA_KEI_SKBT_CD);
		
		if(oyaKeiSkbtCd == null) {
			return null;
		}
		
		
		if(JKKModelConst.OYA_KEI_SKBT_CD_SVC_KEI.equals(oyaKeiSkbtCd) || JKKModelConst.OYA_KEI_SKBT_CD_SVC_KEI_UCWK.equals(oyaKeiSkbtCd)) {
			
			String svcKeiNo = kktkSvcKei.getString(KK0341ETMsg.SVC_KEI_NO);
			
			// 最終更新年月日候補レコードの取得
			return  new JKKejbExclusiveProcKK2111().getLastUpdDtmSvcKeiNo(inMsg, svcKeiNo);
		} 
		else {
		
			// 最終更新年月日候補レコードの取得
			HashMap<String, ArrayList<String>> retMap = execSQLForSelectKaisenUcwkNo(inMsg, key , kkop_svc_cd);

			// 取得結果から更新年月日時分秒のリストを取り出す
			ArrayList<String>updArray = retMap.get(SET_UPD_DTM);
	
			// データが取得できなかった場合はnullを返却する
			if(updArray.size() < 1)
			{
				return null;
			}

			// 最終更新年月日時分秒を取得する
			String maxUpdDtm = new JKKejbExclusiveProcCommon().getLastUpdDtm(updArray);

			return maxUpdDtm;
		}
	}

	/**
	 * サービス契約回線内訳番号に紐付く
	 * 各ルートから導き出される親契約のロックとデータの取得を行います。
	 * @param inMsg バインド変数に設定するための情報を保持しているメッセージ
	 * @param key サービス契約回線内訳番号
	 * @return 実行結果を保持したリスト
	 * 			┣サービス契約番号
	 * 			┗更新年月日時分秒
	 */
	private HashMap<String, ArrayList<String>> execSQLForLockKaisenUcwkNo(CAANMsg inMsg, String key ,String kkop_svc_cd)
	{
		// データベースアクセス機能インスタンスを生成
		JSYejbDBAccess jsydba = new JSYejbDBAccess(KK0251ETMsg.getTableName());

		try
		{
			// 初期化処理を行う
			jsydba.initialize();

			// プリコンパイルするSQL文を設定（レコードロック、データ取得用SQL文）
			jsydba.prepareStatement(new JKKejbExclusiveProcCommon().creSQLForLock(creSQLKaisenUcwkNo()));

			// バインド変数リストの取得
			ArrayList<String> strBind = creBindKaisenUcwkNo(inMsg, key , kkop_svc_cd);

			// パラメータの設定
			for (int i = 0; i < strBind.size(); i++)
			{
				jsydba.setParam(strBind.get(i));
			}

			// PreparedStatementオブジェクトのSQLクエリを実行
			jsydba.executeQuery();

			// 結果設定用ArrayList
			ArrayList<String> setKey = new ArrayList<String>();
			ArrayList<String> setUpd = new ArrayList<String>();

			// 取得結果をメッセージキャリアに格納
			while (jsydba.next())
			{
				// ArrayListに取得結果を設定
				StringBuffer primary = new StringBuffer();
				primary.append(jsydba.getString(SVC_KEI_NO));
				
				setKey.add(primary.toString());
				setUpd.add(jsydba.getString(UPD_DTM));
			}

			// 返却用HashMap
			HashMap<String, ArrayList<String>> retMap = new HashMap<String, ArrayList<String>>();

			// 設定したArrayListをHashMapに格納
			retMap.put(SET_PRIMARY, setKey);
			retMap.put(SET_UPD_DTM, setUpd);

			return retMap;
		}
		catch(SQLException se)
		{
			throw new CAANRuntimeException(se);
		}
		finally
		{
			// リソースの開放処理を行う
			jsydba.terminal();
		}
	}

	/**
	 * サービス契約回線内訳番号に紐付く
	 * 各ルートから導き出される親契約のデータの取得を行います。
	 * @param inMsg バインド変数に設定するための情報を保持しているメッセージ
	 * @param key サービス契約回線内訳番号
	 * @return 実行結果を保持したリスト
	 * 			┣サービス契約番号
	 * 			┗更新年月日時分秒
	 */
	private HashMap<String, ArrayList<String>> execSQLForSelectKaisenUcwkNo(CAANMsg inMsg, String key , String kkop_svc_cd)
	{
		// データベースアクセス機能インスタンスを生成
		JSYejbDBAccess jsydba = new JSYejbDBAccess(KK0251ETMsg.getTableName());

		try
		{
			// 初期化処理を行う
			jsydba.initialize();

			// プリコンパイルするSQL文を設定（データ取得用SQL文）
			jsydba.prepareStatement(creSQLKaisenUcwkNo());

			// バインド変数リストの取得
			ArrayList<String> strBind = creBindKaisenUcwkNo(inMsg, key , kkop_svc_cd);

			// パラメータの設定
			for (int i = 0; i < strBind.size(); i++)
			{
				jsydba.setParam(strBind.get(i));
			}

			// PreparedStatementオブジェクトのSQLクエリを実行
			jsydba.executeQuery();

			// 結果設定用ArrayList
			ArrayList<String> setKey = new ArrayList<String>();
			ArrayList<String> setUpd = new ArrayList<String>();

			// 取得結果をメッセージキャリアに格納
			while (jsydba.next())
			{
				// ArrayListに取得結果を設定
				StringBuffer primary = new StringBuffer();
				primary.append(jsydba.getString(SVC_KEI_NO));
				
				setKey.add(primary.toString());
				setUpd.add(jsydba.getString(UPD_DTM));
			}

			// 返却用HashMap
			HashMap<String, ArrayList<String>> retMap = new HashMap<String, ArrayList<String>>();

			// 設定したArrayListをHashMapに格納
			retMap.put(SET_PRIMARY, setKey);
			retMap.put(SET_UPD_DTM, setUpd);

			return retMap;
		}
		catch(SQLException se)
		{
			throw new CAANRuntimeException(se);
		}
		finally
		{
			// リソースの開放処理を行う
			jsydba.terminal();
		}
	}

	/**
	 * サービス契約回線内訳番号に紐付く、各ルートから親契約を取得するためのSQL文を作成します。
	 * @return データ取得用のSQL文。
	 */
	private String creSQLKaisenUcwkNo()
	{
		StringBuffer buff = new StringBuffer();

		buff.append(" SELECT ");
		buff.append("  KK2111.SVC_KEI_NO, ");
		buff.append("  KK2111.LAST_UPD_DTM AS UPD_DTM ");
		buff.append(" FROM ");
		buff.append("  KK_T_SVKEI_EXC_CTRL KK2111 ");
		buff.append("  INNER JOIN KK_T_KAISEN_TG_SVKEI KK0241 ");
		buff.append("  ON KK0241.SVC_KEI_NO = KK2111.SVC_KEI_NO ");
		buff.append("  INNER JOIN KK_T_SVKEI_KAISEN_UW KK0251 ");
		buff.append("  ON KK0251.SVC_KEI_KAISEN_UCWK_NO = KK0241.SVC_KEI_KAISEN_UCWK_NO ");
		buff.append("  INNER JOIN KK_T_SVC_KEI KK0081 ");
		buff.append("  ON KK0241.SVC_KEI_NO = KK0081.SVC_KEI_NO ");
		buff.append(" WHERE  KK0251.SVC_KEI_KAISEN_UCWK_NO = ? ");
		buff.append(" AND    (KK0251.SVC_KEI_KAISEN_UCWK_NO, KK0251.GENE_ADD_DTM) =   ");
		buff.append("        (SELECT KK0251_GENE.SVC_KEI_KAISEN_UCWK_NO, MAX(KK0251_GENE.GENE_ADD_DTM) AS KK0251_MAX ");
		buff.append("        FROM   KK_T_SVKEI_KAISEN_UW KK0251_GENE ");
		buff.append("        WHERE  KK0251_GENE.SVC_KEI_KAISEN_UCWK_NO = KK0251.SVC_KEI_KAISEN_UCWK_NO ");
		buff.append("        AND    KK0251_GENE.MK_FLG = '0' ");
		buff.append("        GROUP BY KK0251_GENE.SVC_KEI_KAISEN_UCWK_NO) ");
		buff.append(" AND    (KK0081.SVC_KEI_NO, KK0081.RSV_APLY_YMD || KK0081.GENE_ADD_DTM) =   ");
		buff.append("        (SELECT KK0081_GENE.SVC_KEI_NO, MAX(KK0081_GENE.RSV_APLY_YMD || KK0081_GENE.GENE_ADD_DTM) AS KK0081_MAX ");
		buff.append("        FROM   KK_T_SVC_KEI KK0081_GENE ");
		buff.append("        WHERE  KK0081_GENE.SVC_KEI_NO = KK0081.SVC_KEI_NO ");
		buff.append("        AND  KK0081_GENE.RSV_APLY_YMD <= ? ");
		buff.append("        AND  KK0081_GENE.RSV_APLY_CD = '2' ");
		buff.append("        AND  KK0081_GENE.MK_FLG = '0' ");
		buff.append("        GROUP BY KK0081_GENE.SVC_KEI_NO) ");
		buff.append(" AND    KK0081.SVC_CD = ? ");
		buff.append(" AND    KK0241.MK_FLG = '0' ");
		
		return buff.toString();
	}

	/**
	 * サービス契約回線内訳番号指定時のSQL文に設定するためのバインド変数リストの作成を行います。
	 * @param inMsg バインド変数に設定するための情報を保持しているメッセージ
	 * @param key サービス契約回線内訳番号
	 * @return SQLに設定するためのバインド変数のリスト。
	 */
	private ArrayList<String> creBindKaisenUcwkNo(CAANMsg inMsg, String key , String kkop_svc_cd)
	{
		ArrayList<String> retList = new ArrayList<String>();

		String svc_cd = "";

		if(JKKModelConst.KKOP_SVC_CD_ROUTER.equals(kkop_svc_cd)) {
			svc_cd = JKKModelConst.SVC_CD_NET;			
		} else if(JKKModelConst.KKOP_SVC_CD_VA_ADPT.equals(kkop_svc_cd)){
			svc_cd = JKKModelConst.SVC_CD_TEL;			
		}
		// バインド変数の設定
		retList.add(key);
		retList.add(JKKModelCommon.getOpeDate(inMsg));
		retList.add(svc_cd);

		return retList;
	}

}