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        private DBTableModelUtil() {}
049
050        /**
051         * 初期データベースに接続して、Queryを実行します。
052         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
053         * 結果は、DBTableModel として返されます。
054         *
055         * @og.rev 3.0.0.0 (2002/12/25) 新規追加
056         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定
057         * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更
058         * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
059         *
060         * @param   stmt ステートメント文字列
061         * @param   args オブジェクトの引数配列
062         * @param   resource リソースマネージャー
063         * @param   appInfo アプリ情報オブジェクト
064         *
065         * @return  検索結果の配列
066         */
067        public static DBTableModel makeDBTable( final String stmt ,final String[] args, final ResourceManager resource, final ApplicationInfo appInfo ) {
068                return makeDBTable( stmt,args,resource,appInfo,null );
069        }
070
071        /**
072         * 検索するデータベースを指定して、Queryを実行します。
073         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
074         * 結果は、DBTableModel として返されます。
075         * 検索以外のSQLも実行できます。結果は、null を返します。
076         *
077         * @og.rev 3.0.0.0 (2002/12/25) 新規追加
078         * @og.rev 3.0.0.1 (2003/02/14) ヘッダー、フッター情報が null のときの処理追加。
079         * @og.rev 3.5.6.0 (2004/06/18) nullに対する無駄な比較を削除します。
080         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定
081         * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更
082         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応
083         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
084         * @og.rev 5.3.8.0 (2011/08/01) Transaction発生箇所でclose()
085         * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
086         * @og.rev 6.3.6.1 (2015/08/28) QueryFactory.close( Query ) 廃止。Queryはキャッシュしません。
087         *
088         * @param   stmt        ステートメント文字列
089         * @param   args        オブジェクトの引数配列
090         * @param   resource リソースマネージャー
091         * @param   appInfo アプリ情報オブジェクト
092         * @param   dbid        接続先ID
093         *
094         * @return  検索結果の配列
095         */
096        public static DBTableModel makeDBTable( final String stmt ,final String[] args ,
097                                                                                        final ResourceManager resource, final ApplicationInfo appInfo, final String dbid ) {
098                if( stmt == null || stmt.isEmpty() ) { return null; }
099
100                DBTableModel table = null;
101
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
153                                || vals == null || vals.length == 0 || vals[0] == null || vals[0].length == 0 ) {
154                        return null;
155                }
156
157                if( clms.length != vals[0].length ) {
158                        final String errMsg = "キーのカラム数とデータのカラム数が一致していません。"
159                                                + CR
160                                                + " clms.length=[" + clms.length + "]  vals.length=[" + vals[0].length + "]"
161                                                + " clms=" + StringUtil.array2csv( clms ) + CR
162                                                + " vals=" + StringUtil.array2csv( vals[0] )  ; // 5.1.8.0 (2010/07/01) errMsg 修正
163                        throw new HybsSystemException( errMsg );
164                }
165
166                final int numberOfColumns = clms.length;
167                final DBTableModel table = newDBTable() ;
168                table.init( numberOfColumns );
169
170                DBColumn[] dbColumn = new DBColumn[numberOfColumns];
171                for( int column=0; column<numberOfColumns; column++ ) {
172                        dbColumn[column] = resource.makeDBColumn( clms[column] );
173                        table.setDBColumn( column,dbColumn[column] );
174                }
175
176                final int numberOfRows = vals.length;
177                for( int row=0; row<numberOfRows; row++ ) {
178                        table.addColumnValues( vals[row] );
179                }
180
181                return table;
182        }
183
184        /**
185         * 検索結果オブジェクトからDBテーブルモデルを作成します。
186         * 検索結果オブジェクトまたはリソースオブジェクトがセットされていない場合は、nullを返します。
187         *
188         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
189         * @og.rev 5.5.5.4 (2012/08/18) TIMESTAMP 型もCLOBと同様に処理を分ける。
190         * @og.rev 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
191         *
192         * @param   result 検索結果オブジェクト
193         * @param   skipRowCount 読み飛ばし件数
194         * @param       maxRowCount 最大検索件数
195         * @param   resource リソースマネージャー
196         *
197         * @return  DBテーブルモデル
198         * @throws      SQLException データベースアクセスエラー
199         */
200        public static DBTableModel makeDBTable( final ResultSet result, final int skipRowCount, 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
205                final int clmSize =  rsv.getColumnCount();
206
207                final DBTableModel table = DBTableModelUtil.newDBTable() ;
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, final int maxRowCount, final ResourceManager resource, final DBEditConfig config ) throws SQLException {
256                if( result == null || resource == null ) { return null; }
257                final DBTableModel table = new DBTableModelEditor();
258                ((DBTableModelEditor)table).create( result, skipRowCount, maxRowCount, resource, config );
259                return table;
260        }
261
262        /**
263         * ResultSetValue から、DBColumn オブジェクトを作成します。
264         *
265         * DBColumn オブジェクト がリソースファイルに定義されていない場合に、
266         * データベースの検索結果のメタデータを利用して、DBColumn オブジェクトを
267         * 作成します。
268         *
269         * @og.rev 3.4.0.0 (2003/09/01) 表示パラメータ、編集パラメータ、文字パラメータの追加。
270         * @og.rev 3.4.0.2 (2003/09/05) DBType のデフォルト値を、'X' から 'XK' に変更します。
271         * @og.rev 3.6.0.7 (2004/11/06) DBColumn の official属性追加
272         * @og.rev 4.0.0.0 (2005/01/31) lang 変数を取得
273         * @og.rev 5.3.6.0 (2011/06/01) AbstractQueryから移動
274         * @og.rev 6.0.2.1 (2014/09/26) org.opengion.fukurou.db.DBUtil#type2ClassName(int) に移動
275         * @og.rev 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
276         * @og.rev 6.2.0.0 (2015/02/27) フィールドサイズ 追加(VIEW_LENGTHと分離して、役割を明確にする)
277         *
278         * @param       name            カラム名
279         * @param       column          カラム番号
280         * @param   rsv                 ResultSetValueオブジェクト
281         * @param   resource    リソースマネージャー
282         * @return      DBColumnオブジェクト
283         */
284        public static DBColumn makeDBColumn( final String name,final int column,
285                                                        final ResultSetValue rsv, final ResourceManager resource ) {
286                final DBColumn dbColumn ;
287
288                final LabelData labelData = resource.getLabelData( name );
289                final String    lang      = resource.getLang();
290
291                try {
292                        final String    clsName  = rsv.getClassName(column);                                                    // 6.0.4.0 (2014/11/28)
293                        int     size     = rsv.getColumnDisplaySize(column);                                                    // 6.0.4.0 (2014/11/28)
294                        if( size == 0 ) { size = 60; }
295                        final boolean writable = rsv.isWritable(column);                                                                // 6.0.4.0 (2014/11/28)
296                        final String    dbType   = "NUMBER".equals( clsName ) ? "S9" : "XK" ;
297                        final String    defValue = "NUMBER".equals( clsName ) ? "0"  : ""  ;
298                        final DBColumnConfig config = new DBColumnConfig(
299                                lang,                                                   // 言語
300                                name,                                                   // カラム名
301                                labelData,                                              // カラムのラベルデータオブジェクト
302                                clsName ,                                               // カラムのクラスを文字列にした名称
303                                null ,                                                  // 入力枠サイズ                                                               // 6.2.0.0 (2015/02/27)
304                                null ,                                                  // カラムの表示文字数                                            // 6.2.0.0 (2015/02/27)
305                                String.valueOf( size ) ,                // カラムの最大桁数
306                                String.valueOf( writable ) ,    // カラムが書き込み可能かどうか
307                                null ,                                                  // データの表示用レンデラー
308                                null ,                                                  // データの編集用エディター
309                                null ,                                                  // メニューの項目コードデータオブジェクト
310                                dbType ,                                                // データのタイプ
311                                defValue,                                               // データのデフォルト値
312                                null ,                                                  // 表示用レンデラーのパラメータ
313                                null ,                                                  // 編集用エディターのパラメータ
314                                null ,                                                  // データのタイプのパラメータ
315                                null ,                                                  // カラムロール
316                                false,                                                  // 正式なカラムオブジェクトかどうか
317                                null                                                    // データベース接続先ID
318                        );
319
320                        dbColumn = new DBColumn( config );              // 4.0.0 (2005/01/31)
321                }
322                // 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
323                catch( final RuntimeException ex2 ) {
324                        final String errMsg = "予期せぬエラーが発生しました。name=[" + name + " , label=[" + labelData + "]";
325                        throw new HybsSystemException( errMsg,ex2 );            // 3.6.0.0 (2004/09/17)
326                }
327
328                return dbColumn;
329        }
330}