/*
このファイルの中身は、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) ______________________________________.
*/

//
//	GroupAndPeople 管理XMO サーバクラス
//			変更履歴
//				2004.01.08	新規作成	二條智文
//
package jp.co.ntt.lms.xmo.GroupAndPeople;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;
import java.util.*;
import java.sql.*;

import org.apache.commons.lang.StringEscapeUtils;

import jp.co.ntt.lms.xmo.*;
import jp.co.ntt.lms.xmo.Groups.*;
import jp.co.ntt.lms.xmo.Message.Message;
import jp.co.ntt.lms.xmo.util.DebugLog;
import jp.co.ntt.lms.xmo.Assignments.AssignmentsClient;
import jp.co.ntt.lms.xmo.RoleAssignments.RoleAssignmentsClient;
import jp.co.ntt.lms.xmo.People.PeopleClient;

/**
 * GroupAndPeople 管理XMO サーバクラスです。<BR>
 * XMO基本メソッドを実装し、クライアントからの登録、更新、削除、検索処理
 * 要求をうけそれぞれの処理を行います。<BR>
 * RMIサーバとして動作するためRemoteインタフェースであるXMOインタフェースを実装し、
 * 永続的な起動状態を確保するためjava.rmi.server.UnicastRemoteObjectクラスを継承します。
 * @author T.Nijou
 * @version 0.0.0.1 2004/01/08
 */
