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.plugin.daemon;
017
018import org.opengion.hayabusa.common.HybsSystem;
019import org.opengion.hayabusa.common.HybsSystemException;
020import org.opengion.hayabusa.report.GE50Access;
021import org.opengion.hayabusa.report.ReportProcessing;
022import org.opengion.fukurou.system.LogWriter;
023import org.opengion.fukurou.util.StringUtil;
024import org.opengion.fukurou.system.ThrowUtil;                                           // 6.4.2.0 (2016/01/29)
025import org.opengion.fukurou.util.HybsTimerTask;
026import org.opengion.fukurou.db.ApplicationInfo;
027import org.opengion.fukurou.db.DBUtil;
028import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.1.0.0 (2014/12/26) refactoring
029
030import java.util.concurrent.ConcurrentMap;                                                      // 6.4.3.3 (2016/03/04)
031import java.util.concurrent.ConcurrentHashMap;                                          // 6.4.3.1 (2016/02/12) refactoring
032import java.util.Date;
033
034/**
035 * 【レポート出力】帳票要求テーブルを監視して、帳票処理プログラムを呼び出します。
036 * このクラスは、HybsTimerTask を継承した タイマータスククラスです。
037 * startDaemon() がタイマータスクによって、呼び出されます。
038 *
039 * @og.rev 4.3.4.4 (2009/01/01) プラグイン化
040 * @og.group デーモン
041 *
042 * @version  4.0
043 * @author   Kazuhiko Hasegawa
044 * @since    JDK5.0,
045 */
046public class Daemon_Report extends HybsTimerTask {
047        /** このプログラムのVERSION文字列を設定します。   {@value} */
048        private static final String VERSION = "6.4.3.3 (2016/03/04)" ;
049
050        /** コネクションにアプリケーション情報を追記するかどうか指定 */
051        public static final boolean USE_DB_APPLICATION_INFO  = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ;
052
053        // 3.7.0.0 (2005/01/18) 複数同時デーモン時の、同一帳票IDは処理できない。
054        // 実行中の帳票ID をセットする、static Map
055        /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。  */
056        private static final ConcurrentMap<String,String> USE_LISTID = new ConcurrentHashMap<>();               // 6.4.3.1 (2016/02/12)
057
058        // 3.8.5.0 (2006/03/06) EXCELをオープンするファイル名に要求番号を使う場合は、true
059        private static final boolean EXCEL_NAME_USE_YKNO = HybsSystem.sysBool( "REPORT_EXCEL_NAME_USE_YKNO" );
060
061//      // 5.2.0.0 (2010/09/01) Ver4互換モード対応
062//      // 6.9.5.0 (2018/04/23) VER4_COMPATIBLE_MODE 廃止
063//      private static final String OUT_FILE = HybsSystem.sysBool( "VER4_COMPATIBLE_MODE" ) ? "OUTFILE" : "OUT_FILE";
064//      private static final String OUT_DIR = HybsSystem.sysBool( "VER4_COMPATIBLE_MODE" ) ? "OUTDIR" : "OUT_DIR";
065
066        // 3.7.0.0 (2005/01/18) GE53 に DMN_GRP追加による、検索条件の変更
067        // 5.1.0.0 (2009/11/04) OUTDIR ⇒ OUT_DIR , OUTFILE ⇒ OUT_FILE
068        // 5.2.0.0 (2010/09/01) Ver4互換モード対応
069
070        // 5.9.0.1 (2015/09/11)
071        // 6.9.5.0 (2018/04/23) VER4_COMPATIBLE_MODE 廃止
072        // 5.10.0.0 (2018/06/08) SELECT区にC.FGNOML(メール不要フラグ)を追加
073        private static final String GE50_SELECT =
074//              "SELECT A.SYSTEM_ID,A.YKNO,A.GROUPID,A.LISTID,A.JOKEN,A."+OUT_DIR+",A."+OUT_FILE+",A.USRSET" +
075//              "SELECT A.SYSTEM_ID,A.YKNO,A.GROUPID,A.LISTID,A.JOKEN,A.OUT_DIR,A.OUT_FILE,A.USRSET" +
076        //      "SELECT A.SYSTEM_ID,A.YKNO,A.GROUPID,A.LISTID,A.JOKEN,A.OUT_DIR,A.OUT_FILE,A.USRSET,C.FGNOML" +                 // 5.10.0.0 (2018/06/08)
077                "SELECT A.SYSTEM_ID,A.YKNO,A.GROUPID,A.LISTID,A.JOKEN,A.OUT_DIR,A.OUT_FILE,A.USRSET,'0' as FGNOML" +    // 6.9.8.1 (2018/06/11)
078                " FROM GE50 A,GE53 B,GE54 C" +
079                " WHERE A.SYSTEM_ID = B.SYSTEM_ID" +
080                " AND A.JOKEN = B.JOKEN" +
081                " AND A.FGJ = '1'" +
082                " AND B.FGJ = '1'" +
083                " AND A.FGKAN = '1'" +
084                " AND A.SYSTEM_ID = C.SYSTEM_ID" +
085                " AND A.LISTID = C.LISTID"+
086                " AND C.FGJ = '1'";
087
088        private final String DBID = HybsSystem.sys( "RESOURCE_DBID" );          // 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対応
089
090        // 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
091        private ApplicationInfo appInfo ;
092        private ReportProcessing  rc    ;
093
094        private static final int LOOP_COUNTER = 24;             // カウンタを24回に設定
095        private int             loopCnt         ;               // 3.5.4.9 (2004/02/25) メッセージ出力時のループカウント
096
097        // 6.3.9.0 (2015/11/06) Variables should start with a lowercase character(PMD)
098        private String  geSELECT        ;               // 3.7.0.0 (2005/01/18) GE53 に DMN_GRP追加による、検索条件の変更
099        private String  prtID           ;               // 3.8.5.0 (2006/03/06) プリンタIDが、引数から渡される場合の対応
100        private String  dmnNAME         ;               // 3.8.5.0 (2006/03/06) デーモン名を設定します。
101        private boolean debug           ;               // 3.8.5.0 (2006/03/06) デバッグ用のフラグを追加します。小文字に修正
102        private boolean running         = true; // 3.8.5.3 (2006/06/30) タイマータスクがキャンセルされた場合の停止フラグ
103
104        /**
105         * デフォルトコンストラクター
106         *
107         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
108         */
109        public Daemon_Report() { super(); }             // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
110
111        /**
112         * このタイマータスクによって初期化されるアクションです。
113         * パラメータを使用した初期化を行います。
114         *
115         * @og.rev 3.6.0.7 (2004/11/12) 新規追加
116         * @og.rev 3.7.0.0 (2005/01/18) 帳票定義マスタ(GE54)を参照するように仕様変更
117         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
118         * @og.rev 4.0.1.0 (2007/12/19) GE50の検索順をシステムリソースで設定可能にする
119         * @og.rev 5.7.3.2 (2014/02/28) GE53の検索条件修正
120         */
121        @Override
122        public void initDaemon() {
123
124                // 3.7.0.0 (2005/01/18) GE50, GE54 の USRUPD に、デーモン名をセットします。
125                // 3.7.1.1 (2005/05/31) GE50Access を使用して、DB登録を行います。
126
127                // 3.8.5.0 (2006/03/06) デーモン名を設定します。
128                dmnNAME = getName();                                    // 6.3.9.0 (2015/11/06)
129
130                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
131                buf.append( GE50_SELECT );
132
133                // SYSTEM_ID は、指定がなければ、全件検索対象になります。
134                final String systemId = getValue( "SYSTEM_ID" );
135                if( ! StringUtil.isNull( systemId ) ) {
136                        buf.append( " AND A.SYSTEM_ID='" ).append( systemId ).append( '\'' );
137                }
138
139                // 3.8.5.0 (2006/03/06) DMN_GRP は、必須指定
140                // 5.1.9.0 (2010/08/01) Avoid if(x != y) ..; else ..;
141                final String dmnGroup = getValue( "DMN_GRP" );
142                if( StringUtil.isNull( dmnGroup ) ) {
143                        final String errMsg = "デーモングループは必須指定です。" ;
144                        throw new HybsSystemException( errMsg );
145                }
146                else {
147                        buf.append( " AND B.DMN_GRP='" ).append( dmnGroup ).append( '\'' );
148                }
149
150                // 3.8.5.0 (2006/03/06) GE50 の検索条件に、MODBASE と MODNO を使用する。
151                // デーモン起動時に 最大数(MODBASE)と余り番号(MODNO)を渡します。
152                // 最大数(MODBASE)を元に、検索時に、YKNOの余りを求め、これが、
153                // 引数の余り番号(MODNO)と一致する場合のみ、処理をします。
154                final String modBase    = StringUtil.nval( getValue( "MODBASE" ),null );
155                final String modNo      = StringUtil.nval( getValue( "MODNO" ),null );
156                if( modBase != null && modNo != null ) {
157                        buf.append( " AND MOD(A.YKNO," ).append( modBase ).append( ")=" ).append( modNo );
158                }
159
160                // 3.8.5.0 (2006/03/06) PRTID が指定されていれば、その値を使用する。なければ NULL
161                prtID = StringUtil.nval( getValue( "PRTID" ), null );                           // 6.3.9.0 (2015/11/06)
162
163                // 3.8.5.0 (2006/03/06) PRT_GRP が指定されていれば、振分条件検索時に使用する。
164                final String prtGgrp = getValue( "PRT_GRP" );
165                if( ! StringUtil.isNull( prtGgrp ) ) {
166                        buf.append( " AND B.PRTID='" ).append( prtGgrp ).append( '\'' ); // 5.7.3.2 (2014/02/28) GE53ではPRTIDにPRI_GRPが指定されている
167                }
168
169                buf.append( " ORDER BY " )                              // 4.0.1.0 (2007/12/19)
170                        .append( HybsSystem.sys( "REPORT_DAEMON_ORDER_BY" ) );
171
172                geSELECT = buf.toString() ;                             // 6.3.9.0 (2015/11/06)
173
174                // 3.8.5.0 (2006/03/06) デバッグ用のフラグを追加します。
175                debug = StringUtil.nval( getValue( "DEBUG" ),debug ) ;
176
177                if( debug ) {
178                        System.out.println( "DMN_NAME=[" + dmnNAME + "]" );                             // 6.3.9.0 (2015/11/06)
179                        System.out.println( "MODNO=[" + modNo + "]" );
180                        System.out.println( "QUERY=[" + geSELECT + "]" );
181                        System.out.println( "EXCEL_NAME_USE_YKNO=[" + EXCEL_NAME_USE_YKNO + "]" );
182                }
183
184                // 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
185                if( USE_DB_APPLICATION_INFO ) {
186                        appInfo = new ApplicationInfo();
187                        // ユーザーID,IPアドレス,ホスト名
188                        appInfo.setClientInfo( systemId,HybsSystem.HOST_ADRS,HybsSystem.HOST_NAME );
189                        // 画面ID,操作,プログラムID
190                        appInfo.setModuleInfo( "ReportDaemon",prtID,dmnNAME );                  // 6.3.9.0 (2015/11/06)
191                }
192                else {
193                        appInfo = null;
194                }
195        }
196
197        /**
198         * タイマータスクのデーモン処理の開始ポイントです。
199         *
200         * @og.rev 3.5.2.0 (2003/10/20) vals 変数を、ローカルに移動
201         * @og.rev 3.5.4.8 (2004/02/23) タイムスタンプを、10回に1回とする。
202         * @og.rev 3.6.0.0 (2004/09/17) タイムスタンプを、24回に1回とする。
203         * @og.rev 3.6.1.0 (2005/01/05) tyr ~ catch を Exception から Throwable に変更。
204         * @og.rev 3.7.0.0 (2005/01/18) 複数同時デーモンでも、同一帳票IDは処理できない為、スキップします。
205         * @og.rev 3.7.0.4 (2005/03/18) エラー発生時に vals が null なら、HybsSystemException を throw する。
206         * @og.rev 3.7.1.1 (2005/05/31) GE50Access を使用して、DB登録を行います。
207         * @og.rev 3.8.0.0 (2005/06/07) EXCEL 取込時の完成フラグは、FG_DBIN とします。
208         * @og.rev 3.8.0.0 (2005/06/07) rc.execute() 実行結果を boolean ではなく、文字列(FGKAN_XX)で返します。
209         * @og.rev 3.8.5.0 (2006/03/06) EXCELファイル名に要求番号を使う場合は、帳票IDでの排他制御は不要。
210         * @og.rev 3.8.5.2 (2006/05/31) DEBUG 情報の強化
211         * @og.rev 3.8.6.0 (2006/06/30) タイマータスクがキャンセルされた場合の処理を追加(running フラグ)
212         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
213         * @og.rev 5.3.0.0 (2010/12/01) エラーハンドリングを修正
214         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
215         * @og.rev 5.7.0.4 (2013/11/29) listIdをGE50Accessに渡すようにする
216         * @og.rev 6.4.2.0 (2016/01/29) StringUtil#stringStackTrace(Throwable) を、ThrowUtil#ogStackTrace(String,Throwable) に置き換え。
217         * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
218         * @og.rev 6.4.3.3 (2016/03/04) Map#putIfAbsent で対応する。
219         * @og.rev 5.10.0.0 (2018/06/08) エラー時のメール送信判定にfgnomlのパラメータ設定を追加
220         */
221        @Override
222        protected void startDaemon() {
223                if( loopCnt % LOOP_COUNTER == 0 ) {
224                        loopCnt = 1;
225                        System.out.println();
226                        System.out.print( toString() + " " + new Date()  + " " );
227                }
228                else {
229                        System.out.print( "." );
230                        loopCnt++ ;
231                }
232
233                // 3.7.1.1 (2005/05/31) GE50Access を使用して、DB登録を行います。
234                GE50Access ge50 = null ;
235
236                String listId = null;                           // 6.4.3.1 (2016/02/12) vals をローカル化して、listId を大域化します。
237                try {
238                        final String[][] vals = DBUtil.dbExecute( geSELECT,null,appInfo, DBID );                // 6.3.9.0 (2015/11/06)
239                        if( vals != null && vals.length > 0 ) {
240
241                                // 3.7.1.1 (2005/05/31) GE50Access を使用して、DB登録を行います。
242                                // 毎回 オブジェクトを構築します。登録日付が初期化されます。
243                                ge50 = new GE50Access( null,null,dmnNAME ) ;                    // 6.3.9.0 (2015/11/06)
244
245                                if( rc == null ) { rc = new ReportProcessing(); }
246                                // 3.8.6.0 (2006/06/30) タイマータスクがキャンセルされた場合の処理を追加(running フラグ)
247                                for( int row=0; running && row<vals.length; row++ ) {   // 6.4.3.1 (2016/02/12)
248                                        // 3.7.0.0 (2005/01/18) 使用中の帳票IDのチェックと、使用時の登録
249                                        final String systemId = vals[row][0] ;
250                                        final String ykno     = vals[row][1] ;
251                                        listId                            = vals[row][3] ;                              // 6.4.3.1 (2016/02/12)
252                                        // 3.8.5.0 (2006/03/06) EXCELファイル名に要求番号を使う場合は、帳票IDでの排他制御は不要。
253                                        if( ! EXCEL_NAME_USE_YKNO ) {
254                                                // 6.4.3.3 (2016/03/04) Map#putIfAbsent で対応します。
255                                                // Map#putIfAbsent : 戻り値は、以前の値。追加有り、置換なし、削除なし
256                                                if( USE_LISTID.putIfAbsent( listId,"DUMMY" ) != null ) { continue; }    // 使用中なら、飛ばす。
257
258                                                // 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
259                                        }
260
261                                        // デバッグ情報を出力します。
262                                        if( debug ) {
263                                                System.out.println();
264                                                System.out.print( "[" + dmnNAME + "]:[" + ykno + "] START = " );                        // 6.3.9.0 (2015/11/06)
265                                                System.out.println( new Date() );
266                                        }
267
268                                        // 3.7.1.1 (2005/05/31) GE50Access を使用して、DB登録を行います。
269                                        ge50.setSystemId( systemId );
270                                        ge50.setYkno( ykno );
271                                        ge50.setFgNoMl( vals[row][8] );         // 5.10.0.0 (2018/06/08) ADD メール不要フラグ
272                                        ge50.updateGE50( GE50Access.FG_RUN );
273
274                                        ge50.setListId( listId );                       // 5.7.0.4 (2013/11/29)
275
276                                        // system_id,ykno,groupid,listid,joken,outdir,outfile,usrset
277                                        rc.setSystemId( systemId        );
278                                        rc.setYkno(             ykno            );
279                                        rc.setGroupId(  vals[row][2]);
280                                        rc.setListId(   listId          );
281                                        rc.setJoken(    vals[row][4]);
282                                        rc.setPrtId(    prtID           );              // 6.3.9.0 (2015/11/06)
283                                        rc.setOutDir(   vals[row][5]);
284                                        rc.setOutFile(  vals[row][6]);
285                                        rc.setDebug(    debug           );              // 3.8.5.0 (2006/03/06) DEBUGを追加。
286
287                                        // 3.8.0.0 (2005/06/07) 実行結果を boolean ではなく、文字列(FGKAN_XX)で返します。
288                                        String fgkan = rc.execute();
289                                        if( fgkan == null ) {
290                                                fgkan = GE50Access.FG_ERR2 ;
291                                                final String errMsg = rc.getErrMsg();
292                                                // 3.7.1.1 (2005/05/31) GE50Access を使用して、DB登録を行います。
293                                                ge50.insertErrorGE56( errMsg );
294                                        }
295
296                                        // 3.7.1.1 (2005/05/31) GE50Access を使用して、DB登録を行います。
297                                        ge50.updateGE50( fgkan );
298
299                                        rc.clear();
300                                        // 3.8.5.0 (2006/03/06) EXCELファイル名に要求番号を使う場合は、帳票IDでの排他制御は不要。
301                                        if( ! EXCEL_NAME_USE_YKNO ) {
302                                                // 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
303                                                USE_LISTID.remove( listId );
304
305                                        }
306
307                                        // デバッグ情報を出力します。
308                                        if( debug ) {
309                                                System.out.println();
310                                                System.out.print( "[" + dmnNAME + "]:[" + ykno + "] END = " );                  // 6.3.9.0 (2015/11/06)
311                                                System.out.println( new Date() );
312                                        }
313                                }
314                        }
315                }
316                // 5.3.0.0 (2010/12/01) エラーハンドリングを修正
317                catch( final Throwable ex ) {           // 3.6.1.0 (2005/01/05)
318                        rc = null;
319
320                        final String errMsg = ThrowUtil.ogStackTrace( ex ) ;                                                            // 6.4.2.0 (2016/01/29)
321                        System.out.println( errMsg );
322                        LogWriter.log( errMsg );
323
324                        // 6.9.7.0 (2018/05/14) PMD These nested if statements could be combined
325//                      if( ! EXCEL_NAME_USE_YKNO ) {
326//                              // 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
327//                              if( listId != null ) { USE_LISTID.remove( listId ); }
328//                      }
329                        if( ! EXCEL_NAME_USE_YKNO && listId != null ) {
330                                // 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
331                                USE_LISTID.remove( listId );
332                        }
333
334                        // 3.7.1.1 (2005/05/31) GE50Access を使用して、DB登録を行います。
335                        if( ge50 != null ) {
336                                ge50.insertErrorGE56( errMsg );
337                                ge50.updateGE50( GE50Access.FG_ERR1 );
338                        }
339                        // 6.4.3.1 (2016/02/12) 条件は異なるが、ほぼ、近いはず
340                        else if( listId == null ) {
341                                final String errMsg2 = "SQL=[" + geSELECT + "] , appInfo=[" + appInfo + "] , DBID=[" + DBID + "]";
342                                System.out.println( errMsg2 );
343                                LogWriter.log( errMsg2 );
344                                throw new HybsSystemException( errMsg + errMsg2 , ex );
345                        }
346
347                }
348        }
349
350        /**
351         * このタイマータスクのcancel() メソッドをオーバーライドします。
352         * HybsTimerTaskManager#cancelTask( int ) を実行します。
353         *
354         * @og.rev 3.8.5.3 (2006/06/30) 新規追加
355         *
356         * @return      スケジュールされている 1 回以上実行されない場合に true
357         * @see java.util.TimerTask#cancel()
358         */
359        @Override
360        public boolean cancel() {
361                running = false;
362                return super.cancel();
363        }
364}