/*
 * Copyright (c) 2009 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.fukurou.db;

import org.opengion.fukurou.util.AbstractObjectPool;
// import org.opengion.fukurou.db.ApplicationInfo;
import org.opengion.fukurou.system.Closer;
import org.opengion.fukurou.system.OgRuntimeException ;				// 6.4.2.0 (2016/01/29)
import static org.opengion.fukurou.system.HybsConst.CR;				// 6.1.0.0 (2014/12/26) refactoring
import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;	// 6.4.3.3 (2016/03/04)

// import java.util.Map;
// import java.util.HashMap;
import java.util.concurrent.ConcurrentMap;							// 6.4.3.3 (2016/03/04)
import java.util.concurrent.ConcurrentHashMap;
import java.util.Locale;
import java.util.Properties;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.DriverManager;
import java.sql.DatabaseMetaData;

/**
 * データベースのコネクションオブジェクトを取得する為に使用する，ファクトリクラスです。
 *
 * Connection.connection() メソッドで，Connectionオブジェクトを取得します。
 * Connection#close() メソッドで，内部的に ConnectionFactory にオブジェクトを戻す
 * 事によって,Connectionオブジェクトのプーリングを行なっています。
 *
 * コネクションオブジェクトは，プールから貸し出します。
 * つまり，貸し出し中には,プールには，オブジェクトは残っていません。
 * その状態で,コネクションオブジェクトをclose()しない場合は,オブジェクトが破棄されて,
 * 貸し出し中カウントと実際のオブジェクト数が食い違い,リソースが不足します。
 * 必ず,作成したオブジェクトは,close()メソッドを呼び出して,プールに返して下さい。
 *
 * システムリソースの USE_DB_APPLICATION_INFO=true の場合、コネクションにアプリケーション
 * 情報を追記するため、ApplicationInfoオブジェクトを使用します。
 * このオブジェクトは、jsp/common/session-init.jsp にてユーザー情報とアプリケーション
 * 情報を画面アクセスごとに設定します。
 *
 * @og.group ＤＢ/Shell制御
 * @og.rev 4.0.0.0 (2007/10/16) パッケージ移動(hayabusa/db ⇒ fukurou/db)
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public final class ConnectionFactory {
	/** 6.4.3.4 (2016/03/11) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。 */
//	private static final Map<String,ConnectionPool> CONN_MAP = new HashMap<>();		// 6.0.2.5 (2014/10/31) PMDチェック
	private static final ConcurrentMap<String,ConnectionPool> CONN_MAP = new ConcurrentHashMap<>();

	// 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
	// 4.0.0.0 (2007/10/29) 初期値をここでセットする
//	private static  String  DBID = "DEFAULT";
//	private static  ConnectionPool DEF_POOL ;
	private static  String			defDBID = "DEFAULT";					// 6.3.9.1 (2015/11/27) Variables should start with a lowercase character(PMD)
	private static  ConnectionPool	defPOOL ;								// 6.3.9.1 (2015/11/27) Variables should start with a lowercase character(PMD)