public class GroupAndPeople extends UnicastRemoteObject
	implements XMO, GroupAndPeopleMessage, GroupAndPeopleTable
{

	//////////////////////////////////////////////////////////////////
	// メソッド名定義
	//////////////////////////////////////////////////////////////////
	/** 登録メソッド名です */
	private static final String METHOD1 = "insert";	// 登録
	/** 更新メソッド名です */
	private static final String METHOD2 = "update";	// 更新
	/** 削除メソッド名です */
	private static final String METHOD3 = "delete";	// 削除
	/** 検索メソッド名です */
	private static final String METHOD4 = "select";	// 検索
	/** パス検索メソッド名です */
	private static final String METHOD5 = "getPath";	// パス検索
	/** コピーメソッド名です */
	private static final String METHOD6 = "copy";	// コピー
	/** 直接ＤＢ検索メソッド名です */
	private static final String METHOD7 = "selectDatabase";	// ＤＢ検索
	/** キャッシュされているツリーを再読込するメソッド名です */
	private static final String METHOD8 = "reloadTree";
	/** 移動します。 */
	private static final String METHOD9 = "transfer";

	/**
	 * GroupAndPeopleの階層情報を保持します
	 */
	public static GroupAndPeopleTree mobjTree;

	/**
	 * グループテーブルアクセスクラスを保持します
	 */
	private GroupAndPeopleDataAccess mobjDataAccess = null;

	/**
	 * コンストラクタです。
	 */
	public GroupAndPeople() throws RemoteException, XMOException {
		// リモートオブジェクトをエクスポートする
		// java.rmi.server.UnicastRemoteObject の
		// 引数なしのコンストラクタを呼び出す
		super();

		// データクラスをインスタンス化します
		mobjDataAccess = new GroupAndPeopleDataAccess();

		if( mobjTree == null ) {
			// GroupAndPeopleツリー操作クラスをインスタンス化します
			mobjTree = new GroupAndPeopleTree(mobjDataAccess);
			// GroupAndPeopleテーブルから全レコードを読み込み
			// メモリ上にツリー構造を展開します
			mobjTree.load();
		}

	}


	/**
	 * メニュー一覧を返します
	 * @return Vector メニュー一覧
	 */
	public Vector getMenuList(Hashtable htbParam) {
		Vector vecMenuList = new Vector();
		try {
			GroupAndPeopleEnv objEnv = GroupAndPeopleEnv.getInstance();
			vecMenuList = objEnv.getMenuList();
		}
		catch( Exception e ) {
			return new Vector();
		}
		return vecMenuList;
	}

	/**
	 * メソッド一覧を返します
	 * @return Vector
	 */
	public Vector getMethodList() {
		Vector vecMethod = new Vector();
		vecMethod.add( METHOD1 );
		vecMethod.add( METHOD2 );
		vecMethod.add( METHOD3 );
		vecMethod.add( METHOD4 );
		return vecMethod;
	}

	/**
	 * デフォルトメニューを返します
	 * @return String
	 */
	public MenuData getDefaultMenu() {
		return null;
	}

	/**
	 * このXMOで定義された、メソッドを実行するときの
	 * クライアント側からの入り口になるメソッドです。
	 * @param strMethodName 実行するメソッド名を指定します
	 * @param htData メソッドで実行するパラメータを指定します<BR>
	 *               なお必要なキーと値は各DAOの処理メソッドの説明を参照して下さい。
	 * @retunr Object 戻り値（さまざまな戻り値に対応するためObject型としてあります)<BR>
	 *                受け取り側では適切な値にキャストする必要があります。
	 */
	public Object execute( String strMethodName, Hashtable htData ) {

		Object objReturn = null;

		if( strMethodName.equals( METHOD1 ) ) {
			objReturn = insert( htData );
		}
		else if( strMethodName.equals( METHOD2 ) ) {
			objReturn = update( htData );
		}
		else if( strMethodName.equals( METHOD3 ) ) {
			objReturn = delete( htData );
		}
		else if( strMethodName.equals( METHOD4 ) ) {
			objReturn = select( htData );
		}
		else if( strMethodName.equals( METHOD5 ) ) {
			objReturn = getPath( htData );
		}
		else if( strMethodName.equals( METHOD6 ) ) {
			objReturn = copy( htData );
		}
		else if( strMethodName.equals( METHOD7 ) ) {
			objReturn = selectDatabase( htData );
		}
		else if( strMethodName.equals( METHOD8 ) ) {
			objReturn = reloadTree( htData );
		}
		else if( strMethodName.equals( METHOD9 ) ) {
			objReturn = transfer( htData );
		}

		return objReturn;
	}

	/**
	 * 起動確認（必ずtrueを返す）
	 * @return boolean 必ずtrueが返ります
	 */
	public boolean isLaunch() {
		return true;
	}

	/**
	 * GroupAndPeopleテーブルへ登録処理を行います。<BR>
	 * 以下のパラメータチェックを行い、すべてOKの場合は
	 * GroupAndPeopleTreeクラスの登録処理メソッドを実行します。
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             PARENT_ID               親ID
	 *             CHILD_ID                子ID
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htData 登録情報
	 * @return String 結果(正しく終了した場合のみ)
	 * @exception XMOException データベースエラーが発生した場合
	 */
	private Vector insert( Hashtable htData ) {
		Vector vecReturn = new Vector();
		MessageData objMessage = null;
		//パラメータチェックを行い、パラメータエラーを設定します。
		String strMessage = insertCheck( htData );
		if( strMessage.equals( "" ) ) {
			try {
				mobjTree.insert( htData );
			}
			catch( XMOException xe ) {
				objMessage = xe.getMessageData();
			}
		}
		else {
			DebugLog.write( this.getClass(), new Exception(), DebugLog.HIGHT );
			objMessage = getMessageData( strMessage );
		}
		vecReturn.add( objMessage );
		return vecReturn;
	}

	/**
	 * GroupAndPeopleテーブルへ更新処理を行います。<BR>
	 * 以下のパラメータチェックを行い、すべてOKの場合は
	 * GroupAndPeopleTreeクラスの更新処理メソッドを実行します。
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             CONDITION_KEY           更新条件文
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htData 登録情報
	 * @return Vector 結果（配列の先頭にMessageDataオブジェクトを格納して返します)
	 */
	private Vector update( Hashtable htData ) {
		Vector vecReturn = new Vector();
		MessageData objMessage = null;

		// 更新処理のパラメータチェックを行います
		String strMessage = updateCheck( htData );
		if( strMessage.equals( "" ) ) {
			try {
				mobjTree.update( htData );
			}
			catch( XMOException xe ) {
				objMessage = xe.getMessageData();
			}
		}
		else {
			DebugLog.write( this.getClass(), new Exception(), DebugLog.HIGHT );
			objMessage = getMessageData( strMessage );
		}

		vecReturn.add( objMessage );
		return vecReturn;
	}

	/**
	 * GroupAndPeopleテーブルへ削除処理を行います。<BR>
	 * 以下のパラメータチェックを行い、すべてOKの場合は
	 * GroupAndPeopleTreeクラスの削除処理メソッドを実行します。
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             CONDITION_KEY           更新条件文
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htData 削除情報
	 * @return Vector 結果（配列の先頭にMessageDataオブジェクトを格納して返します)
	 */
	private Vector delete( Hashtable htData ) {
		Vector vecReturn = new Vector();
		MessageData objMessage = null;
		try {
			mobjTree.delete( htData );
		}
		catch( XMOException xe ) {
			objMessage = xe.getMessageData();
		}
		vecReturn.add( objMessage );
		return vecReturn;
	}

	/**
	 * GroupAndPeopleテーブルへ検索処理を行います。<BR>
	 * メンバーシップIDおよび親IDおよび子IDが設定されている場合は
	 * GroupAndPeopleTreeクラスの各検索メソッドを実行します。<BR>
	 * もし上記の条件が設定されていない場合はDBから検索を行います。<BR>
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             MEMBER_SHIP_ID          メンバーシップID
	 *             PARENT_ID               親ID
	 *             CHILD_ID                子ID
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htData 検索情報
	 * @return Vector 結果（配列の先頭にMessageDataオブジェクトを格納し、２番目移行に
	 *                      GroupAndPeopleクラスを格納して返します。)
	 */
	private Vector select( Hashtable htData ) {
		Vector vecResult = new Vector();
		MessageData objMessage = null;

		// メンバーシップIDの取得
		String strMemberShipID = (String)htData.get( GroupAndPeopleDataAccess.MEMBER_SHIP_ID );
		// 親IDの取得
		String strSearchParentID = (String)htData.get( GroupAndPeopleDataAccess.PARENT_ID );
		// 子IDの取得
		String strSearchChildID = (String)htData.get( GroupAndPeopleDataAccess.CHILD_ID );
		// メンバーシップIDが設定されている場合はメモリ上から検索を行う
		if( strMemberShipID != null ) {
			// メンバーシップIDから検索を行うメソッドを実行します
			vecResult = mobjTree.getGroupAndPeopleListFromID( strMemberShipID );
		}
		// 親IDと子IDどちらかが設定されていた場合はメモリー上から検索を行う
		else if( strSearchParentID != null || strSearchChildID != null ) {
			// 親IDおよび子IDから検索を行うメソッドを実行します
			vecResult = mobjTree.getGroupAndPeopleList( strSearchParentID, strSearchChildID );
		}
		// メンバーシップIDと親IDと子IDのどれも指定していない場合はDBから検索を行う
		else {
			try {
				vecResult = mobjDataAccess.select( htData );
			}
			catch( XMOException xe ) {
				objMessage = xe.getMessageData();
			}
		}

		vecResult.add( 0, objMessage );

		return vecResult;
	}

	/**
	 * 指定されたIDのパスを検索します
	 * @param htData パラメータ
	 * @return Vector 検索結果
	 */
	private Vector getPath( Hashtable htData ) {
		// ハッシュから検索IDを取得する
		String strID = (String)htData.get( PARENT_ID );
		// メッセージデータオブジェクトの作成
		MessageData objMessage = null;
		// 戻り値設定
		Vector vecReturn = new Vector();
		if( strID == null ) {
			DebugLog.write( this.getClass(), new Exception(), DebugLog.HIGHT );
			 objMessage = getMessageData( PARAM_WAR );
		}
		else {
			// ツリーからパスを検索
			vecReturn = mobjTree.getPath( strID );
		}

		vecReturn.add( 0, objMessage );
		return vecReturn;
	}

	/**
	 * コピーします<BR>
	 * @param htData パラメータ
	 * @return Vector コピー結果
	 */
	private Vector copy( Hashtable htData )
	{
		// 移動元メンバーシップIDリスト
		String[] strSendMemberShipIDList = null;
		// 移動先メンバーシップID
		String strReceiveMemberShipID = null;
		// 処理タイプ
		int intType = 0;

		// 共通データアクセスクラスのインスタンス化
		DataAccess objDataAccess  = new DataAccess();
		try {

			try {
				// 移動元メンバーシップIDリストを取得します
				strSendMemberShipIDList = (String[])htData.get(SEND_MEMBERSHIPID_LIST);
				// 移動先メンバーシップIDを取得します
				strReceiveMemberShipID = (String)htData.get(RECEIVE_MEMBERSHIPID);
				// 処理タイプを取得します
				intType = ((Integer)htData.get(PROCESS_TYPE)).intValue();
			}
			catch(ClassCastException ce) {
				// 内部エラー
				MessageData objMessage = getMessageData(PARAM_WAR);
				throw new XMOException(objMessage);
			}
			// パラメータチェック
			if( strSendMemberShipIDList == null || strReceiveMemberShipID == null ) {
				// 内部エラー
				MessageData objMessage = getMessageData(PARAM_WAR);
				throw new XMOException(objMessage);
			}
			// 処理タイプチェック
			if( !(intType == UP_TYPE || intType == IN_TYPE || intType == DOWN_TYPE) ) {
				// 内部エラー
				MessageData objMessage = getMessageData(PARAM_WAR);
				throw new XMOException(objMessage);
			}

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

			// 所属追加処理を行います。
			copyAction( strSendMemberShipIDList, strReceiveMemberShipID, intType, objDataAccess );

			// コミット
			objDataAccess.commit();
		}
		catch( SQLException se ) {
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			DebugLog.write(this.getClass(), se, DebugLog.HIGHT);
			Vector vecReturn = new Vector();
			vecReturn.add( getMessageData( DB_ERR ) );
			return vecReturn;
		}
		catch( XMOException xe ) {
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			DebugLog.write(this.getClass(), xe, DebugLog.HIGHT);
			Vector vecReturn = new Vector();
			vecReturn.add( xe.getMessageData() );
			return vecReturn;
		}

		// 正常に終了下ので配列の１番目にnullを格納して返す。
		Vector vecReturn = new Vector();
		vecReturn.add(null);
		return vecReturn;
	}

	/**
	 * 所属追加処理を行います。
	 * @param strSendMemberShipIDList 移動元メンバシップIDリスト
	 * @param strReceiveMemberShipID 移動先メンバシップIDリスト
	 * @param intType 処理区分
	 * @param objDataAccess データアクセスクラス
	 * @exception XMOException XMO独自例外
	 */
	private void copyAction( String[] strSendMemberShipIDList, String strReceiveMemberShipID, int intType, DataAccess objDataAccess )
		throws XMOException
	{
		//移動元IDリストをforループで回りながら、親IDと子IDに分割する。
		//移動元のstrSendMemberShipIDListの”＾”を削除する。
		GroupAndPeopleData[] objSendDataList = new GroupAndPeopleData[strSendMemberShipIDList.length];
		for( int i = 0; i < strSendMemberShipIDList.length; i++ ) {
			objSendDataList[i] = makeGroupAndPeopleData( strSendMemberShipIDList[i] );
		}

		//移動先IDリストを親IDと子IDに分割する。
		//移動先のstrReceiveMemberShipIDの”＾”を削除する。
		GroupAndPeopleData objReceiveData = makeGroupAndPeopleData( strReceiveMemberShipID );

		// GroupAndPeopleテーブルアクセスクラスのインスタンス化
		GroupAndPeopleDataAccess objGroupAndPeopleDataAccess = new GroupAndPeopleDataAccess();

		try {
			// 処理前のDB更新チェック処理を行う。データベースが更新されていた場合はエラーを投げる
			if( !copyCheck( objSendDataList, objReceiveData, intType, objDataAccess ) ) {
				// 更新済み警告をスローします。
				throw new XMOException( getMessageData( DB_UPDATE_WAR ) );
			}

			int intReceiveSortNo = 0;
			int intReceiveMaxSortNo = 0;
			int intSortNo = 0;
			//上へ or 下への時
			if (intType == 1 || intType == 3) {
				// 移動先のsort_noを取得する。
				intReceiveSortNo = objGroupAndPeopleDataAccess.getMemberShipIDSortNo(objReceiveData.getMemberShipID(), objDataAccess);

				//移動元IDリスト配列数
				int intSendListLength = strSendMemberShipIDList.length;
				//updateReciveSort_noメソッド内で上への時、下への時のUPDATE文の判定を行っている。
				objGroupAndPeopleDataAccess.updateSortNo(intReceiveSortNo,
																intSendListLength,
																objReceiveData.getParentID(),
																intType,
																objDataAccess);

				for( int i = 0; i < strSendMemberShipIDList.length; i++ ){
					//上への時：移動元のsort_noに対して、移動先のsort_noに1++した値を割り振る為メソッドに渡す前に1++する。
					if (intType == 1){
						intSortNo = intReceiveSortNo++;
					}
					//下への時：移動元のsort_noに対して、移動先のsort_noに++1した値を割り振る為メソッドに渡す前に++1する。
					if (intType == 3){
						intSortNo = ++intReceiveSortNo;
					}
					objGroupAndPeopleDataAccess.insertGroupAndPeople(objSendDataList[i], objReceiveData.getParentID(), intSortNo, objDataAccess);
				}
			}
			//中への時
			else{
				// 移動先の子の配下のsort_noの最大値を取得する。
				intReceiveMaxSortNo = objGroupAndPeopleDataAccess.getMaxSortNo(objReceiveData.getChildID(), objDataAccess);

				//移動元のsort_noに対して、移動先の子の配下のsort_noの最大値に++1したsort_noを割り振る。
				for( int i = 0; i < strSendMemberShipIDList.length; i++ ){
					intSortNo = ++intReceiveMaxSortNo;
					objGroupAndPeopleDataAccess.insertGroupAndPeople(objSendDataList[i], objReceiveData.getChildID(), intSortNo, objDataAccess);
				}
			}

			if( !objReceiveData.getParentID().equals( "" ) ) {
				// アサインの引継ぎ処理
				// 親と同様のアサインを割り当てます
				String strParentMemberShipID = null;
				// 中へ処理の場合
				if( intType == IN_TYPE ) {
					strParentMemberShipID = objReceiveData.getMemberShipID();
				}
				// 上へ、下への場合
				else {
					strParentMemberShipID = objGroupAndPeopleDataAccess.getMemberShipIDFromChildID(objReceiveData.getParentID(), objDataAccess);
				}

				// メンバシップIDが取得できたら親のLOアサインを子に引き継ぎます。
				if( strParentMemberShipID != null ) {
					// 移動元分ループを行い、アサインの設定を行います。
					for(int i = 0; i < objSendDataList.length; i++ ) {
						// 子MemberShipIDを組み立てる
						String strChildMemberShipID = null;
						// 中へ処理の場合
						if( intType == IN_TYPE ) {
							strChildMemberShipID = objReceiveData.getChildID() + objSendDataList[i].getChildID();
						}
						// 上へ、下へ処理の場合
						else {
							strChildMemberShipID = objReceiveData.getParentID() + objSendDataList[i].getChildID();
						}
						// 所属追加は新規登録なので必ずアサイン引継ぎ処理を行う。
						assignLoSameToParent( strParentMemberShipID, strChildMemberShipID, objDataAccess );
					}
				}
			}


			//---------------------------------------------------------------------
			//メモリ上のツリー構造を更新(所属追加処理)
			//---------------------------------------------------------------------
			boolean blIsUpdate = mobjTree.executeCopy( objSendDataList, objReceiveData, intType );
			//更新に失敗した場合
			if ( !blIsUpdate )
			{
				//エラー
				String strUpdateErr = "メモリ上のツリー更新に失敗しました。";
				throw new XMOException( strUpdateErr );
			}

					}
		catch( SQLException se ) {
			// エラー処理
			DebugLog.write( this.getClass(), se, DebugLog.HIGHT );
			// データベースエラーを設定
			throw new XMOException( getMessageData( DB_ERR ) );
		}
	}

	/**
	 * 移動処理前のDB更新チェックを行います。
	 * DBが更新されていた場合はエラーを投げます。
	 * @param objSendDataList 所属追加元リスト
	 * @param objRecieveData 所属追加先リスト
	 * @param intType 処理区分(1: 上へ、2: 中へ、3: 下へ)
	 * @param objDataAccess 共通データアクセスクラス
	 * @return boolean true : チェックOK false : チェックNG
	 * @exception SQLException DBエラー
	 * @exception XMOException XMO例外
	 */
	private boolean copyCheck(	GroupAndPeopleData[] objSendDataList,
								GroupAndPeopleData objRecieveData,
								int intType,
								DataAccess objDataAccess )
		throws SQLException, XMOException
	{
		// 所属追加先ID取得
		String strRecieveID = null;
		if( intType == IN_TYPE ) {
			strRecieveID = objRecieveData.getChildID();
		}
		else {
			strRecieveID = objRecieveData.getParentID();
		}

		// レコードの存在チェック 存在しなかったらエラー
		if( !isExistRecord( objSendDataList, objRecieveData, objDataAccess ) ) {
			return false;
		}

		// 移動先配下の存在チェック 存在したらエラー
		for( int i = 0; i < objSendDataList.length; i++ ) {
			if( isExistUnderRecord( objSendDataList[i], strRecieveID, objDataAccess ) ) {
				return false;
			}
		}

		// 未所属直下に同一ユーザが存在しないことを確認する。存在したらエラー
		if( isExistUnderWastes( objSendDataList, objDataAccess ) ) {
			return false;
		}

		return true;
	}

	/**
	 * コピー再帰呼出し<BR>
	 * @param XMONode ツリー構造
	 * @param DataAccess トランザクション
	 * @param boolean グループ名コピー作成フラグ
	 * @param String コピー先ID
	 */
	private void copyAction(XMONode objNode,
								DataAccess objDataAccess,
								boolean boolFlag,
								String strCopyDescID)
			throws XMOException, Exception
	{
		// XMONodeオブジェクトからID取得
		String strID = objNode.getParentID();

		// グループかユーザーかチェック
		if(strID != null && strID.indexOf("GR") > -1) {
			// 詳細データ取得
			String strGroupName = "";
			String strGroupType = "";
			String strDeleteFlag = "";
			String strForeignID = "";
			String strCustomMsg = "";
			String strOid = "";
			String strAdDn = "";

			// グループXMO
			GroupsClient objGroups = new GroupsClient();
			// コネクションを共有します
			objGroups.setConnectionIndex(objDataAccess.getConnectionIndex());
			// 検索条件のを設定
			objGroups.setWhereGroupID(strID);
			if(!objGroups.select()) {
				throw new XMOException(objGroups.getMessageData());
			}
			if(objGroups.next()) {
				strGroupName   = objGroups.getGroupName();
				strGroupType   = objGroups.getGroupType();
				strDeleteFlag  = objGroups.getDeleteFlag();
				strForeignID   = objGroups.getForeignID();
				strCustomMsg   = objGroups.getCustomMsgDir();
				strOid   = objGroups.getOid();
				strAdDn   = objGroups.getAdDn();
			}

			objGroups.clear();

			// グループ名編集処理
			if(boolFlag) {
				strGroupName = editGroupName(strGroupName, strCopyDescID, objDataAccess);
			}
			// 外部ID編集処理
			strForeignID = editForeignID(strForeignID, objDataAccess);

			// 登録処理
			// コネクションを共有します。
			objGroups.setConnectionIndex(objDataAccess.getConnectionIndex());
			// エンコード設定
			objGroups.setEncode("Windows-31J");
			// パラメータ設定
			objGroups.setParentID(strCopyDescID);
			objGroups.setGroupName(strGroupName);
			objGroups.setGroupType(strGroupType);
			objGroups.setDeleteFlag(strDeleteFlag);
			objGroups.setForeignID(strForeignID);
			objGroups.setCustomMsgDir(strCustomMsg);
			objGroups.setOid(strOid);
			objGroups.setAdDn(strAdDn);
			if(!objGroups.insert()) {
				// 登録に失敗した場合
				throw new XMOException(objGroups.getMessageData());
			}
			// 登録GroupIDを取得する
			String strCopyGroupID = "";
			if(objGroups.next()) {
				// サーバ側登録後のグループIDを取得する
				strCopyGroupID = objGroups.getGroupID();
				// 子ノード分再帰処理を繰り返す。
				for( int i = 0; i < objNode.getChildCount(); i++ ) {
					copyAction( objNode.getChildNode(i),
								objDataAccess,
								false,
								strCopyGroupID);
				}
			}
		}
		else {
			// ユーザーならば
			GroupAndPeopleClient objGapc = new GroupAndPeopleClient();
			objGapc.setConnectionIndex(objDataAccess.getConnectionIndex());
			objGapc.setParentID(strCopyDescID);
			objGapc.setChildID(strID);
			// 登録処理
			if(!objGapc.insert())
			{
				// 登録に失敗した場合
				throw new XMOException(objGapc.getMessageData());
			}
		}
	}



	/**
	 * グループ名リストを取得します<BR>
	 * @param String コピー元の親ID
	 * @return  Vector グループ名リスト
	 */
	private Vector getGroupNameList( String strParentID, DataAccess objDataAccess )
		throws XMOException, Exception
	{
		Vector vecList = new Vector();

		GroupsClient objGroups = new GroupsClient();
		// コネクション共有
		objGroups.setConnectionIndex( objDataAccess.getConnectionIndex() );

		StringBuffer sbCondition = new StringBuffer();
		sbCondition.append( GroupsClient.GROUP_ID );
		sbCondition.append( " in (SELECT " );
		sbCondition.append( CHILD_ID );
		sbCondition.append( " FROM " );
		sbCondition.append( TABLE_NAME );
		sbCondition.append( " WHERE " );
		sbCondition.append( PARENT_ID );
		sbCondition.append( "='" );
		sbCondition.append( StringEscapeUtils.escapeSql(strParentID) );
		sbCondition.append( "')" );

		// 検索条件の設定
		objGroups.setCondition( sbCondition.toString() );
		// 検索処理
		if( !objGroups.select() ) {
			throw new XMOException( objGroups.getMessageData() );
		}

		// 検索結果をVectorに追加する
		while( objGroups.next() ) {
			vecList.add( objGroups.getGroupName() );
		}

		return vecList;
	}

	/**
	 * グループ名を編集します<BR>
	 * @param strGroupName グループ名(編集前)
	 * @return  String グループ名(編集後)
	 */
	private String editGroupName(String strGroupName, String strParentID, DataAccess objDataAccess)
		throws Exception, XMOException
	{
		// グループ名のリストを取得します
		Vector vecLoTitleList = getGroupNameList( strParentID, objDataAccess );

		int intCount = 0;
		while( true ) {
			String strNumber = "";
			if( intCount > 0 ) {
				strNumber = "(" + intCount + ")";
			}
			String strNameTemp = makeDecimalString( strGroupName, strNumber, GroupsClient.GROUPNAME_LENB );
			if( vecLoTitleList.contains( strNameTemp ) ) {
				intCount++;
				continue;
			}
			else {
				strGroupName = strNameTemp;
				break;
			}
		}

		return strGroupName;
	}


	/**
	 * 外部IDを編集します<BR>
	 * NULLで戻った場合エラーとします
	 * @param String 外部ID(編集前)
	 * @return  String 外部ID(編集後)
	 */
	private String editForeignID(String strForeignID,
								DataAccess objDataAccess)
		throws XMOException, Exception
	{
		String strRet = "";
		int intCount = 1;
		GroupsClient objGc = new GroupsClient();
		while(true) {
			String strCount = "(" + intCount + ")";;
			strRet = makeDecimalString( strForeignID, strCount, GroupsClient.FOREIGNID_LENB );
			objGc.clear();
			
			// エンコード設定
			objGc.setEncode("Windows-31J");
			// コネクションの共有
			objGc.setConnectionIndex(objDataAccess.getConnectionIndex());
			// 外部IDを検索条件に設定
			objGc.setWhereForeignID(strRet);
			if(!objGc.select()) {
				throw new XMOException(objGc.getMessageData());
			}
			if(objGc.next()) {
				intCount++;
				continue;
			}
			else {
				break;
			}
		}
		return strRet;
	}

	/**
	 * コピー用の名称作成メソッド
	 */
	private String makeDecimalString( String strName, String strNumber, int intLen ) {
		if( strName == null || strNumber == null || intLen < 0 ) {
			return "";
		}
		byte[] nameByte = strName.getBytes();
		byte[] numByte = strNumber.getBytes();
		while( nameByte.length + numByte.length > intLen ) {
			strName = strName.substring( 0, strName.length() - 1 );
			nameByte = strName.getBytes();
		}

		return strName + strNumber;
	}

	/**
	 * GroupAndPeopleテーブルへ検索処理を行います。<BR>
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             MEMBER_SHIP_ID          メンバーシップID
	 *             PARENT_ID               親ID
	 *             CHILD_ID                子ID
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htData 検索情報
	 * @return Vector 結果（配列の先頭にMessageDataオブジェクトを格納し、２番目移行に
	 *                      GroupAndPeopleクラスを格納して返します。)
	 */
	private Vector selectDatabase( Hashtable htData ) {
		Vector vecResult = new Vector();
		MessageData objMessage = null;

		try {
			vecResult = mobjDataAccess.select( htData );
		}
		catch( XMOException xe ) {
			objMessage = xe.getMessageData();
		}

		vecResult.add( 0, objMessage );

		return vecResult;
	}

	/**
	 * メッセージオブジェクトを作成します
	 * @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;
	}

	/**
	 * 登録処理のパラメータチェックを行います<BR>
	 * 以下のパラメータのチェックを行います。
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             MEMBER_SHIP_ID          人々ID
	 *             PARENT_ID               親ID
	 *             CHILD_ID                子ID
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htbParam パラメータ
	 * @return String エラー時はエラー番号 OKのときは空文字を返します
	 */
	private String insertCheck( Hashtable htbParam ) {

		String strMessage = "";
		String strCheck = "";

		// 親IDのチェック(必須チェックあり)
		strCheck = (String)htbParam.get( PARENT_ID );
		strMessage = GroupAndPeopleCheck.checkParentID( strCheck, true );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 子IDのチェック(必須チェックあり)
		strCheck = (String)htbParam.get( CHILD_ID );
		strMessage = GroupAndPeopleCheck.checkChildID( strCheck, true );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 正常時は空文字を返す
		return "";
	}

	/**
	 * 更新処理のパラメータチェックを行います<BR>
	 * 以下のパラメータのチェックを行います。
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             MEMBER_SHIP_ID          人々ID
	 *             PARENT_ID               親ID
	 *             CHILD_ID                子ID
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htbParam パラメータ
	 * @return String エラー時はエラー番号 OKのときは空文字を返します
	 */
	private String updateCheck( Hashtable htbParam ) {

		String strMessage = "";
		String strCheck = "";

		// 人々IDのチェック
		strCheck = (String)htbParam.get( MEMBER_SHIP_ID );
		strMessage = GroupAndPeopleCheck.checkMemberShipID( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 親IDのチェック
		strCheck = (String)htbParam.get( PARENT_ID );
		strMessage = GroupAndPeopleCheck.checkParentID( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 子IDのチェック
		strCheck = (String)htbParam.get( CHILD_ID );
		strMessage = GroupAndPeopleCheck.checkChildID( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 正常時は空文字を返す
		return "";
	}

	/**
	 * 一括登録用エラー時のツリー再読込メソッド
	 */
	private Vector reloadTree( Hashtable htData ) {
		Vector vecReturn = new Vector();
		MessageData objMessage = null;

		try {
			// ツリーのリロード
			synchronized(mobjTree){
				mobjTree.load();
			}
		}
		catch( XMOException xe ) {
			DebugLog.write(this.getClass(), xe, DebugLog.HIGHT);
			objMessage = xe.getMessageData();
		}
		vecReturn.add( objMessage );
		return vecReturn;
	}

	/**
	 * 移動処理を行います
	 * @param htData パラメータを格納したHashtable
	 * @return Vector 結果
	 */
	private Vector transfer( Hashtable htData ) {
		// 移動元メンバーシップIDリスト
		String[] strSendMemberShipIDList = null;
		// 移動先メンバーシップID
		String strReceiveMemberShipID = null;
		// 処理タイプ
		int intType = 0;

		// 共通データアクセスクラスのインスタンス化
		DataAccess objDataAccess  = new DataAccess();
		try {
			try {
				// 移動元メンバーシップIDリストを取得します
				strSendMemberShipIDList = (String[])htData.get(SEND_MEMBERSHIPID_LIST);
				// 移動先メンバーシップIDを取得します
				strReceiveMemberShipID = (String)htData.get(RECEIVE_MEMBERSHIPID);
				// 処理タイプを取得します
				intType = ((Integer)htData.get(PROCESS_TYPE)).intValue();
			}
			catch(ClassCastException ce) {
				// 内部エラー
				MessageData objMessage = getMessageData(PARAM_WAR);
				throw new XMOException(objMessage);
			}
			// パラメータチェック
			if( strSendMemberShipIDList == null || strReceiveMemberShipID == null ) {
				// 内部エラー
				MessageData objMessage = getMessageData(PARAM_WAR);
				throw new XMOException(objMessage);
			}
			// 処理タイプチェック
			if( !(intType == UP_TYPE || intType == IN_TYPE || intType == DOWN_TYPE) ) {
				// 内部エラー
				MessageData objMessage = getMessageData(PARAM_WAR);
				throw new XMOException(objMessage);
			}

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

			// 移動処理後のLOアサイン更新処理を行うフラグ
			String strUpdateAssignFlag = (String)htData.get( UPDATE_ASSIGNMENTS );

			// 移動処理を行います。
			transferAction( strSendMemberShipIDList, strReceiveMemberShipID, intType, strUpdateAssignFlag, objDataAccess );

			// コミット
			objDataAccess.commit();

		}

		catch( SQLException se ) {
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			DebugLog.write(this.getClass(), se, DebugLog.HIGHT);
			Vector vecReturn = new Vector();
			vecReturn.add( getMessageData( DB_ERR ) );
			return vecReturn;
		}

		catch( XMOException xe ) {
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			DebugLog.write(this.getClass(), xe, DebugLog.HIGHT);
			Vector vecReturn = new Vector();
			vecReturn.add( xe.getMessageData() );
			return vecReturn;
		}

		// 正常に終了下ので配列の１番目にnullを格納して返す。
		Vector vecReturn = new Vector();
		vecReturn.add(null);
		return vecReturn;
	}

	/**
	 * 移動処理を行います。
	 * @param strSendMemberShipIDList 移動元メンバシップIDリスト
	 * @param strReceiveMemberShipID 移動先メンバシップID
	 * @param intType 処理区分(上へ：1、中へ：2、下へ：3)
	 * @param strUpdateAssignFlag アサインの更新の有無(nullの場合にアサイン更新処理を行う)
	 * @param objDataAccess データアクセスクラス
	 * @exception XMOException XMO独自例外
	 */
	private void transferAction(	String[] strSendMemberShipIDList,
									String strReceiveMemberShipID,
									int intType,
									String strUpdateAssignFlag,
									DataAccess objDataAccess )
		throws XMOException
	{

		//移動元IDリストをforループで回りながら、親IDと子IDに分割する。
		//移動元のstrSendMemberShipIDListの”＾”を削除する。
		GroupAndPeopleData[] objSendDataList = new GroupAndPeopleData[strSendMemberShipIDList.length];
		for( int i = 0; i < strSendMemberShipIDList.length; i++ ) {
			objSendDataList[i] = makeGroupAndPeopleData( strSendMemberShipIDList[i] );
		}

		//移動先IDリストを親IDと子IDに分割する。
		//移動先のstrReceiveMemberShipIDの”＾”を削除する。
		GroupAndPeopleData objReceiveData = makeGroupAndPeopleData( strReceiveMemberShipID );

		// GroupAndPeopleテーブルアクセスクラスのインスタンス化
		GroupAndPeopleDataAccess objGroupAndPeopleDataAccess = new GroupAndPeopleDataAccess();

		try {

			// 処理前のDB更新チェック処理を行う。データベースが更新されていた場合はエラーを投げる
			if( !transferCheck( objSendDataList, objReceiveData, intType, objDataAccess ) ) {
				// 更新済み警告をスローします。
				throw new XMOException( getMessageData( DB_UPDATE_WAR ) );
			}

			int intReceiveSortNo = 0;
			int intReceiveMaxSortNo = 0;
			int intSortNo = 0;
			//上へ or 下への時
			if (intType == 1 || intType == 3) {
				// 移動先のsort_noを取得する。
				intReceiveSortNo = objGroupAndPeopleDataAccess.getMemberShipIDSortNo(objReceiveData.getMemberShipID(), objDataAccess);

				//移動元IDリスト配列数
				int intSendListLength = strSendMemberShipIDList.length;
				//updateReciveSort_noメソッド内で上への時、下への時のUPDATE文の判定を行っている。
				objGroupAndPeopleDataAccess.updateSortNo(intReceiveSortNo,
																intSendListLength,
																objReceiveData.getParentID(),
																intType,
																objDataAccess);

				for( int i = 0; i < strSendMemberShipIDList.length; i++ ){
					//上への時：移動元のsort_noに対して、移動先のsort_noに1++した値を割り振る為メソッドに渡す前に1++する。
					if (intType == 1){
						intSortNo = intReceiveSortNo++;
					}
					//下への時：移動元のsort_noに対して、移動先のsort_noに++1した値を割り振る為メソッドに渡す前に++1する。
					if (intType == 3){
						intSortNo = ++intReceiveSortNo;
					}
					objGroupAndPeopleDataAccess.updateGroupAndPeople(objSendDataList[i], objReceiveData.getParentID(), intSortNo, objDataAccess);

					// ユーザ種別が2(AD)でユーザが未所属へ移動の場合、削除フラグを 1 にします。
					updateDeleteFlag(objSendDataList[i], objReceiveData.getParentID(), objDataAccess);
				}
			}
			//中への時
			else{
				// 移動先の子の配下のsort_noの最大値を取得する。
				intReceiveMaxSortNo = objGroupAndPeopleDataAccess.getMaxSortNo(objReceiveData.getChildID(), objDataAccess);

				//移動元のsort_noに対して、移動先の子の配下のsort_noの最大値に++1したsort_noを割り振る。
				for( int i = 0; i < strSendMemberShipIDList.length; i++ ){
					intSortNo = ++intReceiveMaxSortNo;
					objGroupAndPeopleDataAccess.updateGroupAndPeople(objSendDataList[i], objReceiveData.getChildID(), intSortNo, objDataAccess);
					// ユーザ種別が2(AD)でユーザが未所属へ移動の場合、削除フラグを 1 にします。
					updateDeleteFlag(objSendDataList[i], objReceiveData.getChildID(), objDataAccess);

				}
			}

			// アサイン更新フラグがnullの場合はアサイン更新を行う。
			if( strUpdateAssignFlag == null ) {
				// 移動元分ループを行い、アサインの設定を行います。
				for(int i = 0; i < objSendDataList.length; i++ ) {
					// 更新前メンバシップID
					String strSendID = objSendDataList[i].getMemberShipID();
					// 更新後メンバシップID
					String strRecieveID = null;
					if( intType == IN_TYPE ) {
						strRecieveID = objReceiveData.getChildID() + objSendDataList[i].getChildID();
					}
					else {
						strRecieveID = objReceiveData.getParentID() + objSendDataList[i].getChildID();
					}

					// 移動前と移動後のメンバシップIDが変化するものだけアサイン更新処理をコールする。
					if( !strSendID.equals( strRecieveID ) ) {
						// アサインの更新を行います。
						updateAssign( strSendID, strRecieveID, objDataAccess );
					}
				}
			}


			if( !objReceiveData.getParentID().equals( "" ) ) {
				// 親と同様のアサインを割り当てます
				String strParentMemberShipID = null;
				// 中へ処理の場合
				if( intType == IN_TYPE ) {
					strParentMemberShipID = objReceiveData.getMemberShipID();
				}
				// 上へ、下への場合
				else {
					strParentMemberShipID = objGroupAndPeopleDataAccess.getMemberShipIDFromChildID(objReceiveData.getParentID(), objDataAccess);
				}

				// メンバシップIDが取得できたら親のLOアサインを子に引き継ぎます。
				if( strParentMemberShipID != null ) {
					// 移動元分ループを行い、アサインの設定を行います。
					for(int i = 0; i < objSendDataList.length; i++ ) {
						// 子MemberShipIDを組み立てる
						String strChildMemberShipID = null;
						// 中へ処理の場合
						if( intType == IN_TYPE ) {
							strChildMemberShipID = objReceiveData.getChildID() + objSendDataList[i].getChildID();
						}
						// 上へ、下へ処理の場合
						else {
							strChildMemberShipID = objReceiveData.getParentID() + objSendDataList[i].getChildID();
						}

						// 移動前と移動後で、MemberShipIDが変化していないものはアサインの引継ぎは行わない。
						if( !objSendDataList[i].getMemberShipID().equals( strChildMemberShipID ) ) {
							// 親のアサイン引継ぎメソッドをコールする。
							assignLoSameToParent( strParentMemberShipID, strChildMemberShipID, objDataAccess );
						}
					}
				}
			}

			//---------------------------------------------------------------------
			//メモリ上のツリー構造を更新(移動処理)
			//---------------------------------------------------------------------
			boolean blIsUpdate = mobjTree.executeMove( objSendDataList, objReceiveData, intType );
			//更新に失敗した場合
			if ( !blIsUpdate )
			{
				//エラー
				String strUpdateErr = "メモリ上のツリー更新に失敗しました。";
				throw new XMOException( strUpdateErr );
			}

		}
		catch( XMOException xe ) {
			// エラー処理
			DebugLog.write( this.getClass(), xe, DebugLog.HIGHT );
			throw xe;
		}
		catch( SQLException se ) {
			// エラー処理
			DebugLog.write( this.getClass(), se, DebugLog.HIGHT );
			// データベースエラーを設定
			throw new XMOException( getMessageData( DB_ERR ) );
		}
		catch( Exception ex ) {
			// エラー処理
			DebugLog.write( this.getClass(), ex, DebugLog.HIGHT );
			// データベースエラーを設定
			throw new XMOException( getMessageData( SYSTEM_ERR ) );
		}
	}

	/**
	 * 移動処理前のDB更新チェックを行います。
	 * DBが更新されていた場合はエラーを投げます。
	 * @param objSendDataList 元リストデータ
	 * @param objRecieveData 先データ
	 * @param intType 処理区分(1: 上へ、2: 中へ、3: 下へ)
	 * @param objDataAccess 共通データアクセスクラス
	 * @return boolean true : チェックOK false : チェックNG
	 * @exception SQLException DBエラー
	 * @exception XMOException XMO例外
	 */
	private boolean transferCheck( GroupAndPeopleData[] objSendDataList,
									GroupAndPeopleData objRecieveData,
									int intType,
									DataAccess objDataAccess )
		throws SQLException, XMOException
	{
		//
		// 移動先ID取得
		String strRecieveID = null;
		if( intType == IN_TYPE ) {
			strRecieveID = objRecieveData.getChildID();
		}
		else {
			strRecieveID = objRecieveData.getParentID();
		}

		// レコードの存在チェック 存在しなかったらエラー
		if( !isExistRecord( objSendDataList, objRecieveData, objDataAccess ) ) {
			return false;
		}

		// 移動元と移動先の親IDが一緒ではないときのみ移動先配下の存在チェックを行う
		for( int i = 0; i < objSendDataList.length; i++ ) {
			if( !objSendDataList[i].getParentID().equals( strRecieveID ) ) {
				// 移動先配下の存在チェック 存在したらエラー
				if( isExistUnderRecord( objSendDataList[i], strRecieveID, objDataAccess ) ) {
					return false;
				}
			}
		}

		// 移動元が移動先の配下のチェックを行います。配下ならエラー
		if( isUnder( objSendDataList, strRecieveID ) ) {
			return false;
		}

		// もし未所属への移動の場合は複数ユーザチェックを行う
		if( strRecieveID.equals( XMOPropertyDef.WASTES_GROUPID ) ) {
			// 複数存在したらエラー
			if(isCopied(objSendDataList, objDataAccess) ) {
				return false;
			}
		}

		return true;
	}

	/**
	 * レコードの存在チェックを行います。
	 * @param objSendDataList 元リストデータ
	 * @param objRecieveData 先データ
	 * @param objDataAccess 共通データアクセスクラス
	 * @return boolean true : 存在する false : 存在しない
	 * @exception SQLException DB例外
	 */
	public boolean isExistRecord(  GroupAndPeopleData[] objSendDataList,
									GroupAndPeopleData objRecieveData,
									DataAccess objDataAccess )
		throws SQLException
	{
		GroupAndPeopleDataAccess objGroupAndPeopleDataAccess =
										new GroupAndPeopleDataAccess();
		// 元のレコードの存在チェックを行います
		for( int i = 0; i < objSendDataList.length; i++ ) {
			// メンバシップIDを指定して、レコード件数を取得する。
			int intCount = objGroupAndPeopleDataAccess.getCountMemberShipID(
												objSendDataList[i].getMemberShipID(),
												objDataAccess );

			if( intCount == 0 ) {
				// ０件の場合はすでに移動してしまっている。
				return false;
			}
		}

		if( objRecieveData.getParentID() != null &&
			!objRecieveData.getParentID().equals( "" ) ) {
			// 先のレコードの存在チェック
			// メンバシップIDを指定して、レコード件数を取得する。
			int intCount = objGroupAndPeopleDataAccess.getCountMemberShipID(
												objRecieveData.getMemberShipID(),
												objDataAccess );

			if( intCount == 0 ) {
				// ０件の場合はすでに移動してしまっている。
				return false;
			}
		}

		return true;
	}

	/**
	 * 先の直下に元と同一のレコードが存在するかチェックをします。
	 * @param objSendData 元リスト
	 * @param strRecieveID 先の親ID
	 * @param objDataAccess 共通データアクセスクラス
	 * @return boolean true : 存在する false : 存在しない
	 * @exception SQLException DB例外
	 */
	public boolean isExistUnderRecord( GroupAndPeopleData objSendData,
									String strRecieveID,
									DataAccess objDataAccess )
		throws SQLException
	{

		GroupAndPeopleDataAccess objGroupAndPeopleDataAccess =
										new GroupAndPeopleDataAccess();

		// 処理後のレコードのを組み立て、そのレコードが存在するかチェックを行います
		// メンバシップIDを指定して、レコード件数を取得する。
		int intCount = objGroupAndPeopleDataAccess.getCountMemberShipID(
											strRecieveID + objSendData.getChildID(),
											objDataAccess );

		if( intCount == 0 ) {
			// 0件の場合は存在しない
			return false;
		}

		// 存在する
		return true;
	}

	/**
	 * 元が先の配下かチェックを行います。。
	 * @param objSendDataList 元リストデータ
	 * @param strRecieveID 先の親ID
	 * @return boolean true : 配下 false : 配下じゃない
	 * @exception XMOException XMO例外
	 */
	public boolean isUnder( GroupAndPeopleData[] objSendDataList,
							String strRecieveID )
		throws XMOException
	{


		// 元の配下のIDを取得します。
		for( int i = 0; i < objSendDataList.length; i++ ) {
			// メモリツリーから元の配下のIDリストを取得します。
			String[] strUnderIDList = mobjTree.getUnderIDList( objSendDataList[i].getMemberShipID() );

			// 取得できなかった場合はシステムエラーをスローする
			if( strUnderIDList == null ) {
				throw new XMOException( getMessageData( SYSTEM_ERR ) );
			}

			for( int j = 0; j < strUnderIDList.length; j++ ) {
				if( strUnderIDList[j].equals( strRecieveID ) ) {
					// 配下に同じIDが存在した場合
					return true;
				}
			}
		}

		// 存在しなかった場合
		return false;
	}

	/**
	 * 所属追加されているユーザかどうかをチェックします。
	 * @param objSendDataList 元リストデータ
	 * @param objDataAccess 共通データアクセスクラス
	 * @return boolean true : 所属追加されているユーザ false : 単一のユーザ
	 * @exception SQLException DB例外
	 */
	public boolean isCopied( GroupAndPeopleData[] objSendDataList,
							DataAccess objDataAccess )
		throws SQLException
	{
		GroupAndPeopleDataAccess objGroupAndPeopleDataAccess =
										new GroupAndPeopleDataAccess();
		// 元のレコードの存在チェックを行います
		for( int i = 0; i < objSendDataList.length; i++ ) {
			// メンバシップIDを指定して、レコード件数を取得する。
			int intCount = objGroupAndPeopleDataAccess.getCountChildID(
												objSendDataList[i].getChildID(),
												objDataAccess );

			//
			if( intCount > 1 ) {
				// 1件以上の場合は所属追加ユーザ
				return true;
			}
		}

		return false;
	}

	/**
	 * 未所属配下にユーザが存在するかどうかチェックします。
	 * @param objSendDataList 元リストデータ
	 * @param objDataAccess 共通データアクセスクラス
	 * @return boolean true : 存在する false : 存在しない
	 * @exception SQLException DB例外
	 */
	public boolean isExistUnderWastes( GroupAndPeopleData[] objSendDataList,
										DataAccess objDataAccess )
		throws SQLException
	{
		GroupAndPeopleDataAccess objGroupAndPeopleDataAccess =
										new GroupAndPeopleDataAccess();
		// 元のレコードの存在チェックを行います
		for( int i = 0; i < objSendDataList.length; i++ ) {
			// メンバシップIDを指定して、レコード件数を取得する。
			int intCount = objGroupAndPeopleDataAccess.getCountMemberShipID(
												XMOPropertyDef.WASTES_GROUPID + objSendDataList[i].getChildID(),
												objDataAccess );

			if( intCount == 0 ) {
				// ０件の場合は存在しない
				return false;
			}
		}

		return true;
	}

	/**
	 * LOアサインの更新処理を行います。
	 * @param strSendID 更新前メンバシップID
	 * @param strRecieveID 更新後メンバシップID
	 * @param objDataAccess データアクセスクラス
	 * @exception XMOException XMO例外
	 */
	private void updateAssign( String strSendID, String strRecieveID, DataAccess objDataAccess )
		throws XMOException
	{
		//LO割り当てテーブルの更新が必要な場合のみ更新します。
		try {
			// LO割当テーブルを更新します
			AssignmentsClient objAss = new AssignmentsClient();
			// 更新メンバシップIDを設定
			objAss.setMemberShipID( strRecieveID );
			// 更新条件を設定
			objAss.setWhereMemberShipID( strSendID );
			// 現在使用しているコネクションをしようしトランザクションの共有を行います
			objAss.setConnectionIndex( objDataAccess.getConnectionIndex() );
			// LO割当テーブル更新処理
			if( !objAss.update() ) {
				// DBエラーを投げる
				throw new XMOException( objAss.getMessageData() );
			}
		}
		catch( Exception e ) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// システムエラーを投げる
			throw new XMOException( getMessageData( SYSTEM_ERR ) );
		}
	}

	/**
	 * 移動したグループ又はユーザに親のLoAssignmentsと同じものを
	 * 引き継ぎます。<BR>
	 * また、グループに引き継いだ場合、さらにその下のユーザにもアサインを引き継ぎます。
	 * @param strParentMemberShipID 親MemberShipID
	 * @param strChildMemberShipID 子MemberShipID
	 * @exception XMOException XMO独自エラー
	 * @exception SQLException DBエラーが発生した場合
	 */
	private void assignLoSameToParent( String strParentMemberShipID,
										String strChildMemberShipID,
										DataAccess objDataAccess )
		throws XMOException
	{
		try {

			// 子にアサインされている情報を取得する
			AssignmentsClient objChildAssignments = new AssignmentsClient();
			// メンバーシップIDを検索条件に付与します。
			objChildAssignments.setWhereMemberShipID( strChildMemberShipID );
			// 現在使用中のコネクションインデックスを指定し、トランザクションを
			// 共有します。
			objChildAssignments.setConnectionIndex( objDataAccess.getConnectionIndex() );
			// 検索メソッド実行
			if( !objChildAssignments.select() ) {
				// 検索エラーをスローする
				throw new XMOException( objChildAssignments.getMessageData() );
			}

			// 子にアサインされているMaterialIDリストを作成する
			Vector vecChildMaterialList = new Vector();
			while(objChildAssignments.next()) {
				vecChildMaterialList.add( objChildAssignments.getMaterialID() );
			}

			// 親にアサインされている情報を取得する
			AssignmentsClient objParentAssignments = new AssignmentsClient();
			// メンバーシップIDを検索条件に付与します。
			objParentAssignments.setWhereMemberShipID( strParentMemberShipID );
			// 現在使用中のコネクションインデックスを指定し、トランザクションを
			// 共有します。
			objParentAssignments.setConnectionIndex( objDataAccess.getConnectionIndex() );
			// 検索メソッド実行
			if( !objParentAssignments.select() ) {
				// 検索エラーをスローする
				throw new XMOException( objParentAssignments.getMessageData() );
			}

			// 検索結果数文ループをしながら、メンバーシップIDのみを変更して、
			// Assignmentsの登録メソッドを実行します。
			//登録するユーザのアサインを登録
			while(objParentAssignments.next()){
				// 親のMaterialIDがまだ登録されていない場合は新規に子にも登録する
				if( !vecChildMaterialList.contains(objParentAssignments.getMaterialID()) ) {
					// 登録用のAssignmentsClientをインスタンス化します
					AssignmentsClient objInAss = new AssignmentsClient();
					// 現在使用しているコネクションをしようしトランザクションの共有を行います
					objInAss.setConnectionIndex( objDataAccess.getConnectionIndex() );
					// パラメータ設定
					objInAss.setMemberShipID( strChildMemberShipID );				// 人々ID
					objInAss.setMaterialID( objParentAssignments.getMaterialID() );			// コンポーネントID
					objInAss.setStudyStartDate( objParentAssignments.getStudyStartDate() );	// 開始日
					objInAss.setEndDate( objParentAssignments.getEndDate() );					// 終了日
					objInAss.setAssigner( objParentAssignments.getAssigner() );							// アサイン者
					objInAss.setLearnAuthority( objParentAssignments.getLearnAuthority() );				// 学習権限
					objInAss.setManagementAuthority( objParentAssignments.getManagementAuthority() );		// 管理権限
					objInAss.setMethodFlag( objParentAssignments.getMethodFlag() );		// メソッドフラグ情報					
					// 登録メソッド実行
					// アサインXMOの登録処理内でグループ配下へのアサインの引継ぎを行っています。
					if( !objInAss.insert() ) {
						// 登録エラーをスローする
						throw new XMOException( objInAss.getMessageData() );
					}
				}
			}
		}
		catch( XMOException xe ) {
			throw xe;
		}
		catch( Exception e ) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// システムエラーをスローする
			throw new XMOException( getMessageData( SYSTEM_ERR ) );
		}
	}

	/**
	 * デリミタ('^')で区切られたMemberShipIDを受け取り、GroupAndPeopleDataオブジェクトを生成して返します
	 * @param strMemberShipID MemberShipID ただしデリミタ('^')で区切られている
	 * @return GroupAndPeopleData 生成されたGroupAndPeopleDataオブジェクト
	 */
	private GroupAndPeopleData makeGroupAndPeopleData( String strMemberShipID ) {
		GroupAndPeopleData objData = new GroupAndPeopleData();

		String strSendChildID = strMemberShipID.substring( strMemberShipID.indexOf("^") + 1, strMemberShipID.length() );
		String strSendParentID = strMemberShipID.substring( 0, strMemberShipID.indexOf("^") );
		String strSendMemberShipID = strSendParentID + strSendChildID;

		objData.setParentID( strSendParentID );
		objData.setChildID( strSendChildID );
		objData.setMemberShipID( strSendMemberShipID );

		return objData;
	}


	/**
	 * ユーザ種別が2(AD)でユーザが未所属へ移動の場合、削除フラグを 1 にします。
	 * @param objSend 移動元オブジェクト
	 * @param strReceiveID 移動先ID
	 * @exception Exception
	 */
	private void updateDeleteFlag( GroupAndPeopleData objSend, String strReceiveID, DataAccess objDataAccess )
		throws Exception
	{
		if( objSend == null || strReceiveID == null ) {
			// パラメータ不正
			throw new XMOException( PARAM_WAR );
		}

		if( objSend.isGroup() ||
			( !strReceiveID.equals( XMOPropertyDef.WASTES_GROUPID )  &&
			  !objSend.getParentID().equals( XMOPropertyDef.WASTES_GROUPID ) ) ||
			( strReceiveID.equals( XMOPropertyDef.WASTES_GROUPID )  &&
			  objSend.getParentID().equals( XMOPropertyDef.WASTES_GROUPID ) )
		) {
			// 移動元オブジェクトがグループの場合または
			// 移動先、移動元の両方が未所属でない場合または
			// 移動先、移動元の両方が見所属の場合は何もしない。
			return;
		}

		String strUserID = objSend.getChildID();

		// ユーザIDを元にして検索
		PeopleClient objPeople = new PeopleClient();
		objPeople.setWhereUserID( strUserID );
		objPeople.setConnectionIndex( objDataAccess.getConnectionIndex() );

		if( !objPeople.select() ) {
			throw new XMOException( objPeople.getMessageData() );
		}

		if( objPeople.next() ) {
			String strUserType = objPeople.getUserType();
			String strDeleteFlag = null;
			if( strReceiveID.equals( XMOPropertyDef.WASTES_GROUPID ) ) {
				strDeleteFlag = "1";
			}
			else {
				strDeleteFlag = "0";
			}
			// ユーザタイプがADの場合 削除フラグを更新する。
			if( strUserType.equals( XMOPropertyDef.AD_TYPE ) ) {
				// 削除フラグを更新する。
				objPeople.setDeleteFlag(strDeleteFlag);
				objPeople.setSex(objPeople.getSex());
				objPeople.setWhereUserID( strUserID );
				objPeople.setConnectionIndex( objDataAccess.getConnectionIndex() );
				// 更新処理
				if( !objPeople.update() ) {
					// 更新失敗時はエラーを投げる。
					throw new XMOException( objPeople.getMessageData() );
				}
			}
		}
	}

}
