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}