//	// 4.0.0.0 (2007/10/25) hayabusa依存を切るために追加します
//	private static final int BUFFER_MIDDLE = 200;							// 6.4.3.3 (2016/03/04) org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE 使用

	private static DatabaseConfig  dbConf;

	/**
	 *  デフォルトコンストラクターをprivateにして、
	 *  オブジェクトの生成をさせないようにする。
	 *
	 */
	private ConnectionFactory() {
		// オブジェクトの生成をさせないようにする。
	}

	/**
	 * 初期化メソッドです。
	 * <pre>
	 * １)第二引数にXMLファイルをクラスローダ基底からの相対パスで指定した場合は
	 * 　　そのXMLを利用してDBConfigオブジェクトを作成します。例：ConnectionFactory.init( CONTEXT_NAME, "../DBConfig.xml")
	 * 　　nullの場合はWEB-INF/DBConfig.xmlを利用します。例：ConnectionFactory.init( CONTEXT_NAME, null)
	 * ２)キャッシュ初期ConnectionPoolのキーを設定してキャッシュプールを作ります。
	 * 　　この値がnullの場合は"DEFAULT"が設定されます。
	 * </pre>
	 * 
	 * <strong>このクラスを利用する場合は必ず最初にこのメソッドを実行する必要があります。</strong>
	 * キャッシュとDBConfigオブジェクトの同期化はされていないので初期化以外での利用は避けて下さい。
	 *
	 * @og.rev 4.0.0.0 (2007/11/05) 新規作成
	 * @og.rev 6.4.3.3 (2016/03/04) DatabaseConfig のコンストラクター修正で、引数の nullチェックは不要。
	 *
	 * @param defPoolKey  初期DBID名(nullの場合は、"DEFAULT")
	 * @param xmlFileName DBConfig.xmlファイルのファイル名(nullの場合は、WEB-INF/DBConfig.xml)
	 */
	public static void init( final String defPoolKey, final String xmlFileName ) {
		// DBConfigオブジェクトの作成
		// 6.4.3.3 (2016/03/04) DatabaseConfig のコンストラクター修正で、引数の nullチェックは不要。
		dbConf = new DatabaseConfig( xmlFileName );
//		if( xmlFileName == null || xmlFileName.isEmpty() ) {
//			dbConf = new DatabaseConfig();
//		}
//		else {
//			dbConf = new DatabaseConfig( xmlFileName );
//		}

		if( defPoolKey == null || defPoolKey.isEmpty() || dbConf.getDbid( defPoolKey ) == null ) {
//			DBID = "DEFAULT";
			defDBID = "DEFAULT";
		}
		else {
//			DBID = defPoolKey;
			defDBID = defPoolKey;
		}
//		final EDbid edbid = dbConf.getDbid( DBID );
		final EDbid edbid = dbConf.getDbid( defDBID );
		if( edbid == null ) {
			final String errMsg = "初期化時に、指定のDBIDキーが存在しません。"
				+ "[Key ="
//				+ DBID
				+ defDBID
				+ "]";
			throw new OgRuntimeException( errMsg );
		}

	//	if( DEF_POOL != null ) { DEF_POOL.clear(); }	// 6.0.2.5 (2014/10/31) nullでなければ初期化する。
//		DEF_POOL = new ConnectionPool( edbid );
		defPOOL = new ConnectionPool( edbid );
	}

	/**
	 * コネクションオブジェクトを取得します。
	 * 遅い初期化を行なう事により,実際に必要となるまでコネクションオブジェクトは
	 * 作成しません。
	 * 最大プール数に達して,なおかつ,すべてのConnectionが貸し出し中の場合,
	 *
	 * @og.rev 2.1.1.3 (2002/11/22) コネクションID が null の場合に DEFAULT から所得するように変更。
	 * @og.rev 3.1.0.0 (2003/03/20) Hashtable を使用している箇所で、非同期でも構わない箇所を、HashMap に置換え。
	 * @og.rev 3.5.6.2 (2004/07/05) 文字列の連結にStringBuilderを使用します。
	 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
	 * @og.rev 3.8.8.2 (2007/01/26) USE_DB_APPLICATION_INFO ⇒ pool.useApplicationInfo() 変更
	 * @og.rev 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
	 * @og.rev 4.1.0.1 (2008/01/21) 登録時に、大文字に変換する。
	 * @og.rev 6.4.3.3 (2016/03/04) Map#computeIfAbsent で対応する。
	 *
	 * @param   dbid 接続先ID
	 * @param   appInfo アプリ情報オブジェクト
	 *
	 * @return  コネクションオブジェクト
	 */
	public static Connection connection( final String dbid , final ApplicationInfo appInfo ) {
		final ConnectionPool pool ;
//		if( dbid == null || dbid.isEmpty() || DBID.equalsIgnoreCase( dbid ) ) {
		if( dbid == null || dbid.isEmpty() || defDBID.equalsIgnoreCase( dbid ) ) {
//			pool = DEF_POOL ;
			pool = defPOOL ;
		}
		else {
			final String udbid = dbid.toUpperCase( Locale.JAPAN );	// 大文字化

			// 6.4.3.3 (2016/03/04) Map#computeIfAbsent で対応する。
			// Map#computeIfAbsent ： 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし
			// ※ 注意：ConnectionPool のコンストラクタに、従来と異なり、DatabaseConfig オブジェクトを渡しています。
			pool = CONN_MAP.computeIfAbsent( udbid , k -> new ConnectionPool( dbConf,udbid ) );

//			synchronized( CONN_MAP ) {
//				pool = CONN_MAP.get( udbid );
//				// 接続IDが、CONN_MAP に存在しない場合
//				if( pool == null ) {
//					final EDbid edbid = dbConf.getDbid( udbid );
//					if( edbid == null ) {
//						final String errMsg = "指定のDBIDキーが存在しません。"
//							+ "[Key ="
//							+ udbid
//							+ "]";
//						throw new OgRuntimeException( errMsg );
//					}
//					pool = new ConnectionPool( edbid );
//					CONN_MAP.put( udbid,pool );
//				}
//			}
		}

		final Connection conn = pool.newInstance();

		// 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを使用
		// 3.8.8.2 (2007/01/26) ORACLE 以外は、使用しません。
		// 4.0.0.0 (2007/11/29) 入れ子if の統合
		if( appInfo != null && pool.useApplicationInfo() ) {
			appInfo.callAppInfo( conn );
		}
		return conn;
	}

	/**
	 * コネクションオブジェクトをプールに戻します。
	 * Connectionオブジェクトは,close()メソッドで,自分自身を ConnectionFactory の
	 * プールに戻します。
	 * それ以外の コネクションオブジェクトをプールに戻す場合は,このメソッドを使用します。
	 *
	 * @og.rev 2.1.1.3 (2002/11/22) コネクションID が null の場合に DEFAULT から所得するように変更。
	 * @og.rev 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
	 * @og.rev 4.1.0.1 (2008/01/21) 登録時に、大文字に変換する。
	 *
	 * @param   conn コネクションオブジェクト
	 * @param   dbid 接続先ID
	 */
	public static void close( final Connection conn,final String dbid ) {
		if( conn != null ) {
//			if( dbid == null || dbid.isEmpty() || DBID.equalsIgnoreCase( dbid ) ) {
			if( dbid == null || dbid.isEmpty() || defDBID.equalsIgnoreCase( dbid ) ) {
//				DEF_POOL.release( conn ) ;
				defPOOL.release( conn ) ;
			}
			else {
				final String udbid = dbid.toUpperCase( Locale.JAPAN );	// 大文字化
	//			synchronized( CONN_MAP ) {
					final ConnectionPool pool = CONN_MAP.get( udbid );
					if( pool != null ) {
						pool.release( conn );
					}
	//			}
			}
		}
	}

	/**
	 * コネクションオブジェクトを物理的に削除(クローズ)戻します。
	 * これは、コネクション等がエラーを起こした場合に、プールに戻すのではなく、
	 * 接続を閉じる場合に、使用されます。
	 *
	 * @og.rev 2.1.1.3 (2002/11/22) コネクションID が null の場合に DEFAULT から所得するように変更。
	 * @og.rev 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
	 * @og.rev 4.1.0.1 (2008/01/21) 登録時に、大文字に変換する。
	 *
	 * @param   conn コネクションオブジェクト
	 * @param   dbid 接続先ID
	 */
	public static void remove( final Connection conn,final String dbid ) {
		if( conn != null ) {
//			if( dbid == null || dbid.isEmpty() || DBID.equalsIgnoreCase( dbid ) ) {
			if( dbid == null || dbid.isEmpty() || defDBID.equalsIgnoreCase( dbid ) ) {
//				DEF_POOL.remove( conn ) ;
				defPOOL.remove( conn ) ;
			}
			else {
				final String udbid = dbid.toUpperCase( Locale.JAPAN );	// 大文字化
		//		synchronized( CONN_MAP ) {
					final ConnectionPool pool = CONN_MAP.get( udbid );
					if( pool != null ) {
						pool.remove( conn );
//		//				CONN_MAP.put( udbid,pool );
					}
		//		}
			}
		}
	}

	/**
	 * コネクションオブジェクトを実際にすべてクローズします。
	 * コネクションプールの再編成や，管理者による強制クローズに使用します。
	 *
	 * クローズに失敗(コネクションが貸し出し中)の場合は,内部的に
	 * DB_CLOSE_RETRY_TIME だけ待機して, DB_CLOSE_RETRY_COUNT 回数だけ,試行します。
	 * それでもクローズできない場合は, RuntimeException を throw します。
	 *
	 * @og.rev 4.0.0.0 (2005/01/31) ロジック見直し。 pool.clear() で、基本的にはすべて削除されます。
	 * @og.rev 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
	 * @og.rev 6.4.3.3 (2016/03/04) Map#forEach で対応する。
	 */
	public static void realClose() {
//		synchronized( DEF_POOL ) {
//			if( ! DEF_POOL.isEmpty() ) {
//				DEF_POOL.clear();
//			}
//		}
		synchronized( defPOOL ) {
			if( ! defPOOL.isEmpty() ) {
				defPOOL.clear();
			}
		}

		// 6.4.3.3 (2016/03/04) Map#forEach で対応する。
		CONN_MAP.forEach( (id,pl) -> pl.clear() );
		CONN_MAP.clear();

//		final ConnectionPool[] pools ;
//		synchronized( CONN_MAP ) {
//			if( CONN_MAP.isEmpty() ) { return; }
//
//			pools = CONN_MAP.values().toArray( new ConnectionPool[CONN_MAP.size()] ) ;
//			CONN_MAP.clear();
//		}
//
//		ConnectionPool pool ;
//		for( int i=0; i<pools.length ; i++ ) {
//			pool = pools[i];
//			if( pool != null && ! pool.isEmpty() ) {
//				pool.clear();
//			}
//		}
	}

	/**
	 * ConnectionFactory の現在の状況(詳細メッセージ)を返します。
	 * これは，コネクションプールの数(最大値，作成済み数など)を確認する為のものです。
	 *
	 * @og.rev 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
	 *
	 * @return  現在の状態表示
	 * @og.rtnNotNull
	 */
	public static String information() {
		return information( true );
	}

	/**
	 * ConnectionFactory の現在の状況を返します。
	 * これは，コネクションプールの数(最大値，作成済み数など)を確認する為のものです。
	 * 引数により詳細メッセージかどうかを指定できます。
	 *
	 * @og.rev 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
	 * @og.rev 5.3.4.0 (2011/04/01) 詳細メッセージ用引数を追加
	 * @og.rev 5.6.7.3 (2013/08/23) 若干の修正
	 * @og.rev 6.4.3.3 (2016/03/04) Map#forEach で対応する。
	 *
	 * @param	isDetail	詳細メッセージかどうか [true:詳細メッセージ/false:簡易メッセージ]
	 *
	 * @return  現在の状態表示
	 * @og.rtnNotNull
	 */
	public static String information(final boolean isDetail ) {
		// 4.0.0.0 (2007/10/25) hybsとの依存関係を弱めるため。
		final StringBuilder strBuf = new StringBuilder( BUFFER_MIDDLE );

		strBuf.append( "<b>【Connection Information】</b>" ).append( CR );	// 5.6.7.3 (2013/08/23) 若干の修正

//		int rtnCnt = 0;									// 6.4.3.3 (2016/03/04) rtnCnt は、使ってない。
//		synchronized( DEF_POOL ) {
//			if( ! DEF_POOL.isEmpty() ) {
//				rtnCnt += DEF_POOL.size();
//	 			// 5.3.4.0 (2011/04/01) 詳細メッセージ用引数を追加
//				if( isDetail ) {
//					strBuf.append( DEF_POOL.toString() );
//					strBuf.append( "<br /><hr />" );
//				}
//				else {
//					strBuf.append( DEF_POOL.dbidInfo() );
//				}
//			}
//		}
		synchronized( defPOOL ) {
			if( ! defPOOL.isEmpty() ) {
//				rtnCnt += defPOOL.size();
	 			// 5.3.4.0 (2011/04/01) 詳細メッセージ用引数を追加
				if( isDetail ) {
					strBuf.append( defPOOL.toString() ).append( "<br /><hr />" );
				}
				else {
					strBuf.append( defPOOL.dbidInfo() );
				}
			}
		}

		// 6.4.3.3 (2016/03/04) Map#forEach で対応する。
		CONN_MAP.forEach( (id,pl) -> {
				if( isDetail ) {
					strBuf.append( pl.toString() ).append( "<br /><hr />" );
				}
				else {
					strBuf.append( pl.dbidInfo() );
				}
			}
		);

		return strBuf.append( CR ).toString();

//		ConnectionPool[] pools = null;
//		synchronized( CONN_MAP ) {
//			if( !CONN_MAP.isEmpty() ) {
//				pools = CONN_MAP.values().toArray( new ConnectionPool[CONN_MAP.size()] ) ;
//			}
//		}
//
//		if( pools != null ) {
//			for( int i=0; i<pools.length ; i++ ) {
//				final ConnectionPool pool = pools[i];
//				if( pool != null && ! pool.isEmpty() ) {
//					rtnCnt += pool.size();
//		 			// 5.3.4.0 (2011/04/01) 詳細メッセージ用引数を追加
//					if( isDetail ) {
//						strBuf.append( pool.toString() );
//						strBuf.append( "<br /><hr />" );
//					}
//					else {
//						strBuf.append( pool.dbidInfo() );
//					}
//				}
//			}
//		}
//
//		strBuf.append( CR );
//
//		return strBuf.toString();
	}

	/**
	 * この接続が、PreparedStatement#getParameterMetaData() を使用するかどうかを判定します。
	 *
	 * PreparedStatement に対して、String化された 数字などを setObject( int,String ) するとき、
	 * ORACLE と SQLServer は、そのまま設定すれば、自動的に変換されます。
	 * postgreSQL では、ParameterMetaData#getParameterType(int) で、カラムタイプを取得し、
	 * setObject( int,String,int ) する必要があります。
	 * その判定に、このメソッドを使用します。
	 * この結果は、あくまで、各種データベース毎の実地調査の結果を元に、判定結果を
	 * 返すようにしています。
	 * ORACLE の場合は、使用しない(false)が返るように設定しています。
	 * SQLServer では、ORACLEと同様に、false を返します。
	 *
	 * このメソッドは、元々、ApplicationInfo#useParameterMetaData(Connection) に有ったものを
	 * EDbid から取得するように修正したものです。
	 *
	 * @og.rev 5.3.8.0 (2011/08/01) 新規追加
	 * @og.rev 6.4.3.3 (2016/03/04) EDbid のnullチェックを追加
	 *
	 * @param dbid 接続先ID
	 *
	 * @return	[true:使用する/false:その他]
	 */
	public static boolean useParameterMetaData( final String dbid ) {

		// 6.1.0.0 (2014/12/26) refactoring の一環
//		final String udbid = ( dbid == null || dbid.isEmpty() ) ? DBID : dbid.toUpperCase( Locale.JAPAN ) ;
//		final String udbid = ( dbid == null || dbid.isEmpty() ) ? defDBID : dbid.toUpperCase( Locale.JAPAN ) ;
		final String udbid = dbid == null || dbid.isEmpty() ? defDBID : dbid.toUpperCase( Locale.JAPAN ) ;		// 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses.

		final EDbid edbid = dbConf.getDbid( udbid );

//		return edbid.useParamMetaData();
		return edbid != null && edbid.useParamMetaData();
	}

	/**
	 * 接続先のDB名に対応した、enum (DBName) を返します(toUpperCase)。
	 *
	 * @og.rev 5.1.4.0 (2010/03/01) getDBFullName の代わりに新規作成
	 * @og.rev 5.7.7.2 (2014/06/20) 最初の取得時のエラー回避
	 *
	 * @param dbid 接続先ID
	 *
	 * @return  接続先のDB名
	 * @og.rtnNotNull
	 */
	public static String getDBName( final String dbid ) {
		final String dbName;

//		if( dbid == null || dbid.isEmpty() || DBID.equalsIgnoreCase( dbid ) ) {
		if( dbid == null || dbid.isEmpty() || defDBID.equalsIgnoreCase( dbid ) ) {
//			dbName = DEF_POOL.getDBName();
			dbName = defPOOL.getDBName();
		}
		else {
			final String udbid = dbid.toUpperCase( Locale.JAPAN );	// 大文字化
			ConnectionPool pool = null;
	//		synchronized( CONN_MAP ) {
				pool = CONN_MAP.get( udbid );
				if( pool == null ) {
					connection( dbid, null );		// ダミーで、コネクトする。
					pool = CONN_MAP.get( udbid );	// connectionで、CONN_MAP に設定しているため、もう一度、取得する。
				}
	//		}
			// 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
			if( pool == null ) {
				final String errMsg = "指定のDBIDキーに対応するデータベース名を取得出来ません。"
									+ "[Key =" + dbid + "]";
				throw new OgRuntimeException( errMsg );
			}

//			if( pool != null ) {
				dbName = pool.getDBName();
//			}
//			else {
//				final String errMsg = "指定のDBIDキーに対応するデータベース名を取得出来ません。"
//									+ "[Key =" + dbid + "]";
//				throw new OgRuntimeException( errMsg );
//			}
		}

		return dbName.toUpperCase( Locale.JAPAN );
	}

	/**
	 * ConnectionPool は、AbstractObjectPool を継承した オブジェクトプールです。
	 *
	 * コネクションオブジェクトをプールすることにより、ConnectionFactory で
	 * 管理する Map オブジェクトの実態として、各ID毎の コネクションをキープします。
	 *
	 * @og.group ＤＢ/Shell制御
	 *
	 * @version  4.0
	 * @author   Kazuhiko Hasegawa
	 * @since    JDK5.0,
	 */
	// class ConnectionPool extends AbstractObjectPool<Connection> {
	private static final class ConnectionPool extends AbstractObjectPool<Connection> {
		private final transient EDbid edbid;

		/**
		 * DatabaseConfig と、dbid を指定して作成する コンストラクター
		 * オブジェクト作成時のMap設定で、一連の処理を行うために、エラーチェックをもつ
		 * コンストラクターを用意します。
		 * DBID が null の場合は，"DEFAULT" が使用されます。
		 *
		 * @og.rev 6.4.3.3 (2016/03/04) 処理の簡素化のための新規コンストラクター追加
		 *
		 * @param   dbConf	DatabaseConfigオブジェクト
		 * @param   dbid	接続先ID(大文字に変換済み)
		 */
		private ConnectionPool( final DatabaseConfig dbConf , final String dbid ) {
			super();

			final EDbid edbid = dbConf.getDbid( dbid );
			if( edbid == null ) {
				final String errMsg = "指定のDBIDキーが存在しません。"
					+ "[Key ="
					+ dbid
					+ "]";
				throw new OgRuntimeException( errMsg );
			}

			this.edbid	=	edbid;
			init( edbid.getMincount(),edbid.getMaxcount(),true,edbid.getPooltime() );
		}

		/**
		 * DBID を指定して作成する コンストラクター
		 * DBID をキーに､ HybsSystem.sys メソッドのデータベース変数を取得します。
		 * 取得するのは､ DBID + _DB_URL／_DB_USER／_DB_PASSWD／_DB_MINCOUNT／_DB_MAXCOUNT
		 * です。
		 * DBID が null の場合は，"DEFAULT" が使用されます。
		 *
		 * @og.rev 3.5.4.3 (2004/01/05) キャッシュの寿命を指定
		 * @og.rev 3.5.4.7 (2004/02/06) DBID のゼロストリングチェック追加
		 * @og.rev 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
		 * @og.rev 4.0.0.0 (2007/10/25) DB設定情報のXML化に伴う変更
		 *
		 * @param   edbid 接続先情報オブジェクト
		 */
		public ConnectionPool( final EDbid edbid ) {
			super();		// 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor

			// 4.0.0.0 XML化に伴いロード先を変更
			this.edbid	=	edbid;
			init( edbid.getMincount(),edbid.getMaxcount(),true,edbid.getPooltime() );
		}

		/**
		 * オブジェクトプールから削除するときに呼ばれます。
		 * このメソッドで各オブジェクトごとの終了処理を行います。
		 * 例えば､データベースコネクションであれば､close() 処理などです。
		 *
		 * @og.rev 3.5.4.8 (2004/02/23) SQLException は無視します。
		 * @og.rev 3.5.6.0 (2004/06/18) synchronized を解除します。
		 *
		 * @param  obj 終了処理を行うオブジェクト
		 */
		@Override
		protected void objectFinal( final Connection obj ) {
			Closer.connClose( obj );
		}

		/**
		 * コネクションオブジェクトを作成します。
		 * DriverManager.getConnection により作成されたConnection を Connection で
		 * ラッピングします。
		 * Connectionオブジェクトは,close()メソッドで,自分自身を ConnectionFactory の
		 * プールに戻します。
		 *
		 * @og.rev 3.3.3.3 (2003/08/06) コネクションに対して、setTransactionIsolation を、設定しておく。
		 * @og.rev 3.5.2.0 (2003/10/20) 接続情報に、データベース名、ドライバ名情報を追加する。
		 * @og.rev 3.5.6.0 (2004/06/18) synchronized を解除します。
		 * @og.rev 3.8.8.2 (2007/01/26) useAppInfo を設定します。
		 * @og.rev 4.0.0.0 (2007/10/30) 保持情報オブジェクト化に伴う変更
		 * @og.rev 5.1.2.0 (2010/01/01) MySQL対応 明示的に、TRANSACTION_READ_COMMITTED を指定する。
		 * @og.rev 5.5.2.0 (2012/05/01) properties対応
		 * @og.rev 6.3.9.0 (2015/11/06) 内部Propertiesオブジェクトではなく、複製して返します。
		 *
		 * @return  コネクションオブジェクト
		 */
		@Override
		protected Connection createInstance() {
			Connection conn = null;
			try {
		//		DriverManager.setLogWriter( HybsSystem.out );			// ドライバーのログ

				// 5.5.2.0 (2012/05/01) propertyの追加処理と、接続のproperties化
				// 6.3.9.0 (2015/11/06) 内部Propertiesオブジェクトではなく、複製して返します。
	//			final Properties prop = new Properties (edbid.getProps());
				final Properties prop = edbid.getProps();
				prop.put ( "user"    , edbid.getUser() );
				prop.put ( "password", edbid.getPassword() );

				conn = DriverManager.getConnection( edbid.getUrl(), prop );
		//		conn.setReadOnly( true );
				conn.setReadOnly( edbid.isReadonly() );

				conn.setAutoCommit( false );
				conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);  // 初期値
		//		((OracleConnection)conn).setDefaultExecuteBatch(1);  // 初期値
		//		((OracleConnection)conn).setDefaultRowPrefetch(20);  // 初期値

				// 3.5.2.0 (2003/10/20) 接続情報に、データベース名、ドライバ名情報を追加する。
				// 4.0.0.0 (2007/10/26) 登録先をオブジェクト化
				if( edbid.getDbProductName() == null ) {
					final DatabaseMetaData meta = conn.getMetaData();
					edbid.setMetaDataInfo( meta );
				}
				return conn ;
			}
			catch( final SQLException ex ) {
				final String errMsg = "コネクトすることが出来ません。"	+ CR
								+ "DBID=[" + edbid.getDbidKey() + "]"	+ CR
								+ ex.getMessage() + " , status=" + ex.getSQLState();
				Closer.connClose( conn );
				throw new OgRuntimeException( errMsg,ex );		// 3.5.5.4 (2004/04/15) 引数の並び順変更
			}
		}

		/**
		 * アクセスログ取得の為のDBMS_APPLICATION_INFOの使用可否を取得します(初期値:true)。
		 *
		 * データベースへのアクセスログ取得の為、エンジンで接続するコネクションについて
		 * DBMS_APPLICATION_INFO.SET_CLIENT_INFO と SET_MODULE を呼び出しています。
		 * この処理は、ORACLEとの接続のみ有効ですので、接続先データベースが ORACLE 以外は
		 * false を返します。
		 * ORACLE の場合は、システムリソースの USE_DB_APPLICATION_INFO 属性の設定値を
		 * 返します。
		 * この設定値の初期値は、true です。
		 *
		 * @og.rev 3.8.8.2 (2007/01/26) 新規追加
		 *
		 * @return  true:使用する/false:使用しない
		 */
		public boolean useApplicationInfo() {
			return edbid.isApplicationInfo();
		}

		/**
		 * 接続先のDB名を返します。
		 *
		 * @og.rev 4.3.7.0 (2009/06/01) 新規作成
		 *
		 * @return  接続先のDB名
		 */
		public String getDBName() {
			return edbid.getDbProductName();
		}

		/**
		 * 接続先のDBバージョンを返します。
		 *
		 * @og.rev 4.3.7.0 (2009/06/01) 新規作成
		 *
		 * @return 接続先のDBバージョン
		 */
		public String getDBVersion() {
			return edbid.getDbProductVersion();
		}

		/**
		 * 接続先の簡易な内部情報を返します。
		 *
		 * @og.rev 5.3.4.0 (2011/04/01) toString() の簡易版
		 *
		 * @return 接続先の簡易な内部情報
		 */
		public String dbidInfo() {
			return edbid.info();
		}

		/**
		 * 内部状況を簡易的に表現した文字列を返します。
		 * DBID／URL／USER／プールサイズ を返します。
		 *
		 * @og.rev 3.5.2.0 (2003/10/20) 接続情報に、データベース名、ドライバ名情報を追加する。
		 * @og.rev 3.5.6.6 (2004/08/23) 同期化方法を統一する為、synchronized をつけます。(別途 要検討)
		 * @og.rev 4.0.0.0 (2007/10/29) EDbidのtoStringを呼ぶように変更
		 *
		 * @return   このオブジェクトプールの文字列表現
		 * @og.rtnNotNull
		 */
		@Override
		public String toString() {
			return edbid.toString() + super.toString() ;
		}
	}
}
