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