    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.getName() );             // ログ出力
    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                return  !( fname.endsWith( PROP ) || fname.endsWith( BAT ) || fname.endsWith( JAR ) );
    065        };
    066
    067        /**
    068         * コマンドラインを引数に取るコンストラクター
    069         *
    070         * ファイルの監視を開始します。
    071         *
    072         * @og.rev 6.8.1.5 (2017/09/08) LOGGER.debug 情報の追加
    073         * @og.rev 7.2.1.0 (2020/03/13) WORK_PATH,OK_PATH,NG_PATH のスキャンは行わない
    074         *
    075         * @param       cmndLine        コマンドラインオブジェクト
    076         */
    077        public FileExec( final CommandLine cmndLine ) {
    078                LOGGER.debug( () -> "② CommandLine=" + cmndLine );
    079
    080                systemId        = cmndLine.getValue( GE70.SYSTEM_ID );          // ｼｽﾃﾑID
    081                rsrvNo          = cmndLine.getValue( GE70.RSRV_NO );            // 予約番号
    082                execId          = cmndLine.getValue( GE70.EXECID );                     // 処理ID
    083                fileFltr        = cmndLine.getValue( GE70.FILE_FILTER );        // 検索条件
    084
    085                basePath = new BasePath(
    086                                        cmndLine.getValue( GE70.DIR_BASE )              ,       // 取込ﾍﾞｰｽﾌｫﾙﾀﾞ
    087                                        cmndLine.getValue( GE70.DIR_SUB  )              ,       // 取込ｻﾌﾞﾌｫﾙﾀﾞ
    088                                        cmndLine.getValue( GE70.DIR_WORK    )   ,       // 処理ﾌｫﾙﾀﾞ(WORK)
    089                                        cmndLine.getValue( GE70.DIR_BKUP_OK )   ,       // 処理済ﾌｫﾙﾀﾞ(正常)
    090                                        cmndLine.getValue( GE70.DIR_BKUP_NG ) );        // 処理済ﾌｫﾙﾀﾞ(異常)
    091
    092                tableGE71 = new TBL_GE71( systemId,rsrvNo,execId );             // 6.9.7.0 (2018/05/14) PMD
    093
    094                fWatch  = new FileWatch( basePath.SUB_PATH );                   // ｻﾌﾞﾌｫﾙﾀﾞをイベントで監視する
    095                fWatch.setPathMatcher( SCAN_EXT );                                                              // 7.2.1.0 (2020/03/13)
    096                fWatch.setPathMatcher( path -> basePath.isScanPath( path ) );   // 7.2.1.0 (2020/03/13)
    097        }
    098
    099        /**
    100         * このコマンドに対応するフォルダの監視を開始します。
    101         *
    102         * @og.rev 6.8.1.5 (2017/09/08) LOGGER.debug 情報の追加
    103         */
    104        public void watchStart() {
    105                LOGGER.debug( () -> "④ [watchStart()]" );
    106
    107                fWatch.setEventKinds( FileWatch.CREATE,FileWatch.MODIFY );
    108                fWatch.setPathMatcher( new PathMatcherSet().addFileName( fileFltr ) );          // ファイルの検索条件
    109                fWatch.callback( (event,fPath) -> checkFile( event,fPath ) );
    110                fWatch.start();
    111        }
    112
    113        /**
    114         * このコマンドに対応するフォルダの監視を終了します。
    115         *
    116         * @og.rev 6.8.1.5 (2017/09/08) LOGGER.debug 情報の追加
    117         */
    118        public void watchStop() {
    119                LOGGER.debug( () -> "⑩ [watchStop()]" );
    120
    121                AppliExec.removeInstance( systemId,rsrvNo );            // 7.2.1.0 (2020/03/13)
    122
    123                fWatch.stop();
    124        }
    125
    126        /**
    127         * 更新されたファイルをチェックします。
    128         *
    129         * ※ バックアップ処理してから、DB取り込み処理を行います。
    130         * よって、DB登録処理中にエラーが発生した場合でも、バックアップ済みです
    131         *
    132         * @og.rev 6.8.1.5 (2017/09/08) LOGGER.debug 情報の追加
    133         * @og.rev 7.2.1.0 (2020/03/13) ﾃﾞｨﾚｸﾄﾘか存在しない場合は、処理を実行しません。
    134         *
    135         * @param       event     発生イベントの名称
    136         * @param       filePath ファイルパス(相対パス)
    137         */
    138        private void checkFile( final String event,final Path filePath ) {
    139                if( Files.isDirectory( filePath ) || !Files.exists( filePath ) ) { return; }    // 7.2.1.0 (2020/03/13)
    140
    141                String  fgtKan  = "0" ;                 // 取込完了ﾌﾗｸﾞ 0:取込なし 1:処理中 2:済 7:ﾃﾞｰﾓﾝｴﾗｰ 8:ｱﾌﾟﾘｴﾗｰ
    142                Path    bkup    = null;
    143                String  errMsg  = "";
    144                int             suKekka = -1;
    145
    146                final String  tmStr = StringUtil.getTimeFormat();                                                               // 開始時刻
    147                AppliExec appli = null;
    148                try {
    149                        // FileUtil.stablePath は、書き込まれている途中かもしれないので、安定するまで待つ。
    150                        if( FileUtil.stablePath( filePath ) ) {
    151                                LOGGER.debug( () -> "⑤ event=" + event + " , Path=" + filePath );
    152
    153                                appli = AppliExec.newInstance( systemId,rsrvNo,execId );                // 7.2.1.0 (2020/03/13)
    154                                // ワークへ移動してから、DB取り込み処理を行います。
    155                                bkup = FileUtil.backup( filePath,basePath.WORK_PATH );                  // WORKに移動します。
    156                                suKekka = appli.exec( bkup );
    157
    158                                if( suKekka >= 0 ) {
    159//                                      okFile = FileUtil.backup( bkup,basePath.OK_PATH );                      // 処理済OKﾌｫﾙﾀﾞに移動
    160                                        fgtKan = "2" ;          // 2:済
    161                                }
    162                                else {
    163//                                      ngFile = FileUtil.backup( bkup,basePath.NG_PATH );                      // 処理済NGﾌｫﾙﾀﾞに移動
    164                                        fgtKan = "8" ;          // 8:ｱﾌﾟﾘｴﾗｰ
    165                                }
    166
    167//                              tableGE71.dbInsert( fgtKan,tmStr,filePath,okFile,ngFile,suKekka,errMsg );
    168
    169        //                      LOGGER.info( () -> "DAT execute. " + filePath + " , FGTKAN=" + fgtKan + " , kensu=" + suKekka );
    170                        }
    171                        else {
    172                                // エラーにせず、ワークへ移動もせず、保留にします。
    173                                LOGGER.info( () -> "checkFile Not stablePath. " + filePath );
    174                                return ;
    175                        }
    176                }
    177                catch( final Throwable th ) {
    178                        fgtKan = "7" ;                          // 7:ﾃﾞｰﾓﾝｴﾗｰ
    179
    180                        // MSG0021 = 予期せぬエラーが発生しました。\n\tﾒｯｾｰｼﾞ=[{0}]
    181                        errMsg = MsgUtil.errPrintln( th,"MSG0021",filePath );
    182
    183                        // 6.9.8.0 (2018/05/28) FindBugs: メソッド呼び出しは非 null パラメータに対して null を渡している
    184//                      if( Files.exists( bkup ) ) {                                                            // WORKに移動するところまでは、成功しており、その後の、移動ができていない。
    185//                      if( bkup != null && Files.exists( bkup ) ) {                            // WORKに移動するところまでは、成功しており、その後の、移動ができていない。
    186//                              ngFile = FileUtil.backup( bkup,basePath.NG_PATH );              // 処理済NGﾌｫﾙﾀﾞに移動
    187//                      }
    188
    189//                      tableGE71.dbInsert( fgtKan,tmStr,filePath,okFile,ngFile,suKekka,errMsg );
    190                }
    191
    192                // checkFile Not stablePath. の時は、appli == null
    193                if( appli != null ) {
    194                        try {
    195                                // appli.exec が正常でもｴﾗｰでも実行する。
    196                                appli.endExec( bkup,fgtKan,errMsg );
    197                        }
    198                        catch( final Throwable th ) {
    199                                if( fgtKan != "7" ) {                                   // 7:ﾃﾞｰﾓﾝｴﾗｰは、上書きしない。
    200                                        fgtKan = "8" ;
    201                                }
    202                                // MSG0029 = PL/SQｌの実行時にエラーが発生しました。\n\t[{0}]
    203                                errMsg = MsgUtil.errPrintln( th,"MSG0029",filePath );
    204                        }
    205                }
    206
    207                // 6.9.8.0 (2018/05/28) FindBugs: メソッド呼び出しは非 null パラメータに対して null を渡している
    208                Path    okFile  = null;
    209                Path    ngFile  = null;
    210                if( bkup != null && Files.exists( bkup ) ) {                            // WORKに移動するところまでは、成功しており、その後の、移動ができていない。
    211                        if( "2".equals( fgtKan ) ) {
    212                                okFile = FileUtil.backup( bkup,basePath.OK_PATH );              // 処理済OKﾌｫﾙﾀﾞに移動
    213                        }
    214                        else {
    215                                ngFile = FileUtil.backup( bkup,basePath.NG_PATH );              // 処理済NGﾌｫﾙﾀﾞに移動
    216                        }
    217                }
    218
    219                tableGE71.dbInsert( fgtKan,tmStr,filePath,okFile,ngFile,suKekka,errMsg );
    220        }
    221
    222        /**
    223         *このクラスの文字列表現を返します。
    224         *
    225         * @return      クラスの文字列表現
    226         */
    227        @Override
    228        public String toString() {
    229//              return systemId + " , " + execId ;
    230                return String.join( ",",systemId,rsrvNo,execId );               // 6.9.7.0 (2018/05/14) PMD
    231        }
    232
    233        /**
    234         * GE71 実行結果をデータベースに書き込む内部クラスです。 ( 6.9.7.0 (2018/05/14) PMD )
    235         */
    236        private static final class TBL_GE71 {
    237                private static final String[] KEYS              = new String[] {  "SYSTEM_ID","RSRV_NO","EXECID","FGTKAN","TMSTR","TMEND"
    238                                                                                                                                , "FILE_IN","FILE_OK","FILE_NG","SUTORI ","ERRMSG "
    239                                                                                                                                , "DYSET","DYUPD" };
    240                private static final String[] CON_KEYS  = new String[] { "FGJ","PGSET"  ,"PGUPD"  };
    241                private static final String[] CON_VALS  = new String[] { "1"  ,"FileExec","FileExec" };
    242
    243                private static final String INS_QUERY = DBUtil.getInsertSQL( "GE71",KEYS,CON_KEYS,CON_VALS );
    244
    245                private final String systemId ;                 // システムID
    246                private final String rsrvNo;                    // 予約番号
    247                private final String execId ;                   // 処理ID
    248
    249                /**
    250                 * GE71 データベースにインサート処理を行うクラスのコンストラクター
    251                 *
    252                 * @param       sysId   システムID
    253                 * @param       rsNo    予約番号
    254                 * @param       exId    処理ID
    255                 */
    256                public TBL_GE71( final String sysId,final String rsNo ,final String exId ) {
    257                        systemId = sysId ;
    258                        rsrvNo   = rsNo ;
    259                        execId   = exId;
    260                }
    261
    262                /**
    263                 * データベースにインサート処理を行います。
    264                 *
    265                 * @og.rev 6.8.1.5 (2017/09/08) LOGGER.debug 情報の追加
    266                 *
    267                 * @param       fgtKan  取込完了ﾌﾗｸﾞ
    268                 * @param       tmStr   開始時刻
    269                 * @param       fIn             取込ﾌｧｲﾙパス
    270                 * @param       fOk             処理済OKﾌｧｲﾙパス
    271                 * @param       fNg             処理済NGﾌｧｲﾙパス
    272                 * @param       sutori  取込数
    273                 * @param       errMsg  ｴﾗｰﾒｯｾｰｼﾞ
    274                 */
    275                public void dbInsert( final String fgtKan,final String tmStr,final Path fIn,final Path fOk,final Path fNg,final int sutori,final String errMsg ) {
    276                        final String NOW = StringUtil.getTimeFormat();
    277
    278                        // ﾌｧｲﾙは、ﾌｧｲﾙ名のみとします。
    279                        final String fileIn = fIn == null ? "" : fIn.getFileName().toString() ;
    280                        final String fileOk = fOk == null ? "" : fOk.getFileName().toString() ;
    281                        final String fileNg = fNg == null ? "" : fNg.getFileName().toString() ;
    282
    283                        // GE71 テーブルのカラム
    284                        final String[] values = new String[] {
    285                                  systemId                                      // ｼｽﾃﾑID               SYSTEM_ID
    286                                , rsrvNo                                        // 予約番号         RSRV_NO
    287                                , execId                                        // 処理ID         EXECID
    288                                , fgtKan                                        // 取込完了ﾌﾗｸﾞ     FGTKAN
    289                                , tmStr                                         // 開始時刻         TMSTR
    290                                , NOW                                           // 完了時刻         TMEND
    291                                , fileIn                                        // 取込ﾌｧｲﾙ               FILE_IN
    292                                , fileOk                                        // 処理済OKﾌｧｲﾙ    FILE_OK
    293                                , fileNg                                        // 処理済NGﾌｧｲﾙ    FILE_NG
    294                                , String.valueOf( sutori )      // 取込件数         SUTORI
    295                                , errMsg                                        // ｴﾗｰﾒｯｾｰｼﾞ    ERRMSG
    296                                , NOW                                           // 登録日時         DYSET
    297                                , NOW                                           // 更新日時         DYUPD
    298                        } ;
    299
    300                        LOGGER.debug( () -> "⑥ GE71.dbInsert query=" + INS_QUERY + "\n\t values=" + Arrays.toString( values ) );
    301
    302                        DBUtil.execute( INS_QUERY,values );
    303                }
    304        }
    305}