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 018// import java.util.Arrays; 019import java.util.List; 020import java.util.Set; // 7.2.5.0 (2020/06/01) 021// import java.util.HashSet; // 7.2.5.0 (2020/06/01) 022import java.util.Collections; // 7.2.9.4 (2020/11/20) 023import java.util.concurrent.ConcurrentMap; 024import java.util.concurrent.ConcurrentHashMap; 025import java.util.concurrent.ScheduledFuture; // 7.2.5.0 (2020/06/01) 026import java.util.concurrent.ScheduledExecutorService; // 7.2.5.0 (2020/06/01) 027import java.util.concurrent.Executors; // 7.2.5.0 (2020/06/01) 028import java.util.concurrent.TimeUnit; // 7.2.5.0 (2020/06/01) 029import java.util.concurrent.atomic.AtomicBoolean; // 7.2.9.4 (2020/11/20) volatile boolean の代替え 030 031import org.opengion.fukurou.system.HybsConst; // 7.2.5.0 (2020/06/01) 032import static org.opengion.fukurou.fileexec.CommandLine.GE70; // enum を簡素化して使用するための定義 033 034/** 035 * MainProcess は、単独で使用する ファイル取込システムのメインクラスです。 036 * 037 *<pre> 038 * このクラスのmainメソッドから起動します。 039 * コマンドラインを処理することで、各種処理を実行します。 040 * 041 *</pre> 042 * 043 * @og.rev 7.0.0.0 (2017/07/07) 新規作成 044 * @og.rev 7.2.5.0 (2020/06/01) TomcatのServletContextListenerから実行できるように修正 045 * 046 * @version 7.0 047 * @author Kazuhiko Hasegawa 048 * @since JDK1.8, 049 */ 050// public final class MainProcess { 051public final class MainProcess implements Runnable { 052 private static final XLogger LOGGER= XLogger.getLogger( MainProcess.class.getSimpleName() ); // ログ出力 053 054 /** 7.2.5.0 (2020/06/01) エラーの場合、リロードするが、その待機時間 {@value}(秒) */ 055 public static final long WAIT_TIME = 30 * 1000L; 056 057// private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5); // 1.5.0 (2020/04/01) 058 private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(5); // 7.2.9.4 (2020/11/20) 1.5.0 (2020/04/01) 059// private static final Set<ScheduledFuture<?>> futureSet = new HashSet<>(); 060 // 8.5.4.2 (2024/01/12) PMD 7.0.0 UseDiamondOperator 対応 061// private static final Set<ScheduledFuture<?>> FUTURE_SET = Collections.newSetFromMap( new ConcurrentHashMap<ScheduledFuture<?>, Boolean>() ); // 7.2.9.4 (2020/11/20) 062 private static final Set<ScheduledFuture<?>> FUTURE_SET = Collections.newSetFromMap( new ConcurrentHashMap<>() ); // 7.2.9.4 (2020/11/20) 063 064 /** 7.2.5.0 (2020/06/01) 開始しているかどうかを確認するための状態変数 */ 065// private static volatile boolean isStart ; 066 private static final AtomicBoolean IS_START = new AtomicBoolean(); // 7.2.9.4 (2020/11/20) volatile boolean の代替え 067 068 /** 7.2.5.0 (2020/06/01) MainProcess は、シングルインスタンスとして扱います。 */ 069 private static MainProcess mainPrcs ; 070 071 // 7.2.9.4 (2020/11/20) staticレベルのロック 072 private static final Object STATIC_LOCK = new Object(); 073 074 private final ConcurrentMap<String,FileExec> execMap = new ConcurrentHashMap<>(); // キーは、systemId + rsrv_no 075 076 private int cnt ; 077 078 /** 079 * デフォルトコンストラクターをprivateにして、 080 * オブジェクトの生成をさせないようにする。 081 * 082 * @og.rev 7.2.5.0 (2020/06/01) シングルインスタンス 083 */ 084// public MainProcess() { super(); } // 必要ないが、とりあえず。 085 private MainProcess() { 086 LOGGER.info( () -> "MainProcess Start! " ); 087 } 088 089 /** 090 * MainProcess は、シングルインスタンスです。 091 * 092 * 既存のインスタンスか、新しいインスタンスを作成して返します。 093 * serverフォルダ は必須です。 094 * 095 * @og.rev 7.2.5.0 (2020/06/01) シングルインスタンス 096 * @og.rev 7.2.9.4 (2020/11/20) staticレベルのロック 097 * 098 * @return 新しいインスタンス または、既存のインスタンス 099 */ 100// synchronized public static MainProcess getInstance() { 101 public static MainProcess getInstance() { 102 synchronized( STATIC_LOCK ) { 103 if( mainPrcs == null ) { 104 mainPrcs = new MainProcess(); 105 } 106 } 107 108 return mainPrcs; 109 } 110 111 /** 112 * 開始処理を行います。 113 * 114 * 内部で自身のインスタンスを作成して、ScheduledExecutorService で繰り返し実行します。 115 * 116 * @og.rev 7.2.5.0 (2020/06/01) シングルインスタンス 117 * @og.rev 7.2.9.4 (2020/11/20) static final の大文字化 118 * @og.rev 7.2.9.4 (2020/11/20) PMD:volatile boolean の代替え。 119 * @og.rev 7.2.9.4 (2020/11/20) staticレベルのロック 120 */ 121// synchronized public static void start() { 122 public static void start() { 123 try { 124// if( futureSet.isEmpty() ) { // 何度でも実行できるように 125 if( FUTURE_SET.isEmpty() ) { // 何度でも実行できるように 126// final MainProcess mainPrcs = getInstance(); 127 final MainProcess localPrcs ; 128 synchronized( STATIC_LOCK ) { // 7.2.9.4 (2020/11/20) staticレベルのロック 129 localPrcs = getInstance(); 130 } 131 132 // ********** 【初期値定義】 ********** 133 final String loopStr = HybsConst.getenv( "loop" ); // スキャンするインターバル(秒) 134 final long loopSec = loopStr == null || loopStr.isEmpty() ? 30L : Long.parseLong( loopStr ); // スキャンするインターバル(秒) 135 136 // // 一定時間ごとに処理を実行 開始タスク , 初回遅延 , 繰返間隔 , スケール(秒) 137 // futureSet.add( scheduler.scheduleAtFixedRate( localPrcs , 0 , loopSec , TimeUnit.SECONDS ) ); 138 139 // エラー時に繰り返し間隔より長く待機させる。 140 // 処理の完了を待ってから一定時間待機 開始タスク , 初回遅延 , 待機時間 , スケール(秒) 141// futureSet.add( scheduler.scheduleWithFixedDelay( localPrcs , 0 , loopSec , TimeUnit.SECONDS ) ); 142 FUTURE_SET.add( SCHEDULER.scheduleWithFixedDelay( localPrcs , 0 , loopSec , TimeUnit.SECONDS ) ); // 7.2.9.4 (2020/11/20) 143 144// isStart = true; 145 IS_START.set( true ); // 7.2.9.4 (2020/11/20) 146 } 147 } 148 catch( final Throwable th ) { 149 // MSG0021 = 予期せぬエラーが発生しました。\n\tメッセージ=[{0}] 150 final String errMsg = "MainProcess#start" ; 151 LOGGER.warning( th , "MSG0021" , errMsg ); 152 153 shutdown( false ); // エラーなので再実行できるようにしておきます。 154 } 155 } 156 157 /** 158 * 終了処理を行います。 159 * 160 * @og.rev 7.2.5.0 (2020/06/01) シングルインスタンス 161 * @og.rev 7.2.9.4 (2020/11/20) static final の大文字化 162 * @og.rev 7.2.9.4 (2020/11/20) PMD:volatile boolean の代替え。 163 * @og.rev 7.2.9.4 (2020/11/20) staticレベルのロック 164 * 165 * @param flag 完全終了時は true を設定する。 166 */ 167// synchronized public static void shutdown( final boolean flag ) { 168 public static void shutdown( final boolean flag ) { 169 LOGGER.info( () -> "MainProcess Shutdown Starting ..." ); 170// isStart = false; 171 IS_START.set( false ); // 7.2.9.4 (2020/11/20) 172 173// futureSet.forEach( fu -> fu.cancel( true ) ); // 実行中のタスクに割り込む 174// futureSet.clear(); // 初期化しておく 175 176 FUTURE_SET.forEach( fu -> fu.cancel( true ) ); // 7.2.9.4 (2020/11/20) 実行中のタスクに割り込む 177 FUTURE_SET.clear(); // 7.2.9.4 (2020/11/20) 初期化しておく 178 179 if( flag ) { 180// scheduler.shutdownNow(); // trueの場合、再実行できなくなる。 181 SCHEDULER.shutdownNow(); // 7.2.9.4 (2020/11/20) trueの場合、再実行できなくなる。 182 } 183 184 synchronized( STATIC_LOCK ) { // 7.2.9.4 (2020/11/20) staticレベルのロック 185 if( mainPrcs != null ) { 186 // 必要ないかもしれませんが、正常終了させます。 187 mainPrcs.watchStop(); 188 } 189 mainPrcs = null; 190 } 191 192 LOGGER.info( () -> "MainProcess Shutdown Complete." ); 193 } 194 195 /** 196 * MainProcess の処理が起動しているかどうかを返します。 197 * 198 * @og.rev 7.2.5.0 (2020/06/01) 新規追加 199 * @og.rev 7.2.9.4 (2020/11/20) PMD:volatile boolean の代替え。 200 * 201 * @return true:起動中/false:停止中 202 */ 203 public static boolean isStarted() { 204// return isStart ; 205 return IS_START.get(); // 7.2.9.4 (2020/11/20) 206 } 207 208 /** 209 * 時間起動のタスクオブジェクトを起動します。 210 * 211 * コマンドリストは、予約番号,種別,号機指定,雛形ファイル,開始日時,実行間隔,終了日時,経過終了間隔,パラメータMAP を 212 * 文字列として順番に持っています。 213 * リストの数が、少ない場合は、それぞれ、初期値が使用されます。 214 * 最低、コマンド種別は、必要です。 215 * 216 * @param cmndLine CommandLineオブジェクト 217 */ 218 private void startTask( final CommandLine cmndLine ) { 219 // タスクオブジェクトの起動前に、一旦過去の依頼は停止しておきます。 220 final String systemId = cmndLine.getValue( GE70.SYSTEM_ID ); // システムID 221 final String rsrvNo = cmndLine.getValue( GE70.RSRV_NO ); // 予約番号 222 final String mapKey = systemId + "_" + rsrvNo ; 223 stopTask( mapKey ); // 一旦、すべてを停止します。 224 225 // ※ 取込予約フラグ(FGYKAN)は、DB検索時に、1:実行 の場合のみ起動する。 226 final String fgkan = cmndLine.getValue( GE70.FGYKAN ); // 取込予約フラグ 1:実行 2:停止 227 if( "1".equals( fgkan ) ) { // 1:実行 以外は、先に停止されている。 228 final FileExec fExec = new FileExec( cmndLine ); 229 230 LOGGER.info( () -> "startTask: yoyakuNo=[" + mapKey + "]" ); 231 232 fExec.watchStart(); 233 execMap.put( mapKey,fExec ); 234 } 235 else { 236 LOGGER.warning( () -> "【WARNING】startTask: yoyakuNo=[" + mapKey + "] , fgkan=[" + fgkan + "]" ); // 6.8.1.5 (2017/09/08) 237 } 238 } 239 240 /** 241 * 時間起動のタスクオブジェクトをキャンセルします。 242 * 243 * @param mapKey コマンド予約番号時のキーワード 244 */ 245 private void stopTask( final String mapKey ) { 246 final FileExec fExec = execMap.remove( mapKey ); // 取り消しなので、Mapから削除します。 247 if( fExec != null ) { // 完了(正常終了、例外、取り消し)以外は、キャンセルします。 248 fExec.watchStop(); 249 } 250 251 LOGGER.info( () -> "stopTask: yoyakuNo=[" + mapKey + "]" ); 252 } 253 254 /** 255 * すべての成形機のセッションフォルダの監視を終了します。 256 * 257 */ 258 public void watchStop() { 259 execMap.forEach( (no,fExec) -> fExec.watchStop() ); 260 } 261 262 /** 263 * Runnableインターフェースのrunメソッドです。 264 * 265 * ScheduledExecutorService で繰り返し実行させるので、Throwable 全てのを拾う。 266 * 267 * @og.rev 7.2.5.0 (2020/06/01) TomcatのServletContextListenerから実行できるように修正します。 268 */ 269 @Override // Runnable 270 public void run() { 271 try { 272 final List<CommandLine> cmndList = CommandLine.dbCommand(); 273 cmndList.forEach( cmndLine -> startTask( cmndLine ) ); 274 System.out.println( StringUtil.getTimeFormat( "yyyy/MM/dd HH:mm:ss [" + (cnt++) + "]" ) ); // 6.8.1.5 (2017/09/08) 275 } 276 catch( final Throwable th ) { 277 // MSG0021 = 予期せぬエラーが発生しました。\n\tメッセージ=[{0}] 278 final String errMsg = "MainProcess#run" ; 279 LOGGER.warning( th , "MSG0021" , errMsg ); 280 281 shutdown( true ); // 完全終了 282 283 // エラーの場合は、少し待って終了します。 284// try{ Thread.sleep( WAIT_TIME ); } catch( final InterruptedException ex ){} 285 try { Thread.sleep( WAIT_TIME ); } catch( final InterruptedException ignored ) {} // 8.5.4.2 (2024/01/12) PMD 7.0.0 EmptyCatchBlock 286 } 287 } 288 289// /** 290// * ファイル取込システムのメインクラスを起動します。 291// * 292// * <pre> 293// * システムプロパティー定義(例:初期値) 294// * 295// * [-Dloop="10"] : データベースの状態をチェックする間隔(秒)。初期値は、10秒です。 296// * </pre> 297// * 298// * @og.rev 7.2.5.0 (2020/06/01) TomcatのServletContextListenerから実行できるように修正します。 299// * 300// * @param args 引数配列 301// */ 302// public static void main( final String[] args ) { 303// try { 304// MainProcess.start(); 305// } 306// catch( final Throwable th ) { 307// // MSG0021 = 予期せぬエラーが発生しました。\n\tメッセージ=[{0}] 308// final String errMsg = "MainProcess#main" ; 309// LOGGER.warning( th , "MSG0021" , errMsg ); 310// 311// MainProcess.shutdown( true ); // 完全終了処理 312// System.exit( 1 ); // 強制終了します。 313// } 314// 315// // 仮想マシンのシャットダウン・フックを登録 316// final Thread shutdownHook = new Thread( "MainProcess" ) { 317// /** 318// * シャットダウン・フックの実行メソッドです。 319// */ 320// @Override 321// public void run() { 322// MainProcess.shutdown( true ); 323// } 324// }; 325// Runtime.getRuntime().addShutdownHook( shutdownHook ); 326// } 327}