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