/*
このファイルの中身は、NTT オープンソースライセンス　バージョン 1.0（「本
契約」という）の適用を受けます。
本契約を遵守しない限り、このファイルを使用してはなりません。
本契約のコピーは、次のＵＲＬから入手できます。
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

本契約に基づき頒布されるソフトウェアは、現状のまま、明示又は黙示のあらゆ
る種類の保証なしで、頒布されます。本契約に基づく権利及び制限を律する特定
の文言については、本契約を参照してください。

「オリジナルコード」は、 NTT Cyber Space Laboratories Code です。 
「オリジナルコード」の「初期開発者」は、日本電信電話株式会社です。  
日本電信電話株式会社により創作された部分は、Copyright (C) 2004 
日本電信電話株式会社 です。
全ての権利が留保されます。 
「コントリビュータ」：_____________________________________ 


The contents of this file are subject to the NTT Opensource License
Version 1.0 (the License); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

Software distributed under the License is distributed on an AS IS
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.

The Original Code is NTT Cyber Space Laboratories Code .

The Initial Developer of the Original Code is NIPPON TELEGRAPH AND 
TELEPHONE CORPORATION.
Portions created by the NIPPON TELEGRAPH AND TELEPHONE CORPORATION 
are Copyright (C) 2004 NIPPON TELEGRAPH AND TELEPHONE CORPORATION. 
All Rights Reserved.

Contributor(s) ______________________________________.
*/

//
//	Assignments 管理XMO データアクセスクラス
//			変更履歴
//				2004.01.08	新規作成	二條智文
//

package jp.co.ntt.lms.xmo.Assignments;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;

import org.apache.commons.lang.StringEscapeUtils;

import jp.co.ntt.lms.lo.LOException;
import jp.co.ntt.lms.lo.scorm.ScormAttemptDataAccess;
import jp.co.ntt.lms.lo.scorm.ScormObjectiveDataAccess;
import jp.co.ntt.lms.otm.OTMAssignInfo;
import jp.co.ntt.lms.xmo.DataAccess;
import jp.co.ntt.lms.xmo.Environment;
import jp.co.ntt.lms.xmo.MessageData;
import jp.co.ntt.lms.xmo.XMOException;
import jp.co.ntt.lms.xmo.GroupAndPeople.GroupAndPeopleClient;
import jp.co.ntt.lms.xmo.GroupAndPeople.GroupAndPeopleTable;
import jp.co.ntt.lms.xmo.Message.Message;
import jp.co.ntt.lms.xmo.util.ChangeEncode;
import jp.co.ntt.lms.xmo.util.DebugLog;
import jp.co.ntt.lms.xmo.util.XMODate;
import jp.co.ntt.lms.xms.framework.XmsException;
import jp.co.ntt.lms.xms.framework.XmsSystemException;

/**
 * Assignments 管理XMO データアクセスクラスです。<BR>
 * このクラスはAssignmentsテーブルへの登録、修正、削除、検索処理を実行します。<BR>
 * DataAccessクラスを継承し、登録、修正、削除、検索処理単位で
 * トランザクション管理を行います。
 * @author T.Nijou
 * @version 0.0.0.1 2004/01/08
 */
