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

//
//	XMO 共通クライアント部品
//			変更履歴
//				2004.01.08	新規作成	二條智文
//
package jp.co.ntt.lms.xmo;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.util.*;
import jp.co.ntt.lms.xmo.XMO;
import jp.co.ntt.lms.xmo.util.DebugLog;

/**
 * すべてのXMOのクライアント部品の親クラスになります。<BR>
 * 各XMOに関連したクライアント部品を作成する場合はこのクラスを継承
 * してください。
 * @author T.Nijou
 * @version 0.0.0.1 2004/01/08
 */
public class XMOClient {

	/**
	 * リモートオブジェクトをキャッシュします
	 */
	private static final Hashtable mhtbXMO = new Hashtable();

	/**
	 * サーバ側かクライアント側かを判別するためのフラグです。
	 * サーバ側で動作させる場合はこのフラグをtrueにしてください。
	 */
	private static boolean mblServer = false;

	/**
	 * クラス名を保持します
	 */
	private String mstrClassName = "";

	/**
	 * リモートオブジェクトを保持します
	 */
	private XMO mobjXMO;

	/**
	 * RMI通信リトライ回数
	 */
	private static final int RMI_RETRY_COUNT = 10;

	/**
	 * RMI通信リトライ待機時間
	 */
	private static final int RMI_RETRY_WAIT = 1000;

	/**
	 * コンストラクタです。<BR>
	 * 取得したいRMIオブジェクトの登録名を指定してください。
	 * @param strClassName 取得するRMIオブジェクトの登録名
	 */
	public XMOClient( String strClassName ) throws Exception {
		// プライベート変数にクラス名を設定
		mstrClassName = strClassName;
		synchronized( this.getClass() ) {
			// キャッシュから指定されたクラス名のリモートオブジェクトを取り出します
			XMO objXMO = (XMO)mhtbXMO.get( strClassName );
			// キャッシュに存在しない場合は作成する
			if( objXMO == null ) {
				objXMO = getXMO( strClassName );
			}
			mobjXMO = objXMO;
		}

	}

	/**
	 * XMO取得メソッド
	 */
	private XMO getXMO( String strClassName )
		throws Exception
	{
		XMO objXMO = null;
		// リモート側の場合
		if( !mblServer ) {
			try{
				// サーバ名称の取得
				Environment objEnvironment = new Environment();
				String strServerName = objEnvironment.getServerName();
				int intXmoPort = new Integer( objEnvironment.getXmoRegistryPort() ).intValue();
				Registry registry = LocateRegistry.getRegistry( strServerName, intXmoPort );

				for( int i=0; i<RMI_RETRY_COUNT; i++ ){
					try{
						objXMO = (XMO)registry.lookup( "//" + strServerName + "/" + strClassName );
						break;
					}catch( Exception ex ){
						// リトライ回数終了時
						if( i == RMI_RETRY_COUNT -1 ) {
							// 例外をスローする
							throw ex;
						}
						try{
							Thread.sleep(RMI_RETRY_WAIT);
						}
						catch(InterruptedException ex2){
						}
					}
				}
			}catch(Exception e){
				// ログ出力
				DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
				throw e;
			}
		}
		// サーバ側の場合
		else {
			objXMO = (XMO)newInstance( strClassName );
		}
		mhtbXMO.put( strClassName, objXMO );
		return objXMO;
	}

	/**
	 * 基本XMOメソッドの起動を行います。<BR>
	 * XMOのメニューリストを取得します
	 * @return Vector メニューリスト
	 * @exception Exception RMI接続に失敗した場合
	 */
	public Vector getMenuList(Hashtable htbParam)
		throws Exception
	{
		Vector vecList = new Vector();
		try {
			vecList = mobjXMO.getMenuList(htbParam);
		}
		catch(RemoteException ce)
		{
			try
			{
				// 再取得
				mobjXMO = getXMO( mstrClassName );
				vecList = mobjXMO.getMenuList(htbParam);
			}
			catch( RemoteException re ) {
				// リトライ
				for(int i = 0; i < RMI_RETRY_COUNT; i++ ) {
					try {
						vecList = mobjXMO.getMenuList(htbParam);
						break;
					}
					catch(RemoteException re2) {

						// リトライ回数が終わった場合
						if( i == RMI_RETRY_COUNT -1 ) {
							re2.printStackTrace();
						}

						try {
							Thread.sleep( RMI_RETRY_WAIT );
						}
						catch( InterruptedException ie ) {}
					}
				}
			}
			catch( Exception e )
			{
				e.printStackTrace();
			}
		}
		return vecList;
	}

