001/*
002 * Copyright (c) 2017 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.fileexec;
017
018import java.nio.file.Files;
019import java.nio.file.Path;
020import java.util.Arrays;
021import java.nio.file.PathMatcher;
022
023import static org.opengion.fukurou.fileexec.CommandLine.GE70;           // enum を簡素化して使用するための定義
024
025/**
026 * FileExec は、処理の中心で、デーモン一つに対応する処理開始クラスです。
027 *
028 *<pre>
029 * このクラスは、ファイルスキャンのフォルダ単位に、起動され、ファイルのイベントを処理します。
030 *</pre>
031 *
032 * @og.rev 7.0.0.0 (2017/07/07) 新規作成
033 *
034 * @version  7.0
035 * @author   Kazuhiko Hasegawa
036 * @since    JDK1.8,
037 */
038public class FileExec {
039        private static final XLogger LOGGER= XLogger.getLogger( FileExec.class.getSimpleName() );               // ログ出力
040
041        /** システム依存の改行記号(String)。        */
042        public static final String CR = System.getProperty("line.separator");
043
044        private final TBL_GE71  tableGE71 ;             // 6.9.7.0 (2018/05/14) PMD
045
046        private final String    systemId ;              // システムID
047        private final String    rsrvNo;                 // 予約番号
048        private final String    execId;                 // 処理ID
049
050        private final String    fileFltr ;              // 検索条件
051
052        private final BasePath  basePath ;              // 各種パスを管理しているクラス
053
054        private final FileWatch fWatch ;                // 取込フォルダをイベントで監視する
055
056        // 7.2.1.0 (2020/03/13) 拡張子が properties と bat と jar は対象外にします。
057        private static final String PROP = ".properties" ;
058        private static final String BAT  = ".bat" ;
059        private static final String JAR  = ".jar" ;
060
061        // 7.2.1.0 (2020/03/13) 拡張子が properties , bat , jar と WORK,OK,NG は対象外にします。
062        private static final PathMatcher SCAN_EXT = path -> {
063//              final String fname = path.getFileName().toString();
064                final String fname = FileUtil.pathFileName( path );             // 7.2.9.4 (2020/11/20) Path.getFileName().toString()
065                return  !( fname.endsWith( PROP ) || fname.endsWith( BAT ) || fname.endsWith( JAR ) );
066        };
067
068        /**
069         * コマンドラインを引数に取るコンストラクター
070         *
071         * ファイルの監視を開始します。
072         *
073         * @og.rev 6.8.1.5 (2017/09/08) LOGGER.debug 情報の追加
074         * @og.rev 7.2.1.0 (2020/03/13) WORK_PATH,OK_PATH,NG_PATH のスキャンは行わない
075         *
076         * @param       cmndLine        コマンドラインオブジェクト
077         */
078        public FileExec( final CommandLine cmndLine ) {
079                LOGGER.debug( () -> "② CommandLine=" + cmndLine );
080
081                systemId        = cmndLine.getValue( GE70.SYSTEM_ID );          // システムID
082                rsrvNo          = cmndLine.getValue( GE70.RSRV_NO );            // 予約番号
083                execId          = cmndLine.getValue( GE70.EXECID );                     // 処理ID
084                fileFltr        = cmndLine.getValue( GE70.FILE_FILTER );        // 検索条件
085
086                basePath = new BasePath(
087                                        cmndLine.getValue( GE70.DIR_BASE )              ,       // 取込ベースフォルダ
088                                        cmndLine.getValue( GE70.DIR_SUB  )              ,       // 取込サブフォルダ
089                                        cmndLine.getValue( GE70.DIR_WORK    )   ,       // 処理フォルダ(WORK)
090                                        cmndLine.getValue( GE70.DIR_BKUP_OK )   ,       // 処理済フォルダ(正常)
091                                        cmndLine.getValue( GE70.DIR_BKUP_NG ) );        // 処理済フォルダ(異常)
092
093                tableGE71 = new TBL_GE71( systemId,rsrvNo,execId );             // 6.9.7.0 (2018/05/14) PMD
094
095                fWatch  = new FileWatch( basePath.SUB_PATH );                   // サブフォルダをイベントで監視する
096                fWatch.setPathMatcher( SCAN_EXT );                                                              // 7.2.1.0 (2020/03/13)
097                fWatch.setPathMatcher( path -> basePath.isScanPath( path ) );   // 7.2.1.0 (2020/03/13)
098        }
099
100        /**
101         * このコマンドに対応するフォルダの監視を開始します。
102         *
103         * @og.rev 6.8.1.5 (2017/09/08) LOGGER.debug 情報の追加
104         */
105        public void watchStart() {
106                LOGGER.debug( () -> "④ [watchStart()]" );
107
108                fWatch.setEventKinds( FileWatch.CREATE,FileWatch.MODIFY );
109                fWatch.setPathMatcher( new PathMatcherSet().addFileName( fileFltr ) );          // ファイルの検索条件
110                fWatch.callback( (event,fPath) -> checkFile( event,fPath ) );
111                fWatch.start();
112        }
113
114        /**
115         * このコマンドに対応するフォルダの監視を終了します。
116         *
117         * @og.rev 6.8.1.5 (2017/09/08) LOGGER.debug 情報の追加
118         */
119        public void watchStop() {
120                LOGGER.debug( () -> "⑩ [watchStop()]" );
121
122                AppliExec.removeInstance( systemId,rsrvNo );            // 7.2.1.0 (2020/03/13)
123
124                fWatch.stop();
125        }
126
127        /**
128         * 更新されたファイルをチェックします。
129         *
130         * ※ バックアップ処理してから、DB取り込み処理を行います。
131         * よって、DB登録処理中にエラーが発生した場合でも、バックアップ済みです
132         *
133         * @og.rev 6.8.1.5 (2017/09/08) LOGGER.debug 情報の追加
134         * @og.rev 7.2.1.0 (2020/03/13) ディレクトリか存在しない場合は、処理を実行しません。
135         *
136         * @param       event     発生イベントの名称
137         * @param       filePath ファイルパス(相対パス)
138         */
139        private void checkFile( final String event,final Path filePath ) {
140                if( Files.isDirectory( filePath ) || !Files.exists( filePath ) ) { return; }    // 7.2.1.0 (2020/03/13)
141
142                String  fgtKan  = "0" ;                 // 取込完了フラグ 0:取込なし 1:処理中 2:済 7:デーモンエラー 8:アプリエラー
143                Path    bkup    = null;
144                String  errMsg  = "";
145                int             suKekka = -1;
146
147                final String  tmStr = StringUtil.getTimeFormat();                                               // 開始時刻 (PMDでexit point警告が出るが、開始時刻なので仕方がない)
148                AppliExec appli = null;
149                try {
150                        // FileUtil.stablePath は、書き込まれている途中かもしれないので、安定するまで待つ。
151                        if( FileUtil.stablePath( filePath ) ) {
152                                LOGGER.debug( () -> "⑤ event=" + event + " , Path=" + filePath );
153
154                                appli = AppliExec.newInstance( systemId,rsrvNo,execId );                // 7.2.1.0 (2020/03/13)
155                                // ワークへ移動してから、DB取り込み処理を行います。
156                                bkup = FileUtil.backup( filePath,basePath.WORK_PATH );                  // WORKに移動します。
157                                suKekka = appli.exec( bkup );
158
159                                if( suKekka >= 0 ) {
160//                                      okFile = FileUtil.backup( bkup,basePath.OK_PATH );                      // 処理済OKフォルダに移動
161                                        fgtKan = "2" ;          // 2:済
162                                }
163                                else {
164//                                      ngFile = FileUtil.backup( bkup,basePath.NG_PATH );                      // 処理済NGフォルダに移動
165                                        fgtKan = "8" ;          // 8:アプリエラー
166                                }
167
168//                              tableGE71.dbInsert( fgtKan,tmStr,filePath,okFile,ngFile,suKekka,errMsg );
169
170        //                      LOGGER.info( () -> "DAT execute. " + filePath + " , FGTKAN=" + fgtKan + " , kensu=" + suKekka );
171                        }
172                        else {
173                                // エラーにせず、ワークへ移動もせず、保留にします。
174                                LOGGER.info( () -> "checkFile Not stablePath. " + filePath );
175                                return ;
176                        }
177                }
178                catch( final Throwable th ) {
179                        fgtKan = "7" ;                          // 7:デーモンエラー
180
181                        // MSG0021 = 予期せぬエラーが発生しました。\n\tメッセージ=[{0}]
182                        errMsg = MsgUtil.errPrintln( th,"MSG0021",filePath );
183
184                        // 6.9.8.0 (2018/05/28) FindBugs: メソッド呼び出しは非 null パラメータに対して null を渡している
185//                      if( Files.exists( bkup ) ) {                                                            // WORKに移動するところまでは、成功しており、その後の、移動ができていない。
186//                      if( bkup != null && Files.exists( bkup ) ) {                            // WORKに移動するところまでは、成功しており、その後の、移動ができていない。
187//                              ngFile = FileUtil.backup( bkup,basePath.NG_PATH );              // 処理済NGフォルダに移動
188//                      }
189
190//                      tableGE71.dbInsert( fgtKan,tmStr,filePath,okFile,ngFile,suKekka,errMsg );
191                }
192
193                // checkFile Not stablePath. の時は、appli == null
194                if( appli != null ) {
195                        try {
196                                // appli.exec が正常でもエラーでも実行する。
197                                appli.endExec( bkup,fgtKan,errMsg );
198                        }
199                        catch( final Throwable th ) {
200                                if( ! "7".equals( fgtKan ) ) {                                          // 7:デーモンエラーは、上書きしない。
201                                        fgtKan = "8" ;
202                                }
203                                // MSG0032 = PL/SQlの実行時にエラーが発生しました。\n\t[{0}]
204                                errMsg = MsgUtil.errPrintln( th,"MSG0032",filePath );
205                        }
206                }
207
208                // 6.9.8.0 (2018/05/28) FindBugs: メソッド呼び出しは非 null パラメータに対して null を渡している
209                Path    okFile  = null;
210                Path    ngFile  = null;
211                if( bkup != null && Files.exists( bkup ) ) {                            // WORKに移動するところまでは、成功しており、その後の、移動ができていない。
212                        if( "2".equals( fgtKan ) ) {
213                                okFile = FileUtil.backup( bkup,basePath.OK_PATH );              // 処理済OKフォルダに移動
214                        }
215                        else {
216                                ngFile = FileUtil.backup( bkup,basePath.NG_PATH );              // 処理済NGフォルダに移動
217                        }
218                }
219
220                tableGE71.dbInsert( fgtKan,tmStr,filePath,okFile,ngFile,suKekka,errMsg );
221        }
222
223        /**
224         *このクラスの文字列表現を返します。
225         *
226         * @return      クラスの文字列表現
227         */
228        @Override
229        public String toString() {
230//              return systemId + " , " + execId ;
231                return String.join( ",",systemId,rsrvNo,execId );               // 6.9.7.0 (2018/05/14) PMD
232        }
233
234        /**
235         * GE71 実行結果をデータベースに書き込む内部クラスです。 ( 6.9.7.0 (2018/05/14) PMD )
236         */
237        private static final class TBL_GE71 {
238                private static final String[] KEYS              = new String[] {  "SYSTEM_ID","RSRV_NO","EXECID","FGTKAN","TMSTR","TMEND"
239                                                                                                                                , "FILE_IN","FILE_OK","FILE_NG","SUTORI ","ERRMSG "
240                                                                                                                                , "DYSET","DYUPD" };
241                private static final String[] CON_KEYS  = new String[] { "FGJ","PGSET"  ,"PGUPD"  };
242                private static final String[] CON_VALS  = new String[] { "1"  ,"FileExec","FileExec" };
243
244                private static final String INS_QUERY = DBUtil.getInsertSQL( "GE71",KEYS,CON_KEYS,CON_VALS );
245
246                private final String systemId ;                 // システムID
247                private final String rsrvNo;                    // 予約番号
248                private final String execId ;                   // 処理ID
249
250                /**
251                 * GE71 データベースにインサート処理を行うクラスのコンストラクター
252                 *
253                 * @param       sysId   システムID
254                 * @param       rsNo    予約番号
255                 * @param       exId    処理ID
256                 */
257                public TBL_GE71( final String sysId,final String rsNo ,final String exId ) {
258                        systemId = sysId ;
259                        rsrvNo   = rsNo ;
260                        execId   = exId;
261                }
262
263                /**
264                 * データベースにインサート処理を行います。
265                 *
266                 * @og.rev 6.8.1.5 (2017/09/08) LOGGER.debug 情報の追加
267                 * @og.rev 7.2.9.4 (2020/11/20) spotbugs:null になっている可能性があるメソッドの戻り値を利用している
268                 *
269                 * @param       fgtKan  取込完了フラグ
270                 * @param       tmStr   開始時刻
271                 * @param       fIn             取込ファイルパス
272                 * @param       fOk             処理済OKファイルパス
273                 * @param       fNg             処理済NGファイルパス
274                 * @param       sutori  取込数
275                 * @param       errMsg  エラーメッセージ
276                 */
277                public void dbInsert( final String fgtKan,final String tmStr,final Path fIn,final Path fOk,final Path fNg,final int sutori,final String errMsg ) {
278                        final String NOW = StringUtil.getTimeFormat();
279
280                        // ファイルは、ファイル名のみとします。
281                        // 7.2.9.4 (2020/11/20) spotbugs:null になっている可能性があるメソッドの戻り値を利用している
282//                      final String fileIn = fIn == null ? "" : fIn.getFileName().toString() ;
283//                      final String fileOk = fOk == null ? "" : fOk.getFileName().toString() ;
284//                      final String fileNg = fNg == null ? "" : fNg.getFileName().toString() ;
285
286                        final String fileIn = FileUtil.pathFileName( fIn ) ;            // 7.2.9.4 (2020/11/20) Path.getFileName().toString()
287                        final String fileOk = FileUtil.pathFileName( fOk ) ;            // 7.2.9.4 (2020/11/20) Path.getFileName().toString()
288                        final String fileNg = FileUtil.pathFileName( fNg ) ;            // 7.2.9.4 (2020/11/20) Path.getFileName().toString()
289
290                        // GE71 テーブルのカラム
291                        final String[] values = new String[] {
292                                  systemId                                      // システムID               SYSTEM_ID
293                                , rsrvNo                                        // 予約番号         RSRV_NO
294                                , execId                                        // 処理ID         EXECID
295                                , fgtKan                                        // 取込完了フラグ     FGTKAN
296                                , tmStr                                         // 開始時刻         TMSTR
297                                , NOW                                           // 完了時刻         TMEND
298                                , fileIn                                        // 取込ファイル               FILE_IN
299                                , fileOk                                        // 処理済OKファイル    FILE_OK
300                                , fileNg                                        // 処理済NGファイル    FILE_NG
301                                , String.valueOf( sutori )      // 取込件数         SUTORI
302                                , errMsg                                        // エラーメッセージ    ERRMSG
303                                , NOW                                           // 登録日時         DYSET
304                                , NOW                                           // 更新日時         DYUPD
305                        } ;
306
307                        LOGGER.debug( () -> "⑥ GE71.dbInsert query=" + INS_QUERY + "\n\t values=" + Arrays.toString( values ) );
308
309                        DBUtil.execute( INS_QUERY,values );
310                }
311        }
312}