    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/SQｌの実行時にｴﾗｰが発生しました。\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}