	/**
	 * 基本XMOメソッドの起動を行います。<BR>
	 * XMOのメソッドリストを取得します
	 * @return Vector メソッドリスト
	 * @exception Exception RMI接続に失敗した場合
	 */
	public Vector getMethodList()
		throws Exception
	{
		Vector vecList = new Vector();
		try {
			vecList = mobjXMO.getMethodList();
		}
		catch(RemoteException ce)
		{
			try
			{
				// 再取得
				mobjXMO = getXMO( mstrClassName );
				vecList = mobjXMO.getMethodList();
			}
			catch( RemoteException re ) {
				// リトライ
				for(int i = 0; i < RMI_RETRY_COUNT; i++ ) {
					try {
						vecList = mobjXMO.getMethodList();
						break;
					}
					catch(RemoteException re2) {

						// リトライ回数が終わった場合
						if( i == RMI_RETRY_COUNT -1 ) {
							re2.printStackTrace();
						}

						try {
							Thread.sleep( RMI_RETRY_WAIT );
						}
						catch( InterruptedException ie ) {}
					}
				}
			}
			catch( Exception e )
			{
				e.printStackTrace();
			}
		}
		return vecList;
	}

	/**
	 * 基本XMOメソッドの起動を行います。<BR>
	 * デフォルトメニューのURLの取得を行います
	 * @return String デフォルトメニューのURL
	 * @exception Exception RMI接続に失敗した場合
	 */
	public MenuData getDefaultMenu()
		throws Exception
	{
		MenuData objMenu = null;
		try {
			objMenu = mobjXMO.getDefaultMenu();
		}
		catch(RemoteException ce)
		{
			try
			{
				// 再取得
				mobjXMO = getXMO( mstrClassName );
				objMenu = mobjXMO.getDefaultMenu();
			}
			catch( RemoteException re ) {
				// リトライ
				for(int i = 0; i < RMI_RETRY_COUNT; i++ ) {
					try {
						objMenu = mobjXMO.getDefaultMenu();
						break;
					}
					catch(RemoteException re2) {

						// リトライ回数が終わった場合
						if( i == RMI_RETRY_COUNT -1 ) {
							re2.printStackTrace();
						}

						try {
							Thread.sleep( RMI_RETRY_WAIT );
						}
						catch( InterruptedException ie ) {}
					}
				}
			}
			catch( Exception e )
			{
				e.printStackTrace();
			}
		}
		return objMenu;
	}

	/**
	 * 基本XMOメソッドの起動を行います。<BR>
	 * XMOメソッドの起動を行うメソッドです。
	 * @param strMethodName メソッド名
	 * @param objData メソッドのパラメータ
	 * @return Object メソッドの戻り値
	 * @exception Exception RMI接続に失敗した場合
	 */
	public Object execute( String strMethodName, Hashtable objData )
		throws Exception
	{
		Object objRec = null;
		try {
			objRec = mobjXMO.execute( strMethodName, objData );
		}
		catch(RemoteException ce)
		{
			try
			{
				// 再取得
				mobjXMO = getXMO( mstrClassName );
				objRec = mobjXMO.execute( strMethodName, objData );
			}
			catch( RemoteException re ) {
				// リトライ
				for(int i = 0; i < RMI_RETRY_COUNT; i++ ) {
					try {
						objRec = mobjXMO.execute( strMethodName, objData );
						break;
					}
					catch(RemoteException re2) {

						// リトライ回数が終わった場合
						if( i == RMI_RETRY_COUNT -1 ) {
							re2.printStackTrace();
						}

						try {
							Thread.sleep( RMI_RETRY_WAIT );
						}
						catch( InterruptedException ie ) {}
					}
				}
			}
			catch( Exception e )
			{
				e.printStackTrace();
			}
		}
		return objRec;
	}

	/**
	 * XMOの起動確認を行います
	 */
	public boolean isLaunch()
		throws Exception
	{
		boolean blLaunch = false;
		try {
			blLaunch = mobjXMO.isLaunch();
		}
		catch( RemoteException ce ) {
			try {
				// 再取得
				mobjXMO = getXMO( mstrClassName );
				blLaunch = mobjXMO.isLaunch();
			}
			catch( Exception e ) {
				e.printStackTrace();
				throw e;
			}
		}
		return blLaunch;
	}

	/**
	 * サーバ側で動作させる場合にこのメソッドを実行します
	 */
	public static void setServerSide() {
		mblServer = true;
	}

	/**
	 * クラス名よりクラスのインスタンスを取得する内部関数
	 * @param strClassName パッケージ名を含むクラス名称
	 * @return Object インスタンス化されたオブジェクト
	 * @exception Exception クラスが見つからないとき
	 */
	private static Object newInstance( String strClassName )
		throws Exception
	{
		Class c = Class.forName( strClassName );
		Object obj = c.newInstance();
		return obj;
	}

}

