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.hayabusa.db;
017
018import java.sql.ResultSet;
019import java.sql.SQLException;
020
021import static org.opengion.fukurou.system.HybsConst.CR ;                // 6.1.0.0 (2014/12/26)
022import org.opengion.fukurou.db.Transaction;
023import org.opengion.fukurou.db.TransactionReal;
024import org.opengion.fukurou.db.ResultSetValue;                          // 6.0.4.0 (2014/11/28)
025import org.opengion.fukurou.db.ApplicationInfo;
026import org.opengion.fukurou.util.ErrorMessage;
027import org.opengion.fukurou.util.StringUtil;
028import org.opengion.hayabusa.common.HybsSystemException;
029import org.opengion.hayabusa.resource.LabelData;
030import org.opengion.hayabusa.resource.ResourceManager;
031
032/**
033 * データベース関連の便利なメソッドを集めた簡易ユーティリティークラスです。
034 * 全てのメソッドは、static メソッドになっています。
035 *
036 * @og.rev 2.1.1.1 (2002/11/15) Serializable インターフェースを削除する。
037 * @og.rev 4.0.0.0 (2007/10/16) 名称変更(DBUtil ⇒ DBTableModelUtil) DBアクセス関係のメソッドはfukurou/db/DBUtilに移動
038 * @og.group DB/Shell制御
039 *
040 * @version  4.0
041 * @author   Kazuhiko Hasegawa
042 * @since    JDK5.0,
043 */
044public final class DBTableModelUtil {
045        /**
046         * デフォルトコンストラクターをprivateにして、
047         * オブジェクトの生成をさせないようにする。
048         */
049        private DBTableModelUtil() {}
050
051        /**
052         * 初期データベースに接続して、Queryを実行します。
053         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
054         * 結果は、DBTableModel として返されます。
055         *
056         * @og.rev 3.0.0.0 (2002/12/25) 新規追加
057         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定
058         * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更
059         * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
060         *
061         * @param   stmt ステートメント文字列
062         * @param   args オブジェクトの引数配列
063         * @param   resource リソースマネージャー
064         * @param   appInfo アプリ情報オブジェクト
065         *
066         * @return  検索結果の配列
067         */
068        public static DBTableModel makeDBTable( final String stmt ,final String[] args, final ResourceManager resource, final ApplicationInfo appInfo ) {
069                return makeDBTable( stmt,args,resource,appInfo,null );
070        }
071
072        /**
073         * 検索するデータベースを指定して、Queryを実行します。
074         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
075         * 結果は、DBTableModel として返されます。
076         * 検索以外のSQLも実行できます。結果は、null を返します。
077         *
078         * @og.rev 3.0.0.0 (2002/12/25) 新規追加
079         * @og.rev 3.0.0.1 (2003/02/14) ヘッダー、フッター情報が null のときの処理追加。
080         * @og.rev 3.5.6.0 (2004/06/18) nullに対する無駄な比較を削除します。
081         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定
082         * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更
083         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応
084         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
085         * @og.rev 5.3.8.0 (2011/08/01) Transaction発生箇所でclose()
086         * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
087         * @og.rev 6.3.6.1 (2015/08/28) QueryFactory.close( Query ) 廃止。Queryはキャッシュしません。
088         *
089         * @param   stmt        ステートメント文字列
090         * @param   args        オブジェクトの引数配列
091         * @param   resource リソースマネージャー
092         * @param   appInfo アプリ情報オブジェクト
093         * @param   dbid        接続先ID
094         *
095         * @return  検索結果の配列
096         */
097        public static DBTableModel makeDBTable( final String stmt ,final String[] args ,
098                                                                                        final ResourceManager resource, final ApplicationInfo appInfo, final String dbid ) {
099                if( stmt == null || stmt.isEmpty() ) { return null; }
100
101                DBTableModel table = null;
102                try( Transaction tran = new TransactionReal( appInfo ) ) {
103                        final Query query = QueryFactory.newInstance( "JDBCPrepared" );
104                        query.setConnection( tran.getConnection( dbid ) );                      // 6.3.6.1 (2015/08/28)
105                        query.setResourceManager( resource );   // 4.0.0 (2005/01/31)
106                        query.setStatement( stmt );
107                        query.execute( args );
108
109                        final int errCode = query.getErrorCode();
110                        final int executeCount = query.getExecuteCount();
111                        if( errCode < ErrorMessage.NG && executeCount >= 0 ) {          // 異常以外の場合
112                                table = query.getDBTableModel();
113                                tran.commit();                          // 6.3.6.1 (2015/08/28)
114                        }
115                        else {
116                                tran.rollback();                        // 6.3.6.1 (2015/08/28)
117                                final ErrorMessage errMessage = query.getErrorMessage();
118                                throw new HybsSystemException( errMessage.toString() );
119                        }
120                }
121
122                return table;
123        }
124
125        /**
126         * 空の DBTableModelオブジェクトを作成します。
127         * これは、本来、ファクトリクラスで作成すべきですが、簡易作成メソッドとして
128         * DBUtil の static メソッドとして実装します。
129         *
130         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
131         *
132         * @return  DBTableModelオブジェクト
133         * @og.rtnNotNull
134         */
135        public static DBTableModel newDBTable() {
136                return new DBTableModelImpl();
137        }
138
139        /**
140         * カラム名の配列及びデータの2次元配列からDBテーブルモデルを作成します。
141         * カラム名がセットされていない若しくはデータがセットされていない場合は、nullを返します。
142         *
143         * @og.rev 4.2.1.0 (2008/04/26) 新規追加
144         *
145         * @param   clms カラム名の配列
146         * @param   vals 値の配列
147         * @param   resource リソースマネージャー
148         *
149         * @return  DBテーブルモデル
150         */
151        public static DBTableModel makeDBTable( final String[] clms, final String[][] vals, final ResourceManager resource ) {
152                if( clms == null || clms.length == 0 || vals == null || vals.length == 0 || vals[0] == null || vals[0].length == 0 ) {
153                        return null;
154                }
155
156                if( clms.length != vals[0].length ) {
157                        final String errMsg = "キーのカラム数とデータのカラム数が一致していません。"
158                                                + CR
159                                                + " clms.length=[" + clms.length + "]  vals.length=[" + vals[0].length + "]"
160                                                + " clms=" + StringUtil.array2csv( clms ) + CR
161                                                + " vals=" + StringUtil.array2csv( vals[0] )  ; // 5.1.8.0 (2010/07/01) errMsg 修正
162                        throw new HybsSystemException( errMsg );
163                }
164
165                final int numberOfColumns = clms.length;
166                final DBTableModel table = newDBTable() ;
167                table.init( numberOfColumns );
168
169                final DBColumn[] dbColumn = new DBColumn[numberOfColumns];              // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableCouldBeFinal
170                for( int column=0; column<numberOfColumns; column++ ) {
171                        dbColumn[column] = resource.makeDBColumn( clms[column] );
172                        table.setDBColumn( column,dbColumn[column] );
173                }
174
175                final int numberOfRows = vals.length;
176                for( int row=0; row<numberOfRows; row++ ) {
177                        table.addColumnValues( vals[row] );
178                }
179
180                return table;
181        }
182
183        /**
184         * 検索結果オブジェクトからDBテーブルモデルを作成します。
185         * 検索結果オブジェクトまたはリソースオブジェクトがセットされていない場合は、nullを返します。
186         *
187         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
188         * @og.rev 5.5.5.4 (2012/08/18) TIMESTAMP 型もCLOBと同様に処理を分ける。
189         * @og.rev 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
190         *
191         * @param   result 検索結果オブジェクト
192         * @param   skipRowCount 読み飛ばし件数
193         * @param       maxRowCount 最大検索件数
194         * @param   resource リソースマネージャー
195         *
196         * @return  DBテーブルモデル
197         * @throws      SQLException データベースアクセスエラー
198         */
199        public static DBTableModel makeDBTable( final ResultSet result, final int skipRowCount,
200                                                                                        final int maxRowCount, final ResourceManager resource ) throws SQLException {
201                if( result == null || resource == null ) { return null; }
202
203                final ResultSetValue rsv = new ResultSetValue( result );
204                final int clmSize =  rsv.getColumnCount();
205
206//              final DBTableModel table = DBTableModelUtil.newDBTable() ;
207                final DBTableModel table = newDBTable() ;       // 8.5.4.2 (2024/01/12) PMD 7.0.0 UnnecessaryFullyQualifiedName
208                table.init( clmSize );
209
210                for( int clmNo=0; clmNo<clmSize; clmNo++ ) {
211                        final String name = rsv.getColumnName(clmNo) ;
212                        DBColumn dbColumn = resource.getDBColumn( name );
213                        if( dbColumn == null ) {
214                                dbColumn = makeDBColumn( name,clmNo,rsv,resource );
215                        }
216                        table.setDBColumn( clmNo,dbColumn );
217                }
218
219                // データ部の設定
220                int numberOfRows = 0;
221                while( numberOfRows < skipRowCount && rsv.next() ) {
222                        // 注意 rsv.next() を先に判定すると必ず1件読み飛ばしてしまう。
223                        numberOfRows ++ ;
224                }
225                numberOfRows = 0;
226
227                while( numberOfRows < maxRowCount && rsv.next() ) {
228                        numberOfRows ++ ;
229                        table.addColumnValues( rsv.getValues() );
230                }
231
232                // 最大件数が、超えた場合でかつ次のデータがある場合は、オーバーフロー
233                if( numberOfRows >= maxRowCount && rsv.next() ) {
234                        table.setOverflow( true );
235                }
236
237                return table;
238        }
239
240        /**
241         * 検索結果オブジェクトから編集設定に基づいて変換されたDBテーブルモデルを作成します。
242         * 検索結果オブジェクトまたはリソースオブジェクトまたは編集設定オブジェクトがセットされていない場合は、nullを返します。
243         *
244         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
245         *
246         * @param   result 検索結果オブジェクト
247         * @param   skipRowCount 読み飛ばし件数
248         * @param       maxRowCount 最大検索件数
249         * @param   resource リソースマネージャー
250         * @param       config 編集設定オブジェクト
251         *
252         * @return  DBテーブルモデル
253         * @throws      SQLException データベースアクセスエラー
254         */
255        public static DBTableModel makeEditDBTable( final ResultSet result, final int skipRowCount,
256                                                                                                final int maxRowCount, final ResourceManager resource,
257                                                                                                final DBEditConfig config ) throws SQLException {
258                // 8.5.5.1 (2024/02/29) PMD 7.0.0 OnlyOneReturn メソッドには終了ポイントが 1 つだけ必要
259//              if( result == null || resource == null ) { return null; }
260                final DBTableModel table;
261                if( result == null || resource == null ) { table = null; }
262                else {
263//                      final DBTableModel table = new DBTableModelEditor();
264                        table = new DBTableModelEditor();
265                        ((DBTableModelEditor)table).create( result, skipRowCount, maxRowCount, resource, config );
266                }
267                return table;
268        }
269
270        /**
271         * ResultSetValue から、DBColumn オブジェクトを作成します。
272         *
273         * DBColumn オブジェクト がリソースファイルに定義されていない場合に、
274         * データベースの検索結果のメタデータを利用して、DBColumn オブジェクトを
275         * 作成します。
276         *
277         * @og.rev 3.4.0.0 (2003/09/01) 表示パラメータ、編集パラメータ、文字パラメータの追加。
278         * @og.rev 3.4.0.2 (2003/09/05) DBType のデフォルト値を、'X' から 'XK' に変更します。
279         * @og.rev 3.6.0.7 (2004/11/06) DBColumn の official属性追加
280         * @og.rev 4.0.0.0 (2005/01/31) lang 変数を取得
281         * @og.rev 5.3.6.0 (2011/06/01) AbstractQueryから移動
282         * @og.rev 6.0.2.1 (2014/09/26) org.opengion.fukurou.db.DBUtil#type2ClassName(int) に移動
283         * @og.rev 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
284         * @og.rev 6.2.0.0 (2015/02/27) フィールドサイズ 追加(VIEW_LENGTHと分離して、役割を明確にする)
285         *
286         * @param       name            カラム名
287         * @param       column          カラム番号
288         * @param   rsv                 ResultSetValueオブジェクト
289         * @param   resource    リソースマネージャー
290         * @return      DBColumnオブジェクト
291         */
292        public static DBColumn makeDBColumn( final String name,final int column,
293                                                        final ResultSetValue rsv, final ResourceManager resource ) {
294                final DBColumn dbColumn ;
295
296                final LabelData labelData = resource.getLabelData( name );
297                final String    lang      = resource.getLang();
298
299                try {
300                        final String    clsName  = rsv.getClassName(column);                                                    // 6.0.4.0 (2014/11/28)
301                        int     size     = rsv.getColumnDisplaySize(column);                                                    // 6.0.4.0 (2014/11/28)
302                        if( size == 0 ) { size = 60; }
303                        final boolean writable = rsv.isWritable(column);                                                                // 6.0.4.0 (2014/11/28)
304                        final String    dbType   = "NUMBER".equals( clsName ) ? "S9" : "XK" ;
305                        final String    defValue = "NUMBER".equals( clsName ) ? "0"  : ""  ;
306                        final DBColumnConfig config = new DBColumnConfig(
307                                lang,                                                   // 言語
308                                name,                                                   // カラム名
309                                labelData,                                              // カラムのラベルデータオブジェクト
310                                clsName ,                                               // カラムのクラスを文字列にした名称
311                                null ,                                                  // 入力枠サイズ                                                               // 6.2.0.0 (2015/02/27)
312                                null ,                                                  // カラムの表示文字数                                            // 6.2.0.0 (2015/02/27)
313                                String.valueOf( size ) ,                // カラムの最大桁数
314                                String.valueOf( writable ) ,    // カラムが書き込み可能かどうか
315                                null ,                                                  // データの表示用レンデラー
316                                null ,                                                  // データの編集用エディター
317                                null ,                                                  // メニューの項目コードデータオブジェクト
318                                dbType ,                                                // データのタイプ
319                                defValue,                                               // データのデフォルト値
320                                null ,                                                  // 表示用レンデラーのパラメータ
321                                null ,                                                  // 編集用エディターのパラメータ
322                                null ,                                                  // データのタイプのパラメータ
323                                null ,                                                  // カラムロール
324                                false,                                                  // 正式なカラムオブジェクトかどうか
325                                null                                                    // データベース接続先ID
326                        );
327
328                        dbColumn = new DBColumn( config );              // 4.0.0 (2005/01/31)
329                }
330                // 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
331                catch( final RuntimeException ex2 ) {
332                        final String errMsg = "予期せぬエラーが発生しました。name=[" + name + " , label=[" + labelData + "]";
333                        throw new HybsSystemException( errMsg,ex2 );            // 3.6.0.0 (2004/09/17)
334                }
335
336                return dbColumn;
337        }
338}