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/SQlの実行時にエラーが発生しました。\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}