    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *     http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.fukurou.db;
    017
    018import org.opengion.fukurou.util.AbstractObjectPool;
    019import org.opengion.fukurou.system.Closer;
    020import org.opengion.fukurou.system.OgRuntimeException ;                         // 6.4.2.0 (2016/01/29)
    021import static org.opengion.fukurou.system.HybsConst.CR;                         // 6.1.0.0 (2014/12/26) refactoring
    022import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.4.3.3 (2016/03/04)
    023
    024        // import java.util.concurrent.ExecutorService;                                 // 7.1.0.0 (2020/01/20)
    025        // import java.util.concurrent.Executors;                                               // 7.1.0.0 (2020/01/20)
    026        // import java.util.concurrent.Future;                                                  // 7.1.0.0 (2020/01/20)
    027        // import java.util.concurrent.Callable;                                                // 7.1.0.0 (2020/01/20)
    028        // import java.util.concurrent.TimeUnit;                                                // 7.1.0.0 (2020/01/20)
    029        // import java.util.concurrent.ExecutionException;                              // 7.1.0.0 (2020/01/20)
    030        // import java.util.concurrent.TimeoutException;                                // 7.1.0.0 (2020/01/20)
    031        // import java.util.concurrent.CancellationException;                   // 7.1.0.0 (2020/01/20)
    032import java.util.concurrent.ConcurrentMap;                                                      // 6.4.3.3 (2016/03/04)
    033import java.util.concurrent.ConcurrentHashMap;
    034import java.util.Locale;
    035import java.util.Properties;
    036import java.sql.Connection;
    037import java.sql.SQLException;
    038import java.sql.DriverManager;
    039import java.sql.DatabaseMetaData;
    040
    041/**
    042 * データベースのコネクションオブジェクトを取得する為に使用する，ファクトリクラスです。
    043 *
    044 * Connection.connection() メソッドで，Connectionオブジェクトを取得します。
    045 * Connection#close() メソッドで，内部的に ConnectionFactory にオブジェクトを戻す
    046 * 事によって,Connectionオブジェクトのプーリングを行なっています。
    047 *
    048 * コネクションオブジェクトは，プールから貸し出します。
    049 * つまり，貸し出し中には,プールには，オブジェクトは残っていません。
    050 * その状態で,コネクションオブジェクトをclose()しない場合は,オブジェクトが破棄されて,
    051 * 貸し出し中カウントと実際のオブジェクト数が食い違い,リソースが不足します。
    052 * 必ず,作成したオブジェクトは,close()メソッドを呼び出して,プールに返して下さい。
    053 *
    054 * システムリソースの USE_DB_APPLICATION_INFO=true の場合、コネクションにアプリケーション
    055 * 情報を追記するため、ApplicationInfoオブジェクトを使用します。
    056 * このオブジェクトは、jsp/common/session-init.jsp にてユーザー情報とアプリケーション
    057 * 情報を画面アクセスごとに設定します。
    058 *
    059 * @og.group ＤＢ/Shell制御
    060 * @og.rev 4.0.0.0 (2007/10/16) パッケージ移動(hayabusa/db ⇒ fukurou/db)
    061 *
    062 * @version  4.0
    063 * @author   Kazuhiko Hasegawa
    064 * @since    JDK5.0,
    065 */
    066public final class ConnectionFactory {
    067        /** 6.4.3.4 (2016/03/11) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。 */
    068        private static final ConcurrentMap<String,ConnectionPool> CONN_MAP = new ConcurrentHashMap<>();
    069
    070        // 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
    071        // 4.0.0.0 (2007/10/29) 初期値をここでセットする
    072        private static String                   defDBID = "DEFAULT";                                    // 6.3.9.1 (2015/11/27) Variables should start with a lowercase character(PMD)
    073        private static ConnectionPool   defPOOL ;                                                               // 6.3.9.1 (2015/11/27) Variables should start with a lowercase character(PMD)
    074        private static DatabaseConfig   dbConf ;
    075
    076        /**
    077         *  デフォルトコンストラクターをprivateにして、
    078         *  オブジェクトの生成をさせないようにする。
    079         *
    080         */
    081        private ConnectionFactory() {
    082                // オブジェクトの生成をさせないようにする。
    083        }
    084
    085        /**
    086         * 初期化メソッドです。
    087         * <pre>
    088         * １)第二引数にXMLファイルをクラスローダ基底からの相対パスで指定した場合は
    089         * 　　そのXMLを利用してDBConfigオブジェクトを作成します。例：ConnectionFactory.init( CONTEXT_NAME, "../DBConfig.xml")
    090         * 　　nullの場合はWEB-INF/DBConfig.xmlを利用します。例：ConnectionFactory.init( CONTEXT_NAME, null)
    091         * ２)キャッシュ初期ConnectionPoolのキーを設定してキャッシュプールを作ります。
    092         * 　　この値がnullの場合は"DEFAULT"が設定されます。
    093         * </pre>
    094         *
    095         * <strong>このクラスを利用する場合は必ず最初にこのメソッドを実行する必要があります。</strong>
    096         * キャッシュとDBConfigオブジェクトの同期化はされていないので初期化以外での利用は避けて下さい。
    097         *
    098         * @og.rev 4.0.0.0 (2007/11/05) 新規作成
    099         * @og.rev 6.4.3.3 (2016/03/04) DatabaseConfig のコンストラクター修正で、引数の nullチェックは不要。
    100         * @og.rev 7.1.0.0 (2020/01/20) #ConnectionPool(DatabaseConfig,String) に統一
    101         *
    102         * @param defPoolKey  初期DBID名(nullの場合は、"DEFAULT")
    103         * @param xmlFileName DBConfig.xmlファイルのファイル名(nullの場合は、WEB-INF/DBConfig.xml)
    104         */
    105        public static void init( final String defPoolKey, final String xmlFileName ) {
    106                // DBConfigオブジェクトの作成
    107                // 6.4.3.3 (2016/03/04) DatabaseConfig のコンストラクター修正で、引数の nullチェックは不要。
    108                dbConf = new DatabaseConfig( xmlFileName );
    109
    110                if( defPoolKey == null || defPoolKey.isEmpty() || dbConf.getDbid( defPoolKey ) == null ) {
    111                        defDBID = "DEFAULT";
    112                }
    113                else {
    114                        defDBID = defPoolKey;
    115                }
    116
    117                defPOOL = new ConnectionPool( dbConf,defDBID );         // 7.1.0.0 (2020/01/20)
    118//
    119//              final EDbid edbid = dbConf.getDbid( defDBID );
    120//              if( edbid == null ) {
    121//                      final String errMsg = "初期化時に、指定のDBIDキーが存在しません。"
    122//                              + "[Key ="
    123//                              + defDBID
    124//                              + "]";
    125//                      throw new OgRuntimeException( errMsg );
    126//              }
    127//
    128//      //      if( DEF_POOL != null ) { DEF_POOL.clear(); }    // 6.0.2.5 (2014/10/31) nullでなければ初期化する。
    129//              defPOOL = new ConnectionPool( edbid );
    130        }
    131
    132        /**
    133         * コネクションオブジェクトを取得します。
    134         * 遅い初期化を行なう事により,実際に必要となるまでコネクションオブジェクトは
    135         * 作成しません。
    136         * 最大プール数に達して,なおかつ,すべてのConnectionが貸し出し中の場合,
    137         *
    138         * @og.rev 2.1.1.3 (2002/11/22) コネクションID が null の場合に DEFAULT から所得するように変更。
    139         * @og.rev 3.1.0.0 (2003/03/20) Hashtable を使用している箇所で、非同期でも構わない箇所を、HashMap に置換え。
    140         * @og.rev 3.5.6.2 (2004/07/05) 文字列の連結にStringBuilderを使用します。
    141         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
    142         * @og.rev 3.8.8.2 (2007/01/26) USE_DB_APPLICATION_INFO ⇒ pool.useApplicationInfo() 変更
    143         * @og.rev 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
    144         * @og.rev 4.1.0.1 (2008/01/21) 登録時に、大文字に変換する。
    145         * @og.rev 6.4.3.3 (2016/03/04) Map#computeIfAbsent で対応する。
    146         *
    147         * @param   dbid 接続先ID
    148         * @param   appInfo アプリ情報オブジェクト
    149         *
    150         * @return  コネクションオブジェクト
    151         */
    152        public static Connection connection( final String dbid , final ApplicationInfo appInfo ) {
    153                final ConnectionPool pool ;
    154                if( dbid == null || dbid.isEmpty() || defDBID.equalsIgnoreCase( dbid ) ) {
    155                        pool = defPOOL ;
    156                }
    157                else {
    158                        final String udbid = dbid.toUpperCase( Locale.JAPAN );  // 大文字化
    159
    160                        // 6.4.3.3 (2016/03/04) Map#computeIfAbsent で対応する。
    161                        // Map#computeIfAbsent ： 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし
    162                        // ※ 注意：ConnectionPool のコンストラクタに、従来と異なり、DatabaseConfig オブジェクトを渡しています。
    163                        pool = CONN_MAP.computeIfAbsent( udbid , k -> new ConnectionPool( dbConf,udbid ) );
    164                }
    165
    166                final Connection conn = pool.newInstance();
    167
    168                // 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを使用
    169                // 3.8.8.2 (2007/01/26) ORACLE 以外は、使用しません。
    170                // 4.0.0.0 (2007/11/29) 入れ子if の統合
    171                if( appInfo != null && pool.useApplicationInfo() ) {
    172                        appInfo.callAppInfo( conn );
    173                }
    174                return conn;
    175        }
    176
    177        /**
    178         * コネクションオブジェクトをプールに戻します。
    179         * Connectionオブジェクトは,close()メソッドで,自分自身を ConnectionFactory の
    180         * プールに戻します。
    181         * それ以外の コネクションオブジェクトをプールに戻す場合は,このメソッドを使用します。
    182         *
    183         * @og.rev 2.1.1.3 (2002/11/22) コネクションID が null の場合に DEFAULT から所得するように変更。
    184         * @og.rev 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
    185         * @og.rev 4.1.0.1 (2008/01/21) 登録時に、大文字に変換する。
    186         * @og.rev 5.9.32.0 (2018/05/18) プールに戻す前に明示的にcommitをかける
    187         *
    188         * @param   conn コネクションオブジェクト
    189         * @param   dbid 接続先ID
    190         */
    191        public static void close( final Connection conn,final String dbid ) {
    192                if( conn != null ) {
    193                        Closer.commit( conn );  // 5.9.32.0 (2018/05/18) プールに戻す前に明示的にcommitをかける
    194                        if( dbid == null || dbid.isEmpty() || defDBID.equalsIgnoreCase( dbid ) ) {
    195                                defPOOL.release( conn ) ;
    196                        }
    197                        else {
    198                                final String udbid = dbid.toUpperCase( Locale.JAPAN );  // 大文字化
    199        //                      synchronized( CONN_MAP ) {
    200                                        final ConnectionPool pool = CONN_MAP.get( udbid );
    201                                        if( pool != null ) {
    202                                                pool.release( conn );
    203                                        }
    204        //                      }
    205                        }
    206                }
    207        }
    208
    209        /**
    210         * コネクションオブジェクトを物理的に削除(クローズ)戻します。
    211         * これは、コネクション等がエラーを起こした場合に、プールに戻すのではなく、
    212         * 接続を閉じる場合に、使用されます。
    213         *
    214         * @og.rev 2.1.1.3 (2002/11/22) コネクションID が null の場合に DEFAULT から所得するように変更。
    215         * @og.rev 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
    216         * @og.rev 4.1.0.1 (2008/01/21) 登録時に、大文字に変換する。
    217         *
    218         * @param   conn コネクションオブジェクト
    219         * @param   dbid 接続先ID
    220         */
    221        public static void remove( final Connection conn,final String dbid ) {
    222                if( conn != null ) {
    223                        if( dbid == null || dbid.isEmpty() || defDBID.equalsIgnoreCase( dbid ) ) {
    224                                defPOOL.remove( conn ) ;
    225                        }
    226                        else {
    227                                final String udbid = dbid.toUpperCase( Locale.JAPAN );  // 大文字化
    228                //              synchronized( CONN_MAP ) {
    229                                        final ConnectionPool pool = CONN_MAP.get( udbid );
    230                                        if( pool != null ) {
    231                                                pool.remove( conn );
    232                                        }
    233                //              }
    234                        }
    235                }
    236        }
    237
    238        /**
    239         * コネクションオブジェクトを実際にすべてクローズします。
    240         * コネクションプールの再編成や，管理者による強制クローズに使用します。
    241         *
    242         * クローズに失敗(コネクションが貸し出し中)の場合は,内部的に
    243         * DB_CLOSE_RETRY_TIME だけ待機して, DB_CLOSE_RETRY_COUNT 回数だけ,試行します。
    244         * それでもクローズできない場合は, RuntimeException を throw します。
    245         *
    246         * @og.rev 4.0.0.0 (2005/01/31) ロジック見直し。 pool.clear() で、基本的にはすべて削除されます。
    247         * @og.rev 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
    248         * @og.rev 6.4.3.3 (2016/03/04) Map#forEach で対応する。
    249         */
    250        public static void realClose() {
    251                synchronized( defPOOL ) {
    252                        if( ! defPOOL.isEmpty() ) {
    253                                defPOOL.clear();
    254                        }
    255                }
    256
    257                // 6.4.3.3 (2016/03/04) Map#forEach で対応する。
    258                CONN_MAP.forEach( (id,pl) -> pl.clear() );
    259                CONN_MAP.clear();
    260        }
    261
    262        /**
    263         * ConnectionFactory の現在の状況(詳細メッセージ)を返します。
    264         * これは，コネクションプールの数(最大値，作成済み数など)を確認する為のものです。
    265         *
    266         * @og.rev 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
    267         *
    268         * @return  現在の状態表示
    269         * @og.rtnNotNull
    270         */
    271        public static String information() {
    272                return information( true );
    273        }
    274
    275        /**
    276         * ConnectionFactory の現在の状況を返します。
    277         * これは，コネクションプールの数(最大値，作成済み数など)を確認する為のものです。
    278         * 引数により詳細メッセージかどうかを指定できます。
    279         *
    280         * @og.rev 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
    281         * @og.rev 5.3.4.0 (2011/04/01) 詳細メッセージ用引数を追加
    282         * @og.rev 5.6.7.3 (2013/08/23) 若干の修正
    283         * @og.rev 6.4.3.3 (2016/03/04) Map#forEach で対応する。
    284         * @og.rev 7.0.1.0 (2018/10/15) XHTML → HTML5 対応(空要素の、"／＞" 止めを、"＞" に変更します)。
    285         * @og.rev 7.1.0.0 (2020/01/20) DB未接続のDBIDは表示から除外します。
    286         *
    287         * @param       isDetail        詳細メッセージかどうか [true:詳細メッセージ/false:簡易メッセージ]
    288         *
    289         * @return  現在の状態表示
    290         * @og.rtnNotNull
    291         */
    292        public static String information(final boolean isDetail ) {
    293                // 4.0.0.0 (2007/10/25) hybsとの依存関係を弱めるため。
    294                final StringBuilder strBuf = new StringBuilder( BUFFER_MIDDLE );
    295
    296                strBuf.append( "<b>【Connection Information】</b>" ).append( CR );        // 5.6.7.3 (2013/08/23) 若干の修正
    297
    298                synchronized( defPOOL ) {
    299                        if( ! defPOOL.isEmpty() ) {
    300                                // 5.3.4.0 (2011/04/01) 詳細メッセージ用引数を追加
    301                                if( isDetail ) {
    302//                                      strBuf.append( defPOOL.toString() ).append( "<br /><hr />" );
    303                                        strBuf.append( defPOOL.toString() ).append( "<br><hr>" );               // 7.0.1.0 (2018/10/15)
    304                                }
    305                                else {
    306                                        strBuf.append( defPOOL.dbidInfo() );
    307                                }
    308                        }
    309                }
    310
    311                // 6.4.3.3 (2016/03/04) Map#forEach で対応する。
    312                CONN_MAP.forEach( (id,pl) -> {
    313                        if( pl.getDBName() != null ) {                  // 7.1.0.0 (2020/01/20) DB未接続のDBIDは表示から除外
    314                                if( isDetail ) {
    315//                                      strBuf.append( pl.toString() ).append( "<br /><hr />" );
    316                                        strBuf.append( pl.toString() ).append( "<br><hr>" );                    // 7.0.1.0 (2018/10/15)
    317                                }
    318                                else {
    319                                        strBuf.append( pl.dbidInfo() );
    320                                }
    321                        }
    322                } );
    323
    324                return strBuf.append( CR ).toString();
    325        }
    326
    327        /**
    328         * この接続が、PreparedStatement#getParameterMetaData() を使用するかどうかを判定します。
    329         *
    330         * PreparedStatement に対して、String化された 数字などを setObject( int,String ) するとき、
    331         * ORACLE と SQLServer は、そのまま設定すれば、自動的に変換されます。
    332         * postgreSQL では、ParameterMetaData#getParameterType(int) で、カラムタイプを取得し、
    333         * setObject( int,String,int ) する必要があります。
    334         * その判定に、このメソッドを使用します。
    335         * この結果は、あくまで、各種データベース毎の実地調査の結果を元に、判定結果を
    336         * 返すようにしています。
    337         * ORACLE の場合は、使用しない(false)が返るように設定しています。
    338         * SQLServer では、ORACLEと同様に、false を返します。
    339         *
    340         * このメソッドは、元々、ApplicationInfo#useParameterMetaData(Connection) に有ったものを
    341         * EDbid から取得するように修正したものです。
    342         *
    343         * @og.rev 5.3.8.0 (2011/08/01) 新規追加
    344         * @og.rev 6.4.3.3 (2016/03/04) EDbid のnullチェックを追加
    345         *
    346         * @param dbid 接続先ID
    347         *
    348         * @return      [true:使用する/false:その他]
    349         */
    350        public static boolean useParameterMetaData( final String dbid ) {
    351
    352                // 6.1.0.0 (2014/12/26) refactoring の一環
    353                final String udbid = dbid == null || dbid.isEmpty() ? defDBID : dbid.toUpperCase( Locale.JAPAN ) ;              // 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses.
    354
    355                final EDbid edbid = dbConf.getDbid( udbid );
    356
    357                return edbid != null && edbid.useParamMetaData();
    358        }
    359
    360        /**
    361         * 接続先のDB名に対応した、enum (DBName) を返します(toUpperCase)。
    362         *
    363         * @og.rev 5.1.4.0 (2010/03/01) getDBFullName の代わりに新規作成
    364         * @og.rev 5.7.7.2 (2014/06/20) 最初の取得時のエラー回避
    365         *
    366         * @param dbid 接続先ID
    367         *
    368         * @return  接続先のDB名
    369         * @og.rtnNotNull
    370         */
    371        public static String getDBName( final String dbid ) {
    372                final String dbName;
    373
    374                if( dbid == null || dbid.isEmpty() || defDBID.equalsIgnoreCase( dbid ) ) {
    375                        dbName = defPOOL.getDBName();
    376                }
    377                else {
    378                        final String udbid = dbid.toUpperCase( Locale.JAPAN );  // 大文字化
    379                        ConnectionPool pool = null;
    380        //              synchronized( CONN_MAP ) {
    381                                pool = CONN_MAP.get( udbid );
    382                                if( pool == null ) {
    383                                        connection( dbid, null );               // ダミーで、コネクトする。
    384                                        pool = CONN_MAP.get( udbid );   // connectionで、CONN_MAP に設定しているため、もう一度、取得する。
    385                                }
    386        //              }
    387                        // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
    388                        if( pool == null ) {
    389                                final String errMsg = "指定のDBIDキーに対応するデータベース名を取得出来ません。"
    390                                                                        + "[Key =" + dbid + "]";
    391                                throw new OgRuntimeException( errMsg );
    392                        }
    393
    394                        dbName = pool.getDBName();
    395                }
    396
    397                return dbName.toUpperCase( Locale.JAPAN );
    398        }
    399
    400        /**
    401         * ConnectionPool は、AbstractObjectPool を継承した オブジェクトプールです。
    402         *
    403         * コネクションオブジェクトをプールすることにより、ConnectionFactory で
    404         * 管理する Map オブジェクトの実態として、各ID毎の コネクションをキープします。
    405         *
    406         * @og.rev 7.1.0.0 (2020/01/20) Connection 作成時のﾀｲﾑｱｳﾄを用意します。
    407         *
    408         * @og.group ＤＢ/Shell制御
    409         *
    410         * @version  4.0
    411         * @author   Kazuhiko Hasegawa
    412         * @since    JDK5.0,
    413         */
    414        // class ConnectionPool extends AbstractObjectPool<Connection> {
    415        private static final class ConnectionPool extends AbstractObjectPool<Connection> {
    416                private final transient EDbid edbid;
    417                private final static    int   TIMEOUT = 10;                             // 7.1.0.0 (2020/01/20)
    418
    419                /**
    420                 * DatabaseConfig と、dbid を指定して作成する コンストラクター
    421                 * オブジェクト作成時のMap設定で、一連の処理を行うために、エラーチェックをもつ
    422                 * コンストラクターを用意します。
    423                 * DBID が null の場合は，"DEFAULT" が使用されます。
    424                 *
    425                 * @og.rev 6.4.3.3 (2016/03/04) 処理の簡素化のための新規コンストラクター追加
    426                 *
    427                 * @param   dbConf      DatabaseConfigオブジェクト
    428                 * @param   dbid        接続先ID(大文字に変換済み)
    429                 */
    430                private ConnectionPool( final DatabaseConfig dbConf , final String dbid ) {
    431                        super();
    432
    433                        final EDbid edbid = dbConf.getDbid( dbid );
    434                        if( edbid == null ) {
    435                                final String errMsg = "指定のDBIDキーが存在しません。"
    436                                        + "[Key ="
    437                                        + dbid
    438                                        + "]";
    439                                throw new OgRuntimeException( errMsg );
    440                        }
    441
    442                        this.edbid      =       edbid;
    443                        init( edbid.getMincount(),edbid.getMaxcount(),true,edbid.getPooltime() );
    444                }
    445
    446//              /**
    447//               * DBID を指定して作成する コンストラクター
    448//               * DBID をキーに､ HybsSystem.sys メソッドのデータベース変数を取得します。
    449//               * 取得するのは､ DBID + _DB_URL／_DB_USER／_DB_PASSWD／_DB_MINCOUNT／_DB_MAXCOUNT
    450//               * です。
    451//               * DBID が null の場合は，"DEFAULT" が使用されます。
    452//               *
    453//               * @og.rev 3.5.4.3 (2004/01/05) キャッシュの寿命を指定
    454//               * @og.rev 3.5.4.7 (2004/02/06) DBID のゼロストリングチェック追加
    455//               * @og.rev 4.0.0.0 (2007/10/10) キャッシュされた、初期ConnectionPool を使用
    456//               * @og.rev 4.0.0.0 (2007/10/25) DB設定情報のXML化に伴う変更
    457//               * @og.rev 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor
    458//               * @og.rev 7.1.0.0 (2020/01/20) #ConnectionPool(DatabaseConfig,String) に統一
    459//               *
    460//               * @param   edbid 接続先情報オブジェクト
    461//               */
    462//              public ConnectionPool( final EDbid edbid ) {
    463//                      super();
    464//
    465//                      // 4.0.0.0 XML化に伴いロード先を変更
    466//                      this.edbid      =       edbid;
    467//                      init( edbid.getMincount(),edbid.getMaxcount(),true,edbid.getPooltime() );
    468//              }
    469
    470                /**
    471                 * オブジェクトプールから削除するときに呼ばれます。
    472                 * このメソッドで各オブジェクトごとの終了処理を行います。
    473                 * 例えば､データベースコネクションであれば､close() 処理などです。
    474                 *
    475                 * @og.rev 3.5.4.8 (2004/02/23) SQLException は無視します。
    476                 * @og.rev 3.5.6.0 (2004/06/18) synchronized を解除します。
    477                 *
    478                 * @param  obj 終了処理を行うオブジェクト
    479                 */
    480                @Override
    481                protected void objectFinal( final Connection obj ) {
    482                        Closer.connClose( obj );
    483                }
    484
    485                /**
    486                 * コネクションオブジェクトを作成します。
    487                 * DriverManager.getConnection により作成されたConnection を Connection で
    488                 * ラッピングします。
    489                 * Connectionオブジェクトは,close()メソッドで,自分自身を ConnectionFactory の
    490                 * プールに戻します。
    491                 *
    492                 * @og.rev 3.3.3.3 (2003/08/06) コネクションに対して、setTransactionIsolation を、設定しておく。
    493                 * @og.rev 3.5.2.0 (2003/10/20) 接続情報に、データベース名、ドライバ名情報を追加する。
    494                 * @og.rev 3.5.6.0 (2004/06/18) synchronized を解除します。
    495                 * @og.rev 3.8.8.2 (2007/01/26) useAppInfo を設定します。
    496                 * @og.rev 4.0.0.0 (2007/10/30) 保持情報オブジェクト化に伴う変更
    497                 * @og.rev 5.1.2.0 (2010/01/01) MySQL対応 明示的に、TRANSACTION_READ_COMMITTED を指定する。
    498                 * @og.rev 5.5.2.0 (2012/05/01) properties対応
    499                 * @og.rev 6.3.9.0 (2015/11/06) 内部Propertiesオブジェクトではなく、複製して返します。
    500                 * @og.rev 7.1.0.0 (2020/01/20) Connection 作成時のﾀｲﾑｱｳﾄを用意します。
    501                 *
    502                 * @return  コネクションオブジェクト
    503                 */
    504                @Override
    505                protected Connection createInstance() {
    506                        Connection conn = null;
    507                        try {
    508                //              DriverManager.setLogWriter( HybsSystem.out );                   // ドライバーのログ
    509
    510                                // 5.5.2.0 (2012/05/01) propertyの追加処理と、接続のproperties化
    511                                // 6.3.9.0 (2015/11/06) 内部Propertiesオブジェクトではなく、複製して返します。
    512        //                      final Properties prop = new Properties (edbid.getProps());
    513                                final Properties prop = edbid.getProps();
    514                                prop.put ( "user"    , edbid.getUser() );
    515                                prop.put ( "password", edbid.getPassword() );
    516
    517                                // 7.1.0.0 (2020/01/20) Connection 作成時のﾀｲﾑｱｳﾄを用意します。
    518        //                      if( TIMEOUT > 0 ) {
    519        //                              DriverManager.setLoginTimeout( TIMEOUT );
    520        //                              // このExecutorService はConnection を取得する一発物なので、シャットダウンしておく。
    521        //                              final ExecutorService executor = Executors.newSingleThreadExecutor();           // 7.1.0.0 (2020/01/20)
    522        //                              final Future<Connection> future = executor.submit(
    523        //                                      new Callable<Connection>() {
    524        //                                              @Override
    525        //                                              public Connection call() throws SQLException {
    526        //                                                      return DriverManager.getConnection( edbid.getUrl(), prop );
    527        //                                              }
    528        //                                      }
    529        //                              );
    530        //                              try {
    531        //                                      conn = future.get( TIMEOUT, TimeUnit.SECONDS );
    532        //                              }
    533        //                              finally {
    534        //                                      executor.shutdown();                    // 正常なシャットダウン
    535        //                              }
    536        //                      }
    537        //                      else {
    538                                        DriverManager.setLoginTimeout( TIMEOUT );                                                                       // 7.1.0.0 (2020/01/20)
    539                                        conn = DriverManager.getConnection( edbid.getUrl(), prop );
    540        //                      }
    541
    542//                              conn = DriverManager.getConnection( edbid.getUrl(), prop );
    543                //              conn.setReadOnly( true );
    544                                conn.setReadOnly( edbid.isReadonly() );
    545
    546                                conn.setAutoCommit( false );
    547                                conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);  // 初期値
    548                //              ((OracleConnection)conn).setDefaultExecuteBatch(1);  // 初期値
    549                //              ((OracleConnection)conn).setDefaultRowPrefetch(20);  // 初期値
    550
    551                                // 3.5.2.0 (2003/10/20) 接続情報に、データベース名、ドライバ名情報を追加する。
    552                                // 4.0.0.0 (2007/10/26) 登録先をオブジェクト化
    553                                if( edbid.getDbProductName() == null ) {
    554                                        final DatabaseMetaData meta = conn.getMetaData();
    555                                        edbid.setMetaDataInfo( meta );
    556                                }
    557                                return conn ;
    558                        }
    559                        catch( final SQLException ex ) {
    560                                final String errMsg = "コネクトすることが出来ません。" + CR
    561                                                                + "DBID=[" + edbid.getDbidKey() + "]"   + CR
    562                                                                + ex.getMessage() + " , status=" + ex.getSQLState();
    563                                Closer.connClose( conn );
    564                                throw new OgRuntimeException( errMsg,ex );              // 3.5.5.4 (2004/04/15) 引数の並び順変更
    565                        }
    566        //              catch( final InterruptedException | TimeoutException | CancellationException | ExecutionException ex ) {
    567        //                      final String errMsg = "コネクト時にタイムアウトが発生しました。"    + CR
    568        //                                                      + "DBID=[" + edbid.getDbidKey() + "]" ;
    569        //                      Closer.connClose( conn );
    570        //                      throw new OgRuntimeException( errMsg,ex );
    571        //              }
    572                }
    573
    574                /**
    575                 * アクセスログ取得の為のDBMS_APPLICATION_INFOの使用可否を取得します(初期値:true)。
    576                 *
    577                 * データベースへのアクセスログ取得の為、エンジンで接続するコネクションについて
    578                 * DBMS_APPLICATION_INFO.SET_CLIENT_INFO と SET_MODULE を呼び出しています。
    579                 * この処理は、ORACLEとの接続のみ有効ですので、接続先データベースが ORACLE 以外は
    580                 * false を返します。
    581                 * ORACLE の場合は、システムリソースの USE_DB_APPLICATION_INFO 属性の設定値を
    582                 * 返します。
    583                 * この設定値の初期値は、true です。
    584                 *
    585                 * @og.rev 3.8.8.2 (2007/01/26) 新規追加
    586                 *
    587                 * @return  true:使用する/false:使用しない
    588                 */
    589                public boolean useApplicationInfo() {
    590                        return edbid.isApplicationInfo();
    591                }
    592
    593                /**
    594                 * 接続先のDB名を返します。
    595                 *
    596                 * @og.rev 4.3.7.0 (2009/06/01) 新規作成
    597                 *
    598                 * @return  接続先のDB名
    599                 */
    600                public String getDBName() {
    601                        return edbid.getDbProductName();
    602                }
    603
    604                /**
    605                 * 接続先のDBバージョンを返します。
    606                 *
    607                 * @og.rev 4.3.7.0 (2009/06/01) 新規作成
    608                 *
    609                 * @return 接続先のDBバージョン
    610                 */
    611                public String getDBVersion() {
    612                        return edbid.getDbProductVersion();
    613                }
    614
    615                /**
    616                 * 接続先の簡易な内部情報を返します。
    617                 *
    618                 * @og.rev 5.3.4.0 (2011/04/01) toString() の簡易版
    619                 *
    620                 * @return 接続先の簡易な内部情報
    621                 */
    622                public String dbidInfo() {
    623                        return edbid.info();
    624                }
    625
    626                /**
    627                 * 内部状況を簡易的に表現した文字列を返します。
    628                 * DBID／URL／USER／プールサイズ を返します。
    629                 *
    630                 * @og.rev 3.5.2.0 (2003/10/20) 接続情報に、データベース名、ドライバ名情報を追加する。
    631                 * @og.rev 3.5.6.6 (2004/08/23) 同期化方法を統一する為、synchronized をつけます。(別途 要検討)
    632                 * @og.rev 4.0.0.0 (2007/10/29) EDbidのtoStringを呼ぶように変更
    633                 *
    634                 * @return   このオブジェクトプールの文字列表現
    635                 * @og.rtnNotNull
    636                 */
    637                @Override
    638                public String toString() {
    639                        return edbid.toString() + super.toString() ;
    640                }
    641
    642//              /**
    643//               * すべての要素を オブジェクトプールから削除します。
    644//               * 貸し出し中のオブジェクトは、クリアしません。よって、返り値は、
    645//               * すべてのオブジェクトをクリアできた場合は、true 、貸し出し中の
    646//               * オブジェクトが存在した場合(クリアできなかった場合)は、false です。
    647//               *
    648//               * @og.rev 6.3.9.0 (2015/11/06) Use block level rather than method level synchronization.(PMD)
    649//               * @og.rev 7.1.0.0 (2020/01/20) Connection 作成時のﾀｲﾑｱｳﾄを用意します。
    650//               *
    651//               * @return すべてクリア(true)/貸し出し中のオブジェクトが残っている(false)
    652//               */
    653//              @Override
    654//              public boolean clear() {
    655//                      executor.shutdownNow();
    656//                      return super.clear();
    657//              }
    658        }
    659}