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.report;
017
018import org.opengion.hayabusa.common.HybsSystem;
019import org.opengion.hayabusa.db.DBTableModelUtil;
020import org.opengion.hayabusa.db.DBTableModel;
021import org.opengion.hayabusa.resource.ResourceFactory;
022import org.opengion.hayabusa.resource.ResourceManager;
023
024import org.opengion.fukurou.util.StringUtil;
025import org.opengion.fukurou.system.ThrowUtil;
026import org.opengion.fukurou.util.FileUtil;
027import org.opengion.fukurou.db.ApplicationInfo;
028import org.opengion.fukurou.db.DBUtil;
029import static org.opengion.fukurou.system.HybsConst.CR ;                // 6.1.0.0 (2014/12/26)
030import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.1.0.0 (2014/12/26) refactoring
031
032import java.io.File;
033
034/**
035 * 【レポート出力】DBTableModelオブジェクトをレポート形式に返還するタグリブクラスです。
036 * このオブジェクトに、 データ(DBTableModel)と、コントローラ(DBTableReport クラス)を与えて、
037 * 外部からコントロールすることで、各種形式で データ(DBTableModel)を表示させることが
038 * 可能です。
039 *
040 * @og.group 帳票システム
041 *
042 * @version  4.0
043 * @author   Kazuhiko Hasegawa
044 * @since    JDK5.0,
045 */
046public class ReportConverter {
047        private final StringBuilder errMsg ;
048
049        // DBTableReport に対して設定する情報
050        private String[]        headerKeys              ;               // 固定部の key 部分を指定する。カンマで複数指定できる。
051        private String[]        headerVals              ;               // 固定部の key に対応する値を指定する。
052        private String[]        footerKeys              ;               // 繰り返し部の終了後に表示する key 部分を指定する。カンマで複数指定できる。
053        private String[]        footerVals              ;               // 繰り返し部の終了後に表示する key に対する値を指定する。
054        private boolean         pageEndCut              ;               // ボディー部(繰り返し部)がなくなったときに、それ以降のページを出力するか指定する。
055        private File            templateFile    ;               // 3.8.0.0 (2005/06/07)
056        private File            firstTemplateFile;              // 3.8.0.0 (2005/06/07)
057        private DBTableModel    table           ;
058        private ResourceManager resource        ;               // 4.0.0 (2005/01/31)
059
060        // 受け渡し変数
061        private final String    SYSTEM_ID       ;
062        private final String    YKNO            ;
063        private final String    LISTID          ;
064        private final String    HTML_DIR        ;
065        private final String    LANG            ;
066        private final boolean   DEBUG           ;               // 3.8.5.0 (2006/03/06) デバッグ用のフラグを追加
067
068        // GE54 帳票定義マスタ
069        private String          modelDIR        ;
070        private String          modelFILE       ;
071        private String          hSQL            ;
072        private String          fSQL            ;
073        private String          bSQL            ;
074        private boolean         fgLOCAL         ;                       // 0:未使用 1:使用 4.0.0 (2005/01/31)
075        private boolean         fgDIRECT        ;                       // 0:未使用 1:使用 4.0.0 (2005/01/31)
076
077        // GE54 の帳票定義情報を取得するSQL文です。
078        // 4.0.0 (2005/01/31) 共有 system_id を、考慮
079        private static final String GE54_SELECT =
080                "SELECT MODELDIR,MODELFILE,FGCUT,HSQL,FSQL,BSQL,FGLOCAL,FGDIRECT,SYSTEM_ID" +   // 4.0.0 (2005/01/31)
081                " FROM GE54" +
082                " WHERE FGJ = '1'" +
083                " AND  SYSTEM_ID IN (?,'**')" +
084                " AND  LISTID = ?" ;
085
086        private static final int GE54_MODELDIR  = 0;
087        private static final int GE54_MODELFILE = 1;
088        private static final int GE54_FGCUT             = 2;
089        private static final int GE54_HSQL              = 3;
090        private static final int GE54_FSQL              = 4;
091        private static final int GE54_BSQL              = 5;
092        private static final int GE54_FGLOCAL   = 6;
093        private static final int GE54_FGDIRECT  = 7;
094        private static final int GE54_SYSTEM_ID = 8;
095
096        /** コネクションにアプリケーション情報を追記するかどうか指定 */
097        public static final boolean USE_DB_APPLICATION_INFO  = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ;
098
099        // 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
100        private final ApplicationInfo appInfo;
101        private final String DBID = HybsSystem.sys( "RESOURCE_DBID" );          // 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対応
102
103        /**
104         * コンストラクター
105         * 引数を受けとって、インスタンスを作成します。
106         *
107         * @og.rev 3.0.0.4 (2003/02/26) FGRUN が PRT のみのときは,MODELFILE のみセットして終了する。
108         * @og.rev 3.8.0.0 (2005/06/07) FGRUNは,使用しない
109         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
110         *
111         * @param system_id システムID
112         * @param ykno 要求番号
113         * @param listId 帳票ID
114         * @param tempDir 出力ディレクトリ
115         * @param lang 言語
116         * @param debug デバッグフラグ言語
117         */
118        public ReportConverter( final String system_id, final String ykno, final String listId,
119                                                         final String tempDir,final String lang,final boolean debug ) {
120                SYSTEM_ID       = system_id;
121                YKNO            = ykno;
122                LISTID          = listId;
123                HTML_DIR        = tempDir;
124                LANG            = lang;
125                DEBUG           = debug;
126                errMsg          = new StringBuilder( BUFFER_MIDDLE );
127
128                // 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
129                if( USE_DB_APPLICATION_INFO ) {
130                        appInfo = new ApplicationInfo();
131                        // ユーザーID,IPアドレス,ホスト名
132                        appInfo.setClientInfo( SYSTEM_ID,HybsSystem.HOST_ADRS,HybsSystem.HOST_NAME );
133                        // 画面ID,操作,プログラムID
134                        appInfo.setModuleInfo( "ReportConverter",YKNO,LISTID );
135                }
136                else {
137                        appInfo = null;
138                }
139        }
140
141        /**
142         * 変換処理を実行します。
143         *
144         * @og.rev 3.0.0.4 (2003/02/26) FGRUN が PRT のみのときは,MODELFILE のみセットして終了する。
145         * @og.rev 3.5.4.9 (2004/02/25) 存在チェックエラー(原因不明)の暫定対応
146         * @og.rev 3.8.0.0 (2005/06/07) initialDataSet() を ReportProcessing 側で呼び出します。
147         * @og.rev 6.4.2.0 (2016/01/29) StringUtil#stringStackTrace(Throwable) を、ThrowUtil#ogStackTrace(Throwable) に置き換え。
148         *
149         * @return 結果 [true:正常/false:異常]
150         */
151        public boolean execute() {
152                System.out.print( "ReportConverter Started ... " );
153                boolean flag = true;
154
155                try {
156                        // 雛形ファイルのチェック
157                        // 3.8.0.0 (2005/06/07) 存在チェックは、FileUtil.checkFile で行う。
158                        if( flag ) {
159                                System.out.print( "MDL CK," );
160                                templateFile = FileUtil.checkFile( modelDIR, modelFILE + ".html" );
161                                flag = templateFile != null ;           // チェックの結果が null なら、見つからなかった。
162
163                                if( !flag ) {
164                                        errMsg.append( "ModelFile Not Found Error !" ).append( CR )
165                                                .append( "MODELDIR=" ).append( modelDIR ).append( CR )
166                                                .append( "MODELFILE=" ).append( modelFILE ).append( ".html" ).append( CR );     // 6.0.2.5 (2014/10/31) char を append する。
167                                }
168                        }
169
170                        // ファーストページ雛形ファイルのチェック(なくても良い)
171                        // 3.8.0.0 (2005/06/07) 存在チェックは、FileUtil.checkFile で行う。
172                        if( flag ) {
173                                // チェックは、1回のみ行う。
174                                firstTemplateFile = FileUtil.checkFile( modelDIR, modelFILE + "_FIRST.html",1 );
175                        }
176
177                        // ヘッダ,フッタ, ボディー部の SQL を実行します。
178                        if( flag ) {
179                                flag = isHeaderFooter();
180                                if( flag ) { System.out.print( "HF SQL," ); }
181                        }
182
183                        // 帳票変換処理を実行します。
184                        if( flag ) {
185                                flag = reportRun();
186                                if( flag ) { System.out.print( "RPT RUN," ); }
187                        }
188                }
189                catch( final RuntimeException ex ) {
190                        errMsg.append( "ReportConverter Execute Exception Error!" ).append( CR )
191                                .append( "==============================" ).append( CR )
192                                .append( ThrowUtil.ogStackTrace( ex ) ).append( CR ) ;                                  // 6.4.2.0 (2016/01/29)
193                        flag = false;
194                }
195
196                System.out.println( "End." );
197                return flag ;
198        }
199
200        /**
201         * 初期データセットを行います。
202         * ここでは、GE54 テーブルより必要な情報を取得します。
203         *
204         * @og.rev 3.8.0.0 (2005/06/07) initialDataSet() を ReportProcessing 側で呼び出します。
205         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
206         * @og.rev 4.0.0.0 (2005/01/31) ローカルリソースフラグとダイレクトアクセスフラグを追加
207         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
208         *
209         * @return 結果 [true:正常/false:異常]
210         */
211        public boolean initialDataSet() {
212                final String[] args = new String[] { SYSTEM_ID,LISTID };
213                // modeldir,modelfile,fgcut,hsql,fsql,bsql,fglocal,fgdirect,system_id
214                final String[][] vals = DBUtil.dbExecute( GE54_SELECT,args,appInfo, DBID );             // 5.5.5.1 (2012/08/07)
215                if( vals == null || vals.length == 0 ) {
216                        errMsg.append( "Data does not exist in GE54 table." ).append( CR )
217                                .append( "==============================" ).append( CR )
218                                .append( "SYSTEM_ID=["  ).append( SYSTEM_ID )
219                                .append( "] , LISTID=[" ).append( LISTID    ).append( ']' )             // 6.0.2.5 (2014/10/31) char を append する。
220                                .append( CR );
221                        return false;
222                }
223
224                int row = 0;
225                // 検索結果が複数帰ったとき、SYSTEM_ID が 指定されている方のデータ(行)を採用する。
226                for( int i=0; i<vals.length; i++ ) {
227                        if( SYSTEM_ID.equalsIgnoreCase( vals[i][GE54_SYSTEM_ID] ) ) { row = i; break; }
228                }
229
230                modelDIR        = StringUtil.nval( vals[row][GE54_MODELDIR],modelDIR );
231                modelFILE       = StringUtil.nval( vals[row][GE54_MODELFILE],modelFILE );
232                pageEndCut      = StringUtil.nval( vals[row][GE54_FGCUT],pageEndCut );  // boolean タイプ
233
234                if( DEBUG ) {
235                        System.out.println( "MODELDIR   = [" + modelDIR   + "]" );
236                        System.out.println( "MODELFILE  = [" + modelFILE  + "]" );
237                        System.out.println( "pageEndCut = [" + pageEndCut + "]" );
238                }
239
240                hSQL = StringUtil.nval( vals[row][GE54_HSQL],hSQL );
241                fSQL = StringUtil.nval( vals[row][GE54_FSQL],fSQL );
242                bSQL = StringUtil.nval( vals[row][GE54_BSQL],bSQL );
243                if( bSQL == null || bSQL.isEmpty() ) {
244                        errMsg.append( "Body SQL Columns does not exist in GE54 table." ).append( CR )
245                                .append( "==============================" ).append( CR )
246                                .append( "SYSTEM_ID=["  ).append( SYSTEM_ID )
247                                .append( "] , LISTID=[" ).append( LISTID    ).append( "] " )
248                                .append( CR );
249                        return false;
250                }
251
252                // 4.0.0 (2005/01/31) ローカルリソースフラグとダイレクトアクセスフラグを追加
253                fgLOCAL = vals[row][GE54_FGLOCAL]  != null && vals[row][GE54_FGLOCAL].trim().equals( "1" ) ;
254                fgDIRECT= vals[row][GE54_FGDIRECT] != null && vals[row][GE54_FGDIRECT].trim().equals( "1" ) ;
255
256                return true;
257        }
258
259        /**
260         * ヘッダーフッター情報の取得を行います。
261         * GE54 の HSQL,FSQL,BSQL のコマンドを実行して、データを取得します。
262         * ヘッダー情報、フッター情報がなくても異常とは判断されませんが、
263         * ボディ情報が存在しない場合は、エラーとなります。
264         *
265         * @og.rev 3.0.0.1 (2003/02/14) ヘッダー、フッター情報が null のときの処理追加。
266         * @og.rev 3.0.1.3 (2003/03/11) 検索時の最大件数での打ち切りをエラーとする。
267         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
268         * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更 , メソッド名変更
269         *
270         * @return 結果 [true:正常/false:異常]
271         */
272        private boolean isHeaderFooter() {
273                // 4.0.0 (2005/01/31) FGLOCAL 指定時は、SYSTEM_ID を指定してリソース作成
274                if( fgLOCAL ) {
275                        // ローカルリソース指定時は、SYSTEM_ID,LANG を使用します。先読みは、使用しません。
276                        resource = ResourceFactory.newInstance( SYSTEM_ID,LANG,false ); // 4.0.0 (2005/01/31)
277                }
278                else {
279                        // 従来と互換性のあるモード(ローカルリソースは使用しない。
280                        resource = ResourceFactory.newInstance( LANG ); // 4.0.0 (2005/01/31)
281                }
282
283                // 4.0.0 (2005/01/31) FGDIRECT 指定時は、where 条件は、null になります。
284                final String[] where = fgDIRECT ? null : new String[] { SYSTEM_ID , YKNO } ;
285
286                // ヘッダー情報の取得
287                final DBTableModel header = DBTableModelUtil.makeDBTable( hSQL, where, resource, appInfo );             // 3.8.7.0 (2006/12/15)
288                if( header != null && header.getRowCount() > 0 ) {
289                        headerKeys              = header.getNames();
290                        final Object[] obj      = header.getValues(0);
291                        headerVals              = new String[obj.length];
292                        for( int i=0; i<obj.length; i++ ) {
293                                headerVals[i] = obj[i].toString().trim();
294                        }
295                }
296
297                // フッター情報の取得
298                final DBTableModel footer = DBTableModelUtil.makeDBTable( fSQL, where, resource ,appInfo );             // 3.8.7.0 (2006/12/15)
299                if( footer != null && footer.getRowCount() > 0 ) {
300                        footerKeys              = footer.getNames();
301                        final Object[] obj      = footer.getValues(0);
302                        footerVals              = new String[obj.length];
303                        for( int i=0; i<obj.length; i++ ) {
304                                footerVals[i] = obj[i].toString().trim();
305                        }
306                }
307
308                // ボディー情報の取得
309                table = DBTableModelUtil.makeDBTable( bSQL, where, resource ,appInfo );         // 3.8.7.0 (2006/12/15)
310                if( table.getRowCount() <= 0 ) {
311                        errMsg.append( "Database Body row count is Zero." ).append( CR )
312                                .append( "==============================" ).append( CR )
313                                .append( bSQL )
314                                .append( CR );
315                        return false;
316                }
317                // 3.0.1.3 (2003/03/11) 検索時の最大件数での打ち切りをエラーとする。
318                if( table.isOverflow() ) {
319                        errMsg.append( "Database is Overflow. [" )
320                                .append( table.getRowCount() )
321                                .append( ']' ).append( CR ).append( CR )                // 6.0.2.5 (2014/10/31) char を append する。
322                                .append( "==============================" ).append( CR )
323                                .append( "Check SystemParameter Data in DB_MAX_ROW_COUNT Overflow" )
324                                .append( CR );
325                        return false;
326                }
327
328                return true;
329        }
330
331        /**
332         * 実際のレポート変換処理を行います。
333         *
334         * @og.rev 3.5.4.3 (2004/01/05) HTMLDBTableReport のクラス名変更。
335         * @og.rev 3.6.0.0 (2004/09/17) メソッド名の変更。setInputFile ⇒ setTemplateFile
336         * @og.rev 3.6.1.0 (2005/01/05) 帳票ID(LISTID)をセットします。
337         * @og.rev 3.8.5.1 (2006/04/28) setOutputFileKey の代わりに、setYkno を使用します。
338         * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更
339         *
340         * @return 結果 [true:正常/false:異常]
341         */
342        private boolean reportRun() {
343                final DBTableReport report = new DBTableReport_HTML();
344
345                report.setDBTableModel( table );
346                report.setTemplateFile( templateFile );                         // 3.6.0.0 (2004/09/17)
347                report.setFirstTemplateFile( firstTemplateFile );       // 3.6.0.0 (2004/09/17)
348                report.setOutputDir( HTML_DIR );
349                report.setOutputFileKey( YKNO );        // 要求番号をファイル名として使用します。
350                report.setYkno( YKNO );                                                         // 3.8.5.1 (2006/04/28)
351                report.setHeaderKeys( headerKeys );
352                report.setHeaderVals( headerVals );
353                report.setFooterKeys( footerKeys );
354                report.setFooterVals( footerVals );
355                report.setPageEndCut( pageEndCut );
356                report.setResourceManager( resource );          // 4.0.0 (2005/01/31)
357                report.setListId( LISTID );             // 3.6.1.0 (2005/01/05)
358                report.writeReport();
359
360                return true;
361        }
362
363        /**
364         * modelFILE を返します。
365         *
366         * @og.rev 6.4.2.1 (2016/02/05) メソッド名変更 ReportConverter#modelFile() → ReportConverter#getModelFile() 。
367         *
368         * @return modelFILE名
369         */
370        public String getModelFile() {
371                return modelFILE ;
372        }
373
374        /**
375         * エラーが存在した場合に、エラーメッセージを返します。
376         *
377         * @return エラーメッセージ String
378         * @og.rtnNotNull
379         */
380        public String getErrMsg() {
381                return errMsg.toString();
382        }
383}