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