public class AssignmentsDataAccess
	implements AssignmentsMessage, AssignmentsTable
{

	/** データアクセスクラス内部で使うキー */
	private static final String ASSIGN_USERID = "assing_userid";

	/**
	 * コンストラクタです。<BR>
	 */
	public AssignmentsDataAccess() {
	}

	/**
	 * Assignmentsテーブルへ登録処理を行います。<BR>
	 * 以下の情報をHashtableに格納して渡してください。<BR>
	 * なおテーブルの主キー以外を省略した場合は省略したフィールドには
	 * Null値が格納されます。
	 * <PRE>
	 *			   key					   説明
	 *			---------------------------------------------
	 *			   MEMBER_SHIP_ID		   人々ID
	 *			   MATERIAL_ID			   コンポーネントID
	 *			   STUDY_START_DATE 	   開始日
	 *			   END_DATE 			   終了日
	 *			   ASSIGNER 			   アサイン者
	 *			   LEARN_AUTHORITY		   学習権限
	 *			   MANAGEMENT_AUTHORITY    管理権限
	 *			---------------------------------------------
	 * </PRE>
	 * @param htData 登録情報
	 * @return AssignmentsData 結果(正しく終了した場合のみ)
	 * @exception XMOException データベースエラーが発生した場合
	 */
	public synchronized AssignmentsData insert( Hashtable htData )
		throws XMOException
	{

		// アサイン状況を格納するためのデータオブジェクトを生成。
		AssignmentsData objData =  new AssignmentsData();

		// Assignmentsデータがnullのとき
		if( htData == null ) {
			DebugLog.write( this.getClass(), new Exception(), DebugLog.HIGHT );	
			// パラメータエラーをスローする
			throw new XMOException( getMessageData( PARAM_WAR ) );
		}

		// データアクセスクラスをインスタンス化します
		DataAccess objDataAccess = new DataAccess(TABLE_NAME);
		try {
			// トランザクションを開始する
			objDataAccess.trans( htData );

			// 存在チェックを行います
			if( isExitAssign( htData, objDataAccess ) ) {
				// すでに存在しているエラーを返します
				throw new XMOException( getMessageData( ALREADY_ASSING_WAR ) );
			}

			// インサート処理実行メソッドを呼びます
			objData = insertAction( htData, objDataAccess, objData );

			// コミット処理
			objDataAccess.commit();
		}
		catch( XMOException xe ) {
			DebugLog.write( this.getClass(), xe, DebugLog.HIGHT );
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			throw xe;
		}
		catch( SQLException e ) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			// データベースエラーを設定
			throw new XMOException( getMessageData( DB_ERR ) );
		}

		return objData;
	}

	/**
	 * 登録処理実行メソッドです。<BR>
	 * 自分のテーブルに登録処理を行った後、グループと人管理XMO
	 * から子グループを取得し、存在したら、子グループにも同様の
	 * 登録処理を行います。
	 * パラメータのチェックおよびトランザクションの管理は
	 * 上位メソッド内で行ってください。<BR>
	 * @param htbParam 登録情報
	 * @exception XMOException XMO独自エラー
	 * @exception SQLException DBエラーが発生した場合
	 */
	private AssignmentsData insertAction( Hashtable htbParam, DataAccess objDataAccess, AssignmentsData objData )
		throws XMOException, SQLException
	{

		// 登録処理用のデータをセットします
		Hashtable htbData = setData( htbParam );

		// 存在チェックを行いすでに登録されている場合は
		// 何もせずに子の登録に行きます。
		String strAssignID = "";
		if( !isExitAssign( htbData, objDataAccess ) ) {
			// 最大のAssignID取得
			strAssignID = getMaxAssignID(objDataAccess);
			// AssignIDを登録情報にセットします
			htbData.put( ASSIGN_ID, strAssignID );

			// アサイン対象ユーザIDを取得する
			String strAssignUserID = (String)htbParam.get( ASSIGN_USERID );
			if( strAssignUserID != null ) {
				objData.addAssignUser( strAssignUserID );
			}

			// 登録SQLを取得します
			String strSQL = objDataAccess.getInsertSQL( htbData );

			// 登録処理実行
			objDataAccess.execute( strSQL );
		}

		//処理モードを取得します
		String strMode = (String)htbParam.get( MODE_KEY );

		// 処理モードがONの場合は以下の処理は行わない
		// グループと人管理XMOを使用して、子グループおよび人が存在するか検索を行い
		// 存在する場合は同様の登録処理を行います
		if( strMode == null || !strMode.equals("on") ) {
			insertChild( htbData, objDataAccess, objData );
		}

		// 登録したアサインIDを設定して返します
		objData.setAssignID( strAssignID );

		return objData;
	}

	/**
	 * グループと人管理XMOから指定されたメンバーシップIDの子リストを取得し
	 * 存在する場合は子に対して、Assignmentを登録します
	 * @param htbData パラメータ
	 * @exception XMOException XMO独自エラー
	 * @exception SQLException DBエラーが発生した場合
	 */
	private void insertChild( Hashtable htbData, DataAccess objDataAccess, AssignmentsData objData )
		throws XMOException, SQLException
	{
		try {
			// グループと人管理XMOのクライアントをインスタンス化します
			GroupAndPeopleClient objGroupAndPeople = new GroupAndPeopleClient();

			// メンバーシップIDを取得します
			String strMemberShipID = (String)htbData.get( MEMBER_SHIP_ID );

			// グループと人管理XMOクライアントにメンバーシップIDを設定して
			// 検索処理を行います
			objGroupAndPeople.setWhereMemberShipID( strMemberShipID );
			// 現在使用中のコネクションインデックスを設定します
			objGroupAndPeople.setConnectionIndex( objDataAccess.getConnectionIndex() );

			if( !objGroupAndPeople.selectDatabase() ) {
				// 検索に失敗した場合は検索エラーを返します
				throw new XMOException( objGroupAndPeople.getMessageData() );
			}

			// 検索結果数分ループして、insert処理を呼び出します
			if( objGroupAndPeople.next() ) {
				// メンバーシップIDより見つかったレコードの子IDをキーにして、子リストを取得する
				String strParentID = objGroupAndPeople.getChildID();
				// パラメータクリア
				objGroupAndPeople.clear();
				// 現在使用中のコネクションインデックスを指定します
				objGroupAndPeople.setConnectionIndex( objDataAccess.getConnectionIndex() );
				// 親IDを設定
				objGroupAndPeople.setWhereParentID( strParentID );

				// 子リスト検索
				if( !objGroupAndPeople.selectDatabase() ) {
					// 検索に失敗した場合は検索エラーを返します
					throw new XMOException( objGroupAndPeople.getMessageData() );
				}

				// 子リスト分ループして親グループと同じLOを割り当てます。
				while( objGroupAndPeople.next() ) {

					// 子のメンバーシップIDを設定します
					Hashtable htbChildParam = setData( htbData );
					htbChildParam.put( MEMBER_SHIP_ID, objGroupAndPeople.getMemberShipID() );
					// 子IDがユーザの場合、ユーザアサイン情報にユーザIDを追加
					if( !objGroupAndPeople.isGroup() ) {
						htbChildParam.put( ASSIGN_USERID, objGroupAndPeople.getChildID() );
					}
					// アサインのインサート処理の再帰呼び出しを行います
					insertAction( htbChildParam, objDataAccess, objData );
				}
			}
		}
		catch( Exception e ) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// データベースエラーを設定
			throw new XMOException( getMessageData( DB_ERR ) );
		}
	}

	/**
	 * Assignmentsテーブルへ更新処理を行います。<BR>
	 * 以下の情報をHashtableに格納して渡してください。<BR>
	 * 省略したフィールドは更新されません。
	 * <PRE>
	 *			   key					   説明
	 *			---------------------------------------------
	 *			   MEMBER_SHIP_ID		   人々ID
	 *			   MATERIAL_ID			   コンポーネントID
	 *			   STUDY_START_DATE 	   開始日
	 *			   END_DATE 			   終了日
	 *			   ASSIGNER 			   アサイン者
	 *			   LEARN_AUTHORITY		   学習権限
	 *			   MANAGEMENT_AUTHORITY    管理権限
	 *			---------------------------------------------
	 *			   CONDITION_KEY		   更新条件文
	 *			---------------------------------------------
	 * </PRE>
	 * @param htData 更新情報
	 * @return String 結果(正しく終了した場合のみ)
	 * @exception XMOException データベースエラーが発生した場合
	 */
	public synchronized String update( Hashtable htData )
		throws XMOException
	{
		// LOデータがnullのとき
		if( htData == null ) {
			DebugLog.write( this.getClass(), new Exception(), DebugLog.HIGHT );	
			// パラメータエラーをスローする
			throw new XMOException( getMessageData( PARAM_WAR ) );
		}

		// データアクセスクラスをインスタンス化します
		DataAccess objDataAccess = new DataAccess(TABLE_NAME);
		try {

			// トランザクションを開始する
			objDataAccess.trans( htData );

			// 更新処理実行メソッドを実行します
			updateAction( htData, objDataAccess );

			// コミット処理
			objDataAccess.commit();
		}
		catch( XMOException xe ) {
			DebugLog.write( this.getClass(), xe, DebugLog.HIGHT );
			// ロールバック
			try { objDataAccess.rollback(); }
			catch( Exception ex ) {}
			throw xe;
		}
		catch( SQLException e ) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			// データベースエラーを設定
			throw new XMOException( getMessageData( DB_ERR ) );
		}

		// 正常時空文字返却
		return "";
	}

	/**
	 * 更新処理実行メソッドです。<BR>
	 * パラメータのチェックおよびトランザクションの管理は
	 * 上位メソッド内で行ってください。<BR>
	 * @param htbParam 更新情報
	 * @exception XMOException XMO独自エラー
	 * @exception SQLException DBエラーが発生した場合
	 */
	private void updateAction( Hashtable htbParam, DataAccess objDataAccess )
		throws XMOException, SQLException
	{

		// 更新処理用のデータをセットします
		Hashtable htbData = setData( htbParam );

		String strSQL = objDataAccess.getUpdateSQL(htbData);

		// 条件文の取得
		String strCondition = (String)htbParam.get( CONDITION_KEY );
		if( strCondition != null ) {
			strSQL += strCondition;
		}

		// 更新処理を実行
		objDataAccess.execute( strSQL );

	}

	/**
	 * Assignmentsテーブルへ削除処理を行います。<BR>
	 * 以下の情報をHashtableに格納して渡してください。
	 * <PRE>
	 *			   key					   説明
	 *			---------------------------------------------
	 *			   CONDITION_KEY		   削除条件文
	 *			---------------------------------------------
	 * </PRE>
	 * @param htData 削除情報
	 * @return String 結果(正しく終了した場合のみ)
	 * @exception XMOException データベースエラーが発生した場合
	 */
	public synchronized String delete( Hashtable htData )
		throws XMOException
	{
		// データアクセスクラスをインスタンス化します
		DataAccess objDataAccess = new DataAccess(TABLE_NAME);
		try {

			// トランザクションを開始する
			objDataAccess.trans( htData );

			// 削除処理実行メソッドを実行します
			deleteAction( htData, objDataAccess );

			// コミット処理
			objDataAccess.commit();
		}
		catch( XMOException xe ) {
			DebugLog.write( this.getClass(), xe, DebugLog.HIGHT );
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			throw xe;
		}
		catch( SQLException e ) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			// データベースエラーを設定
			throw new XMOException( getMessageData( DB_ERR ) );
		}
		return "";
	}

	/**
	 * 削除処理実行メソッドです。<BR>
	 * パラメータのチェックおよびトランザクションの管理は
	 * 上位メソッド内で行ってください。<BR>
	 * @param htbParam 削除情報
	 * @exception XMOException XMO独自エラー
	 * @exception SQLException DBエラーが発生した場合
	 */
	private void deleteAction( Hashtable htbParam, DataAccess objDataAccess )
		throws XMOException, SQLException
	{
		// SQLの組み立て
		StringBuffer sbSQL = new StringBuffer();
		sbSQL.append( "DELETE FROM " + TABLE_NAME );

		// 条件文の取得
		String strCondition = (String)htbParam.get( CONDITION_KEY );
		if( strCondition != null ) {
			sbSQL.append( strCondition );
		}

		// 削除処理を実行
		objDataAccess.execute( sbSQL.toString() );
	}


	/**
	 * Assignmentsテーブルへ検索処理を行います。<BR>
	 * 以下の情報をHashtableに格納して渡してください。
	 * <PRE>
	 *			   key					   説明
	 *			---------------------------------------------
	 *			   CONDITION_KEY		   検索条件文
	 *			---------------------------------------------
	 * </PRE>
	 * @param htData 検索情報
	 * @return String 結果(正しく終了した場合のみ)
	 * @exception XMOException データベースエラーが発生した場合
	 */
	public Vector select( Hashtable htData )
		throws XMOException
	{
		// Assignmentsデータがnullのとき
		if( htData == null ) {
			DebugLog.write( this.getClass(), new Exception(), DebugLog.HIGHT );	
			throw new XMOException( getMessageData( PARAM_WAR ) );
		}

		// 戻り値
		Vector vecReturn = new Vector();

		// データアクセスクラスをインスタンス化します
		DataAccess objDataAccess = new DataAccess(TABLE_NAME);
		try {
			// トランザクションを開始する
			objDataAccess.trans( htData );

			// 検索処理実行メソッド
			vecReturn = selectAction( htData, objDataAccess );

			// コミット
			objDataAccess.commit();
		}
		catch( XMOException xe ) {
			DebugLog.write( this.getClass(), xe, DebugLog.HIGHT );
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			throw xe;
		}
		catch( SQLException e ) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			// データベースエラーを設定
			throw new XMOException( getMessageData( DB_ERR ) );
		}
		return vecReturn;
	}

	/**
	 * 検索処理実行メソッドです。<BR>
	 * パラメータのチェックおよびトランザクションの管理は
	 * 上位メソッド内で行ってください。<BR>
	 * @param htbParam 検索情報
	 * @return Vector 検索結果
	 * @exception XMOException XMO独自エラー
	 * @exception SQLException DBエラーが発生した場合
	 */
	private Vector selectAction( Hashtable htbParam, DataAccess objDataAccess )
		throws XMOException, SQLException
	{

		// SQLの組み立て
		StringBuffer sbSQL = new StringBuffer();
		sbSQL.append( "SELECT * FROM " + TABLE_NAME );

		// 条件文の取得
		String strCondition = (String)htbParam.get( "condition_key" );
		if( strCondition != null ) {
			sbSQL.append( strCondition );
		}
		// 順序の取得
		String strOrderBy = (String)htbParam.get( "order_by" );
		if( strOrderBy != null ) {
			sbSQL.append( strOrderBy );
		}

		// クエリーを実行します
		ResultSet rs = objDataAccess.executeQuery(sbSQL.toString());

		Vector vecReturn = new Vector();
		while(rs.next()) {
			// 各フィールドの値を取得します
			String strAssignID = ChangeEncode.setChar( rs.getString( ASSIGN_ID ) );
			String strMemberShipID = ChangeEncode.setChar( rs.getString( MEMBER_SHIP_ID ) );
			String strMaterialID = ChangeEncode.setChar( rs.getString( MATERIAL_ID ) );
			String strStudyStartDate = XMODate.parseTime( rs.getTimestamp( STUDY_START_DATE ) );
			String strEndDate = XMODate.parseTime( rs.getTimestamp( END_DATE ) );
			String strAssigner = ChangeEncode.setChar( rs.getString( ASSIGNER ) );
			String strLearnAuthority = ChangeEncode.setChar( rs.getString( LEARN_AUTHORITY ) );
			String strManagementAuthority = ChangeEncode.setChar( rs.getString( MANAGEMENT_AUTHORITY ) );
// リザルトセットから新規追加したカラムデータを取得。
			// 学習開始日時
			Date openingDate = null;
			openingDate = rs.getTimestamp(OPENING_DATE);
			// 学習終了日時
			Date closingDate = null;
			closingDate = rs.getTimestamp(CLOSING_DATE);
			// 学習回数
			String studyCount =null;
			studyCount = rs.getString(STUDY_COUNT);
			// 学習制限回数
			String studyLimitCount =null;
			studyLimitCount = rs.getString(STUDY_LIMIT_COUNT);
			// メソッドフラグ情報
			String methodFlag = null;
			methodFlag = rs.getString(METHOD_FLAG);
			
			// AssignmentsDataクラスのインスタンス化
			AssignmentsData objData = new AssignmentsData();
			// 各フィールド値をセットします
			objData.setAssignID( strAssignID );
			objData.setMemberShipID( strMemberShipID );
			objData.setMaterialID( strMaterialID );
			objData.setStudyStartDate( strStudyStartDate );
			objData.setEndDate( strEndDate );
			objData.setAssigner( strAssigner );
			objData.setLearnAuthority( strLearnAuthority );
			objData.setManagementAuthority( strManagementAuthority );
			objData.setMethodFlag(methodFlag);
			
			// 新規カラムデータをデータクラスに設定
			// 学習開始日時
			objData.setOpeningDate( openingDate );
			// 学習終了日時
			objData.setClosingDate( closingDate );
			// 学習回数
			objData.setStudyCount( studyCount );
			// 学習制限回数
			objData.setStudyLimitCount( studyLimitCount );
			// 返却ベクターにAssignmentsDataクラスを追加します
			vecReturn.add( objData );
		}

		return vecReturn;

	}

	/**
	 * 最大のAssignID取得
	 * @return String 最大AssignID
	 */
	private String getMaxAssignID( DataAccess objDataAccess )
		throws SQLException
	{
		String strSQL="";

		try{
			//XMS.iniファイルロードクラスのインスタンス
			Environment objEnv=new Environment();
			//Oracleの場合
			if(objEnv.getDBType().equals( objEnv.DB_SQLSERVER )){
				 strSQL = "select MAX(CONVERT(INT,assignID)) + 1 as maxassignid from Assignments";
			//SQLServerの場合
			}else if(objEnv.getDBType().equals( objEnv.DB_ORACLE )){
				 strSQL = "select MAX(TO_NUMBER(assignID)) + 1 as maxassignid from Assignments";
			//PostgreSQLの場合
			}else if(objEnv.getDBType().equals( objEnv.DB_POSTGRE )){
				 strSQL = "select MAX(TO_NUMBER((assignID),'9999999999')) + 1 as maxassignid from Assignments";
			}
		}
		catch(Exception ex)
		{

		}

		String strMaxAssignID = "";
		DebugLog.write( this.getClass(), strSQL, DebugLog.ROW );
		ResultSet rs = objDataAccess.executeQuery(strSQL);
		while(rs.next()) {
			int intTemp = 0;
			intTemp = rs.getInt( "maxassignid" );
			strMaxAssignID = new Integer(intTemp).toString();
		}

		return strMaxAssignID;
	}

	/**
	 * 割当の存在チェックを行います
	 * @param htbParam パラメータ
	 * @param objDataAccess DBアクセスクラス
	 * @return boolean true: 割り当てられている false: 割り当てられていない
	 * @exception SQLException DBエラー
	 */
	private boolean isExitAssign( Hashtable htbParam, DataAccess objDataAccess )
		throws SQLException
	{
		// 人々IDの取得
		String strMemberShipID = (String)htbParam.get( MEMBER_SHIP_ID );
		// コンポーネントIDの取得
		String strMaterialID = (String)htbParam.get( MATERIAL_ID );

		// 条件文の組み立て
		String strCondition = " WHERE " + MEMBER_SHIP_ID + "='" + StringEscapeUtils.escapeSql(strMemberShipID) + "' AND " + MATERIAL_ID + "='" + StringEscapeUtils.escapeSql(strMaterialID) + "'";

		return objDataAccess.isExit( strCondition, TABLE_NAME );
	}

	/**
	 * 登録、更新処理時のデータを組み立てます
	 * @param htData
	 * @return Hashtable
	 */
	private Hashtable setData( Hashtable htbParam ) {

		Hashtable htbData = new Hashtable();
		putData( htbData, htbParam, MEMBER_SHIP_ID );
		putData( htbData, htbParam, MATERIAL_ID );
		putData( htbData, htbParam, STUDY_START_DATE );
		putData( htbData, htbParam, END_DATE );
		putData( htbData, htbParam, ASSIGNER );
		putData( htbData, htbParam, LEARN_AUTHORITY );
		putData( htbData, htbParam, MANAGEMENT_AUTHORITY );
// 登録するカラムの追加
		putData( htbData, htbParam, OPENING_DATE );
		putData( htbData, htbParam, CLOSING_DATE );
		putData( htbData, htbParam, STUDY_COUNT );
		putData( htbData, htbParam, STUDY_LIMIT_COUNT );
		//	ADD 2005/03/28 START Kentaro Ishizaki [メソッド管理追加]
		putData( htbData, htbParam, METHOD_FLAG );
		//	ADD 2005/03/28 END Kentaro Ishizaki [メソッド管理追加]
		return htbData;
	}

	/**
	 * 安全にHashtableに追加するメソッドです
	 */
	private void putData( Hashtable htbData,  Hashtable htbParam, String strKey ) {
		String strValue = (String)htbParam.get( strKey );
		if( strValue != null ) {
			htbData.put( strKey, strValue );
		}
	}

	/**
	 * メッセージオブジェクトを作成します
	 * @param strMessageID メッセージID
	 * @return MessageData メッセージオブジェクト 例外発生時はnullを返します
	 */
	private MessageData getMessageData( String strMessageID) {
		MessageData objMessage = null;
		try {
			objMessage = Message.getInstance().getMessageData( strMessageID, MSG_FIEL_PATH, MSG_FILE_NAME );
		}
		catch( Exception e ) {

		}
		return objMessage;
	}
	/**
	 * アサイン者の検索を行います
	 * @param strMaterialIDList MaterialIDリスト
	 * @param strUserID ユーザID
	 * @param intAssignType アサインタイプ
	 * @return String[] アサイン者リスト
	 * @exception SQLException DBエラー
	 */
	public String[] selectAssigner( String[] strMaterialIDList, String strUserID, int intAssignType )
		throws SQLException
	{

		DataAccess objDataAccess = new DataAccess();

		// 検索結果保持Vector
		Vector vecAssingerList = new Vector();
		try {
			// トランザクションの開始
			objDataAccess.trans();

			int intMaxCount = strMaterialIDList.length;
			int intCount = 0;

			while( intCount < intMaxCount ) {

				StringBuffer sbMaterialSQL = new StringBuffer();
				// 100件ずつ in 句にMateiralIDを設定する
				while( ( intCount + 1 ) % 100 != 0 &&
						intCount < intMaxCount )
				{
					sbMaterialSQL.append( "'" + StringEscapeUtils.escapeSql(strMaterialIDList[intCount]) + "'" );
					sbMaterialSQL.append( "," );
					intCount++;
				}

				// 最後の','を取り除く
				String strMaterialSQL = sbMaterialSQL.substring( 0, sbMaterialSQL.length() - 1 );

				// 権限の条件を作成する
				String strAuthSQL = "";
				if( intAssignType == LEARN_TYPE ) {
					strAuthSQL = TABLE_NAME + "." + LEARN_AUTHORITY + "='1'";
				}
				else if( intAssignType == MANAGE_TYPE ) {
					strAuthSQL = TABLE_NAME + "." + MANAGEMENT_AUTHORITY + "='1'";
				}
				else {
					strAuthSQL = TABLE_NAME + "." + LEARN_AUTHORITY + "='1' AND " + TABLE_NAME + "." + MANAGEMENT_AUTHORITY + "='1'";
				}

				// SQLの作成 Assignment INNER JOIN GroupAndPeople ON Assignments.memberShipID = GroupAndPeople.memberShipID
				StringBuffer sbSQL = new StringBuffer();
				sbSQL.append( "SELECT " + TABLE_NAME + "." + ASSIGNER + " as " + ASSIGNER );
				sbSQL.append( " FROM " + TABLE_NAME + " INNER JOIN " + GroupAndPeopleTable.TABLE_NAME + " ON " );
				sbSQL.append( TABLE_NAME + "." + MEMBER_SHIP_ID + "=" + GroupAndPeopleTable.TABLE_NAME + "." + GroupAndPeopleTable.MEMBER_SHIP_ID );
				sbSQL.append( " WHERE " + GroupAndPeopleTable.TABLE_NAME + "." + GroupAndPeopleTable.CHILD_ID + "='" + StringEscapeUtils.escapeSql(strUserID) + "' AND " );
				sbSQL.append( TABLE_NAME + "." + MATERIAL_ID + " IN (" + strMaterialSQL + ") AND " );
				sbSQL.append( strAuthSQL );

				// クエリーを実行します
				ResultSet rs = objDataAccess.executeQuery(sbSQL.toString());

				while(rs.next()) {
					String strAssignerID = ChangeEncode.setChar(rs.getString( ASSIGNER ));
					if( !vecAssingerList.contains( strAssignerID ) ) {
						vecAssingerList.add( strAssignerID );
					}
				}
			}

			// コミット
			objDataAccess.commit();
		}
		catch( SQLException se ) {
			try{ objDataAccess.rollback(); } catch( Exception ex ) {}
			throw se;
		}

		String[] strRes = new String[vecAssingerList.size()];
		vecAssingerList.copyInto( strRes );

		return strRes;

	}

	/**
	 * 指定されたユーザIDとLOIDのアサイン有効・無効判定を取得して返す。<BR>
	 * @param strUserID ユーザID
	 * @param strGroupID グループID（nullの場合は兼務すべてが対象)
	 * @param strMaterialID MaterialID
	 * @return AssignUsableList
	 */
	public AssignUsableList getAssignUsable(
		String strUserID,
		String strGroupID,
		String strMaterialID) 
		throws SQLException
	{

		DataAccess dataAccess = new DataAccess();

		// アサイン判定リストクラスのインスタンス化
		AssignUsableList list = new AssignUsableList();

		try {
			// トランザクション開始
			dataAccess.trans();
			
			StringBuffer sbSQL = new StringBuffer();
			
			// SQLの作成(グループIDがnullでないときはグループIDも条件に指定する)
			// SQLに見易さを優先して、コーディング規約とは異なった記述をしているので注意！
			sbSQL.append( "SELECT " );
			sbSQL.append( "    lorel.parentID AS lo_parent_id, " );
			sbSQL.append( "    lorel.childID AS lo_child_id,   " );
			sbSQL.append( "    grp.ParentID AS group_id,       " );
			sbSQL.append( "    ass.opening_date AS opening_date,  " );
			sbSQL.append( "    ass.closing_date AS closing_date,  " );
			sbSQL.append( "    ass.study_limit_cnt AS study_limit_cnt,  " );
			sbSQL.append( "    ass.study_cnt AS study_cnt, " );
			sbSQL.append( "    ass.learn_authority AS learn_authority, " );
			sbSQL.append( "    ass.management_authority AS management_authority " );
			sbSQL.append( "FROM " );
			sbSQL.append( "    Assignments ass  " );
			sbSQL.append( "    INNER JOIN " );
			sbSQL.append( "    GroupAndPeople grp ON  " );
			sbSQL.append( "    ass.memberShipID = grp.memberShipID  " );
			sbSQL.append( "    RIGHT OUTER JOIN " );
			sbSQL.append( "    LORelation lorel ON  " );
			sbSQL.append( "    ass.materialID = lorel.materialID " );
			sbSQL.append( "WHERE " );
			sbSQL.append( "    lorel.materialID = '" + StringEscapeUtils.escapeSql(strMaterialID) + "' AND  " );
			sbSQL.append( "    grp.childID = '" + StringEscapeUtils.escapeSql(strUserID) + "' " );
			if( strGroupID != null ) 
			sbSQL.append( "    AND grp.ParentID = '" + StringEscapeUtils.escapeSql(strGroupID) + "' " );

			DebugLog.write( this.getClass(), sbSQL.toString(), DebugLog.ROW );
			ResultSet rs = dataAccess.executeQuery(sbSQL.toString());
			
			// 結果セット分ループ（2回以上ループするのは兼務ユーザに同一アサインがある場合のみ）
			while( rs.next() ) {
				AssignUsable usable = new AssignUsable();
				
				// 実アサインLOの親ID
				String assingLoParentID = ChangeEncode.setChar(rs.getString("lo_parent_id"));
				// 実アサインLOの子ID
				String assignLoChildID = ChangeEncode.setChar(rs.getString("lo_child_id"));
				// グループID
				String groupID = ChangeEncode.setChar(rs.getString("group_id"));

				// 学習アサイン
				String learnAuthority = ChangeEncode.setChar( rs.getString( "learn_authority" ) );
				// 管理アサイン
				String managementAuthority = ChangeEncode.setChar( rs.getString( "management_authority" ) );

				// 期限開始日時（明示的にjava.util.Date にキャスト）
				java.util.Date opendingDate = (java.util.Date)rs.getTimestamp("opening_date");
				// 期限終了日時（明示的にjava.util.Date にキャスト）
				java.util.Date closingDate = (java.util.Date)rs.getTimestamp("closing_date");
				// 学習制限回数
				int studyLimitCnt = rs.getInt("study_limit_cnt");
				// 学習回数
				int studyCnt = rs.getInt("study_cnt");
				
				usable.setAssignLoParentID(assingLoParentID);
				usable.setAssignLoChildID(assignLoChildID);
				usable.setGroupID(groupID);
				usable.setOpeningDate(opendingDate);
				usable.setClosingDate(closingDate);
				usable.setStudyLimitCnt(studyLimitCnt);
				usable.setStudyCnt(studyCnt);

				usable.setLearnAuthority(learnAuthority);
				usable.setManagementAuthority(managementAuthority);

				// リストに追加
				list.add(usable);
			}
			
			// コミット
			dataAccess.commit();
			
		}
		catch(SQLException se ) {
			try {
				dataAccess.rollback();
			}
			catch(SQLException sse ) {}

			throw se;
		}
		return list;
	}


	/**
	/**
	 * 指定されたユーザIDとLOIDの直下のアサイン有効・無効判定を取得して返す。<BR>
	 * @param strMaterialID MaterialID
	 * @return AssignUsableList
	 * @param strUserID ユーザID
	 * @param strGroupID グループID（nullの場合は兼務すべてが対象)
	 * @param strLoID LOID
	 * @return List
	 */
	public List getUnderAssignUsable(
		String strUserID,
		String strGroupID,
		String strLoID) 
			throws SQLException 	
	{

		DataAccess dataAccess = new DataAccess();

		// アサイン判定リストクラスのインスタンス化
		ArrayList resultList = new ArrayList();

		try {
			// トランザクション開始
			dataAccess.trans();
			
			// SQLの作成(グループIDがnullでないときはグループIDも条件に指定する)
			// SQLに見易さを優先して、コーディング規約とは異なった記述をしているので注意！
			StringBuffer sbSQL = new StringBuffer();
			sbSQL.append("SELECT ");
			sbSQL.append("    lorel.parentID AS lo_parent_id, ");
			sbSQL.append("    lorel.childID AS lo_child_id, ");
			sbSQL.append("    gras.ParentID AS group_id, ");
			sbSQL.append("    gras.ChildID AS user_id, ");
			sbSQL.append("    gras.materialID AS materialID, ");
			sbSQL.append("    gras.opening_date AS opening_date, ");
			sbSQL.append("    gras.closing_date AS closing_date, ");
			sbSQL.append("    gras.study_limit_cnt AS study_limit_cnt, ");
			sbSQL.append("    gras.study_cnt AS study_cnt ");
			sbSQL.append("FROM ");
			sbSQL.append("    LORelation lorel ");
			sbSQL.append("LEFT OUTER JOIN ");
			sbSQL.append("   (SELECT    grp.ParentID, ");
			sbSQL.append("          grp.ChildID, ");
			sbSQL.append("          ass.materialID, ");
			sbSQL.append("          ass.opening_date, ");
			sbSQL.append("          ass.closing_date, ");
			sbSQL.append("          ass.study_limit_cnt, ");
			sbSQL.append("          ass.study_cnt ");
			sbSQL.append("    FROM    Assignments ass ");
			sbSQL.append("    INNER JOIN ");
			sbSQL.append("          GroupAndPeople grp  ");
			sbSQL.append("    ON      ass.memberShipID = grp.memberShipID ");
			sbSQL.append("    WHERE   grp.childID = '" + StringEscapeUtils.escapeSql(strUserID) + "' ");
			if( strGroupID != null )
			sbSQL.append( "   AND     grp.ParentID = '" + StringEscapeUtils.escapeSql(strGroupID) + "' " );
			sbSQL.append("    ) gras ");
			sbSQL.append("ON      gras.materialID = lorel.materialID ");
			sbSQL.append("WHERE   lorel.parentID = '" + StringEscapeUtils.escapeSql(strLoID) + "' ");
			DebugLog.write( this.getClass(), sbSQL.toString(), DebugLog.ROW );
			ResultSet rs = dataAccess.executeQuery(sbSQL.toString());
			
			// 作業用Mapオブジェクト
			HashMap work = new HashMap();
			
			// 結果セット分ループ（2回以上ループするのは兼務ユーザに同一アサインがある場合のみ）
			while( rs.next() ) {
				
				// アサイン有無(MaterialIDがNULLの時はアサインが存在しない)
				boolean assign = rs.getString("materialID") != null;
				// 実アサインLOの親ID
				String assingLoParentID = ChangeEncode.setChar(rs.getString("lo_parent_id"));
				// 実アサインLOの子ID
				String assignLoChildID = ChangeEncode.setChar(rs.getString("lo_child_id"));
				// グループID
				String groupID = ChangeEncode.setChar(rs.getString("group_id"));
				// 期限開始日時（明示的にjava.util.Date にキャスト）
				java.util.Date opendingDate = (java.util.Date)rs.getTimestamp("opening_date");
				// 期限終了日時（明示的にjava.util.Date にキャスト）
				java.util.Date closingDate = (java.util.Date)rs.getTimestamp("closing_date");
				// 学習制限回数
				int studyLimitCnt = rs.getInt("study_limit_cnt");
				// 学習回数
				int studyCnt = rs.getInt("study_cnt");

				// 作業用MapからLOIDをキーにして，アサイン判定オブジェクトリストを取り出す。
				AssignUsableList usableList = (AssignUsableList)work.get(assignLoChildID);
				if( usableList == null ) {
					// まだ作業用Mapに登録されていない場合は新規にインスタンス化
					usableList = new AssignUsableList();
					usableList.setLoID(assignLoChildID);
					usableList.setUserID(strUserID);
					
					// 作業用MapにLOIDをキーにして保存
					work.put(assignLoChildID, usableList);
					
					// 結果リストにも登録
					resultList.add( usableList );
				}
				
				if( assign ) {
					// アサインが存在する場合のみアサイン判定オブジェクトを作成してリストに加える。
					AssignUsable usable = new AssignUsable();
					
					usable.setLoID(assignLoChildID); // 実アサインとターゲットのLOは同一
					usable.setAssignLoParentID(assingLoParentID);
					usable.setAssignLoChildID(assignLoChildID);
					usable.setGroupID(groupID);
					usable.setOpeningDate(opendingDate);
					usable.setClosingDate(closingDate);
					usable.setStudyLimitCnt(studyLimitCnt);
					usable.setStudyCnt(studyCnt);
					
					// リストに追加
					usableList.add(usable);
				}
			}

			// コミット
			dataAccess.commit();
			
		}
		catch(SQLException se ) {
			try {
				dataAccess.rollback();
			}
			catch(SQLException sse ) {}
			throw se;
		}
		return resultList;

	}


   /**
	* 指定されたグループIDまたはユーザIDとLOIDのアサイン情報を取得して返却します。<BR>
	* @param inComponentList 	IN句としたコンポーネントID
	* @param inGroupList 		IN句としたグループID
	* @param strUserID 		ユーザID
	* 
	* @return resultList 		検索結果を格納したAssignUsableのリスト
	*/
	public List getAssignInfo(
		String inComponentList,
		String inGroupList,
		String strUserID) 
		throws XmsException {

		DataAccess dataAccess = new DataAccess();
		ResultSet rs = null;
		boolean exceptionFlag = false;

		// アサイン判定リストクラスのインスタンス化
		List resultList = new ArrayList();

		try {

			// チェック日時の取得
			Date checkDate = new Date();

			// トランザクション開始
			dataAccess.trans();

			// SQLの作成(グループIDがnullでないときはグループIDも条件に指定する)
			// SQLに見易さを優先して、コーディング規約とは異なった記述をしているので注意！
			StringBuffer sbSQL = new StringBuffer();
			sbSQL.append( "SELECT " );
			sbSQL.append( "    gp.ParentID AS GroupID, " );	// 所属グループID
			sbSQL.append( "    gp.ChildID AS UserID, " );	// ユーザID
			sbSQL.append( "    a.materialID AS CompornentID, " );	// コンポーネントID
			sbSQL.append( "    a.opening_date AS OpenPeriod, " );	// アサイン期間 開始日時
			sbSQL.append( "    a.closing_date AS ClosePeriod, " );	// アサイン期間 終了日時
			sbSQL.append( "    a.study_limit_cnt AS StudyLimitCount, " );	// 学習制限回数
			sbSQL.append( "    a.study_cnt AS StudyCount " );	// 学習回数
			sbSQL.append( "FROM " );
// Oracleではテーブル別名にasを使用しない。
			sbSQL.append( " GroupAndPeople gp" );
			sbSQL.append( " INNER JOIN" );
			sbSQL.append( " Assignments a ON" );
			sbSQL.append( "    gp.memberShipID = a.memberShipID " );
			sbSQL.append( "WHERE " );
			sbSQL.append( "    a.learn_authority = '1' " );	//学習権限ありのアサインのみ
			sbSQL.append( "    AND " );

			// グループ・ユーザ指定どちらでもIN句を条件とする
			sbSQL.append( "    gp.ParentID " + inGroupList );
			// ユーザ指定の場合
			if (strUserID != null) {			
				sbSQL.append( "    AND " );
				sbSQL.append( "    gp.ChildID = '" + StringEscapeUtils.escapeSql(strUserID) + "'");
			}
			sbSQL.append( "    AND " );						
			// コンポーネントID指定
			sbSQL.append( "    a.materialID " + inComponentList );

			rs = dataAccess.executeQuery(sbSQL.toString());

			// 結果セット分ループ
			while( rs.next() ) {
				
				// グループID
				String assingGroupID = ChangeEncode.setChar(rs.getString("GroupID"));
				// ユーザID
				String assignUserID = ChangeEncode.setChar(rs.getString("UserID"));
				// コンポーネントID
				String compornentID = ChangeEncode.setChar(rs.getString("CompornentID"));
				// 期限開始日時（明示的にjava.util.Date にキャスト）
				Date opendingDate = (Date)rs.getTimestamp("OpenPeriod");
				// 期限終了日時（明示的にjava.util.Date にキャスト）
				Date closingDate = (Date)rs.getTimestamp("ClosePeriod");
				// 学習制限回数
				int studyLimitCount = rs.getInt("StudyLimitCount");
				// 学習回数
				int studyCount = rs.getInt("StudyCount");


				// アサイン判定オブジェクトを作成してリストに加える。
				AssignUsable usable = new AssignUsable();
				// グループIDを設定
				usable.setGroupID(assingGroupID);
				// ユーザIDを設定
				usable.setUserID(assignUserID);
				// コンポーネントIDを設定
				usable.setComponentId(compornentID);
				// 期限開始日時
				usable.setOpeningDate(opendingDate);
				// 期限終了日時
				usable.setClosingDate(closingDate);
				// 学習制限回数
				usable.setStudyLimitCnt(studyLimitCount);
				// 学習回数
				usable.setStudyCnt(studyCount);
				// チェック日時を設定する
				usable.setCheckDate( checkDate );
				// リストに追加
				resultList.add(usable);
			}

			// コミット
			dataAccess.commit();
			
		} catch (Exception e) {
			throw new XmsSystemException(e);
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (Exception e) {
					if (exceptionFlag == true) {
						throw new XmsSystemException(e);
					}
				}
				rs = null;
			}
		}
		return resultList;

	}

	/**
	 * 指定したユーザIDとマテリアルIDの組み合わせの学習回数を１つ増加する。<br>
	 * 指定したユーザの「兼務」することにより、該当するレコードが複数ある場合、
	 * それらレコードすべてが増加対象となる。
	 * @param userID ユーザID。
	 * @param loID 対象の教材ID。
	 * @param loType 対象のＬＯ種別。
	 * @throws SQLException データベースエラーが発生した場合。
	 * @throws XMOException ＸＭＯ共通エラーが発生した場合。
	 * @throws Exception	その他エラーが発生した場合。
	 */
// マテリアルIDまたは教材IDでカウントアップできるように修正
// マテリアルIDを引数で受け取らない、またＬＯ種別を受け取るように修正。
	public void countupStudyCount(String userID, String loID, String loType)
			throws SQLException, XMOException, Exception {
		
		DataAccess dataAccess = null;
		boolean exceptionFlag = false;
		boolean transactionStartFlag = false;
		Environment environment = null;
		String dbType = null;

		StringBuffer stbWhere = null;
// ＬＯ種別がＷＢＴ、SmartForce、Perceptionの場合、独自IDからXMS2へのLOIDに変換が必要
// そのロジックに必要な変数

// 変数不要となった為、クエリ生成用StringBufferと変換後のLOIDStringを削除
		// クエリ実行後に取得するリザルトセット
		ResultSet resultSet =null;

		try {

// メソッド開始デバッグログを出力
			DebugLog.write( this.getClass()
				, "HEAD countupStudyCount("
					+ " \""+ userID + "\""
					+ ", \"" + loID + "\""
					+ ", \"" + loType + "\")"
				, DebugLog.ROW);

			exceptionFlag = true;
			transactionStartFlag = false;
// データベースによってユーザID, LOIDの変更をしなければならない為、
// データベースタイプ取得位置を変更
			//==================================================================
			// データベースタイプの種別
			environment = new Environment();		
			dbType = environment.getDBType();


			if ( userID == null || userID.length() == 0 ) {
				DebugLog.write( this.getClass(),
						"countupStudyCount():useID == null", DebugLog.HIGHT);
				throw new XMOException( "useID == null" );
			}
// マテリアルIDまたは教材IDでカウントアップできるように修正したため、
// 例外を発生させる条件を変更

// 引数は教材IDのみにしたので条件を変更
			// LOIDともにnullの場合エラー
			if ( loID == null || loID.length() == 0 ) {
				DebugLog.write( this.getClass(),
						"countupStudyCount():loID == null", DebugLog.HIGHT);
				throw new XMOException( "loID == null" );
			}			

// ＬＯ種別がＷＢＴの場合、独自IDからXMS2へのLOIDに変換していたが、
// LOIDが使用されるようになるので変換ロジックは必要でなくなる為、削除する。
			// =================================================================
			// コネクション取得・トランザクション開始
			dataAccess = new DataAccess();
			dataAccess.trans();
			transactionStartFlag = true;
			// =================================================================
			// 条件句の取得
			stbWhere = new StringBuffer();

// SQLデータベースでは、データ中の空白を除去した形で後方一致をしてくれるが、
// Oracleデータベースの場合、空白もデータとして扱っていることから後方一致が
// 正しく行われていない。
// このことから、Oracleの場合はmemberShipID中に指定IDの文字列が含まれている
// ものを検索するように修正した。

			// MS SQL Server の場合
			if ( dbType.equals( "0" ) == true ) {
// マテリアルIDまたは教材IDでカウントアップできるように修正

// LOIDだけでカウントアップするように再修正
// ユーザIDについてもも空白除去関数を呼ぶため、RDMSごとに記述するように挿入
				// ユーザID
				stbWhere.append( " AND rtrim(" + MEMBER_SHIP_ID + ")" );
				stbWhere.append( " like '%" + StringEscapeUtils.escapeSql(userID) + "'" );
				// 教材IDがわたった場合は後方一致。
				stbWhere.append( " AND rtrim(" + MATERIAL_ID + ")" );
				stbWhere.append( " like '%" + StringEscapeUtils.escapeSql(loID) + "'" );

			}
			// Oracle の場合 or PostgreSQL の場合
			else if ( dbType.equals( "1" ) == true || dbType.equals( "2" ) == true ) {

// LOIDだけでカウントアップするように再修正
// ユーザIDについてもも空白除去関数を呼ぶため、RDMSごとに記述するように挿入
				// ユーザID
				stbWhere.append( " AND trim(" + MEMBER_SHIP_ID + ")" );
				stbWhere.append( " like '%" + StringEscapeUtils.escapeSql(userID) + "'" );
				// 教材IDがわたった場合は後方一致。
				stbWhere.append( " AND trim(" + MATERIAL_ID + ")" );
				stbWhere.append( " like '%" + StringEscapeUtils.escapeSql(loID) + "'" );

			}

// データベースによってユーザID, LOIDの変更をしなければならない為、
// データベースタイプ取得位置を本処理中の前方へ移動
			//==================================================================
			// データベースタイプの種別
			// =================================================================
			// SQLの作成
			StringBuffer sbSQL = new StringBuffer();
			sbSQL.append( "update " + TABLE_NAME );
			sbSQL.append( " set " + STUDY_COUNT + "=" );
			// DBサーバーによってNULL値変換メソッドが異なるため、分岐

			//XMS.iniファイルロードクラスのインスタンス
			Environment objEnv=new Environment();

			// MS SQL Serverの場合
			if(objEnv.getDBType().equals( objEnv.DB_SQLSERVER )){
				sbSQL.append( "isnull(" + STUDY_COUNT + ",0) + 1" );
			// Oracleの場合
			} else if (objEnv.getDBType().equals( objEnv.DB_ORACLE)){
				sbSQL.append( "nvl(" + STUDY_COUNT + ",0) + 1" );
			// PostgreSQLの場合	
			} else if (objEnv.getDBType().equals( objEnv.DB_POSTGRE )){
				sbSQL.append( "COALESCE(" + STUDY_COUNT + ",0) + 1" );
			}

			// 条件句(先頭のANDを除去)
			sbSQL.append(" WHERE ");
			sbSQL.append(stbWhere.substring(4));

// トランザクション開始位置をより早い段階に実施
			DebugLog.write( this.getClass(), sbSQL.toString(), DebugLog.ROW );
			// =================================================================
			// ＳＱＬ発行
			DebugLog.write(this.getClass(), sbSQL, DebugLog.MID);
			dataAccess.execute(sbSQL.toString());
			// =================================================================
			// コミット
			dataAccess.commit();
			
			exceptionFlag = false;
		} finally {
// 結果セットのクローズ
			try {
				if ( resultSet != null ) {
					resultSet.close();
					resultSet = null;
				}
			} catch ( SQLException e ) {
				// すでに例外が発生していれば、その例外を優先し、
				// 発生していなければ、クローズの例外をスローする。
				if ( exceptionFlag == false ) {
					exceptionFlag = true;
					throw e;
				}
			} finally {
				// 例外が発生し、且つ、例外の発生がトランザクション開始前の場合
				// ロールバックを実行。
				if ( ( exceptionFlag == true ) && (transactionStartFlag == true ) ) {
					dataAccess.rollback();
					dataAccess = null;
				}
				// メソッド終了ログを出力
				DebugLog.write( this.getClass()
					, "TAIL countupStudyCount("
						+ " \""+ userID + "\""
						+ ", \"" + loID + "\""
						+ ", \"" + loType + "\")"
					, DebugLog.ROW);
			}
		}
	}
}
