001/* 002 * Copyright (c) 2009 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.util; 017 018import java.util.TimerTask; 019import java.util.Date; 020import java.util.Map; 021import java.util.concurrent.ConcurrentMap; // 6.4.3.3 (2016/03/04) 022import java.util.concurrent.ConcurrentHashMap; // 6.4.3.3 (2016/03/04) 023import java.util.concurrent.atomic.AtomicInteger; // 5.5.2.6 (2012/05/25) findbugs対応 024 025import org.opengion.fukurou.system.OgRuntimeException ; // 6.4.2.0 (2016/01/29) 026import org.opengion.fukurou.system.LogWriter; // 6.4.2.0 (2016/01/29) package変更 fukurou.util → fukurou.system 027import org.opengion.fukurou.system.DateSet; // 6.4.2.0 (2016/01/29) 028 029/** 030 * HybsTimerTask.java は、String 型キーにString型値を Map するクラスです。 031 * 032 * HTMLのPOST/GET等の受け渡しや、String型の引数が多い場合に効果があります。 033 * 特に、getHybsTimerTask( String[] param ) による属性リスト作成は、 034 * HTMLタグの属性定義を行う上で、非常に便利に利用できます。 035 * 036 * この実装は同期化されません。 037 * 038 * @version 4.0 039 * @author Kazuhiko Hasegawa 040 * @since JDK5.0, 041 */ 042public abstract class HybsTimerTask extends TimerTask implements Comparable<HybsTimerTask> { // 4.3.3.6 (2008/11/15) Generics警告対応 043 044 private static AtomicInteger counter = new AtomicInteger(); // 5.5.2.6 (2012/05/25) findbugs対応 045 046 private final int uniqKey ; // タイマータスクのユニークキー 047 private final long createTime = System.currentTimeMillis() ; // オブジェクトが生成された時刻 048 // 3.2.2.0 (2003/05/31) HybsTimerTask に対して、設定値を渡せるように変更。 049 /** 6.4.3.3 (2016/03/04) ConcurrentHashMap に置き換えます。 */ 050 private final ConcurrentMap<String,String> paramMap = new ConcurrentHashMap<>(); // タイマータスクのパラメータ 3.6.0.7 (2004/11/06) 051 052 private String name ; // タイマータスクの名称 053 private String comment ; // タイマータスクの説明 054 private String body ; // タイマータスクのボディー要素 055 private String startTime = "000000"; // 24時間制の開始時刻 056 private String stopTime = "000000"; // 24時間制の終了時刻 057 private int startStop ; // 24時間制の日付またがりをチェック。 058 private boolean aliveFlag = true ; // 活きているかどうか 059 private int errorSleep ; // TimerTask がエラーのときのスリープ時間(s) 3.7.0.4 (2005/03/14) 060 061 /** 062 * デフォルトコンストラクター 063 * オブジェクトは、newInstance でのみ、生成されます。 064 * 065 * @og.rev 5.5.2.6 (2012/05/25) findbugs対応。staticフィールドへの書き込みに、AtomicInteger を利用します。 066 * @og.rev 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor 067 */ 068 public HybsTimerTask() { 069 super(); 070 // 4.3.4.4 (2009/01/01) 071 uniqKey = counter.getAndIncrement() ; // 5.5.2.6 (2012/05/25) findbugs対応 072 } 073 074 /** 075 * このタイマータスクによって実行されるアクションです。 076 * ここでは、エラートラップを入れていますので、サブクラスで 077 * 再定義できないように、final 化しています。 078 * サブクラスでは、stratDaemon() をオーバーライドしてください。 079 * 080 * @see java.util.TimerTask#run() 081 * @see #startDaemon() 082 */ 083 @Override 084 public final void run() { 085 try { 086 if( isExecution() ) { 087 startDaemon(); 088 } 089 } 090 catch( final Throwable th) { 091 // 3.7.0.4 (2005/03/14) 092 if( errorSleep > 0 ) { 093 try { Thread.sleep( errorSleep * 1000L ); } 094 catch( final InterruptedException ex ) { LogWriter.log( ex ); } 095 System.out.println( th.getMessage() ); 096 } 097 else { 098 cancel(); 099 throw new OgRuntimeException( th ); 100 } 101 } 102 } 103 104 /** 105 * このタイマータスクによって実行されるアクションです。 106 * run メソッドより呼ばれます。 107 * サブクラスでは、startDaemon() をオーバーライドしてください。 108 * 109 * @see #run() 110 */ 111 protected abstract void startDaemon() ; 112 113 /** 114 * このタイマータスクによって初期化されるアクションです。 115 * サブクラスでは、initDaemon() をオーバーライドしてください。 116 */ 117 public abstract void initDaemon() ; 118// public void initDaemon() { 119// // ここでは処理を行いません。 120// } 121 122 /** 123 * タイマータスクの名称(ユニークキー)を設定します。 124 * 125 * @param nm タイマータスクの名称 126 */ 127 public void setName( final String nm ) { 128 name = nm; 129 } 130 131 /** 132 * タイマータスクの名称(ユニークキー)を取得します。 133 * 134 * @return タイマータスクの名称 135 */ 136 public String getName() { 137 return name; 138 } 139 140 /** 141 * タイマータスクの説明を設定します。 142 * 143 * @param cmt タイマータスクの説明 144 */ 145 public void setComment( final String cmt ) { 146 comment = cmt; 147 } 148 149 /** 150 * タイマータスクの説明を取得します。 151 * 152 * @return タイマータスクの説明 153 */ 154 public String getComment() { 155 return comment; 156 } 157 158 /** 159 * このオブジェクトの内部ユニークキー値を返します。 160 * オブジェクト生成毎に、+1 されて、内部に持っています。 161 * 162 * @return オブジェクトの内部ユニークキー 163 */ 164 public int getUniqKey() { 165 return uniqKey; 166 } 167 168 /** 169 * このオブジェクトが生成された時刻をミリ秒で返します。 170 * オブジェクト生成時に、System.currentTimeMillis() の値を取得しています。 171 * 172 * @return オブジェクトが生成された時刻(ミリ秒) 173 */ 174 public long getCreateTime() { 175 return createTime; 176 } 177 178 /** 179 * 内部で使用するパラメータを設定します。 180 * 181 * 外部より、引数として渡されてきます。これを利用して、各サブシステムは、 182 * パラメーターを設定したり、初期化したり利用出来ます。 183 * 184 * ※ 6.4.3.1 (2016/02/12) で、内部のMapを ConcurrentHashMap に置き換えたが、引数のMapが 185 * not null制限が入っているかどうか不明なので、取りえず元に戻しておきます。 186 * @og.rev 6.4.3.3 (2016/03/04) 受け取って、Mapに登録するときに、not null制限チェックを入れます。 187 * 188 * @param map パラメータマップ 189 */ 190 public void setParameter( final Map<String,String> map ) { 191 if( map != null ) { 192 // ※ 通常の HashMap から、ConcurrentHashMap への値の設定なので、null チェックが必要です。 193 map.forEach( (k,v) -> { if( k != null && v != null ) { paramMap.put( k,v ); } } ); 194 } 195 } 196 197 /** 198 * 内部で使用するパラメータを返します。 199 * 200 * Mapオブジェクトそのものですので、サブクラス等で書き換えた場合、内容も書き換わってしまいます。 201 * 202 * @og.rev 6.9.0.0 (2018/01/31) 新規追加 203 * 204 * @return 内部で使用するパラメータMap 205 */ 206 protected ConcurrentMap<String,String> getParameter() { 207 return paramMap; 208 } 209 210 /** 211 * 内部で使用するパラメータのキーに対する値を取得します。 212 * 213 * 各サブシステムは、パラメーターを設定したり、初期化したり利用出来ます。 214 * 215 * @param key 引数のキー 216 * 217 * @return キーに対する値 218 */ 219 public String getValue( final String key ) { 220 // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method 221 // 反転注意 222 return key == null ? null : paramMap.get( key ) ; // 6.4.3.3 (2016/03/04) 223 } 224 225 /** 226 * 内部で使用するBody要素の値を設定します。 227 * 228 * 外部より、引数として渡されてきます。これを利用して、各サブシステムは、 229 * パラメーターを設定したり、初期化したり利用出来ます。 230 * 231 * @param body Body要素の値 232 */ 233 public void setBody( final String body ) { 234 this.body = body ; 235 } 236 237 /** 238 * 内部で使用するBody要素の値を取得します。 239 * 240 * 各サブシステムは、パラメーターを設定したり、初期化したり利用出来ます。 241 * 242 * @return Body要素の値 243 */ 244 public String getBody() { 245 return body ; 246 } 247 248 /** 249 * 24時間制(YYMMDD)の開始時刻を設定します。 250 * 251 * 指定時刻範囲内での実行のみ許可するように開始時刻を設定します。 252 * これは、タイマーで指定した間隔ごとにチェックを入れるので、チェック時間が 253 * 長い場合は、正確に開始時刻から始まるというものではありません。 254 * 初期値は、"000000" です。 255 * 256 * @param st 開始時刻 257 */ 258 public void setStartTime( final String st ) { 259 if( st == null || st.length() != 6 ) { 260 final String errMsg = "startTime is inaccurate." + 261 "startTime=[" + st + "]" ; 262 throw new OgRuntimeException( errMsg ); 263 } 264 startTime = st ; 265 initStartStop(); 266 } 267 268 /** 269 * 24時間制(YYMMDD)の終了時刻を設定します。 270 * 271 * 指定時刻範囲内での実行のみ許可するように終了時刻を設定します。 272 * これは、タイマーで指定した間隔ごとにチェックを入れるので、チェック時間が 273 * 長い場合は、正確に終了時刻で終了するというものではありません。 274 * (終了時刻を越えてからの新規実行はありません。) 275 * 初期値は、"000000" です。 276 * 277 * @param st 終了時刻 278 */ 279 public void setStopTime( final String st ) { 280 if( st == null || st.length() != 6 ) { 281 final String errMsg = "stopTime is inaccurate." + 282 "stopTime=[" + st + "]" ; 283 throw new OgRuntimeException( errMsg ); 284 } 285 stopTime = st ; 286 initStartStop(); 287 } 288 289 /** 290 * TimerTask がエラー発生時のスリープ時間(s) 設定します(初期値:0)。 291 * 292 * これは、予期せぬエラー(たとえば、データベースが落ちていたなど)が 293 * 発生したときでも、TimerTask を終了させずに、Sleep させて待機させる 294 * 事により、原因が除去された場合に、自動復帰するようにします。 295 * これに、0 を設定すると、エラー時に即 終了します。 296 * 設定は、秒で指定してください。 297 * 298 * @param erTime スリープ時間(s)(初期値:0) 299 */ 300 public void setErrorSleepSec( final int erTime ) { 301 errorSleep = erTime ; 302 } 303 304 /** 305 * 24時間制の開始/終了時刻の日付またがりを初期設定します。 306 * 307 * 開始時刻、終了時刻は、24時間制でしか指定できません。(日付指定できない) 308 * そのため、朝7:00から夜22:00などの 開始<終了 の時は単純な範囲チェックで 309 * 判断できますが、夜22:00から朝7:00に実行したい場合は、異なるチェックが 310 * 必要になります。 311 * また、開始時刻と終了時刻が未設定の場合や、同じ時刻の場合は、常に実行する必要が 312 * あります。これらのチェックを毎回行うのではなく、開始/終了時刻設定時にチェックして 313 * おきます。 314 * 315 */ 316 private void initStartStop() { 317 if( startTime == null || stopTime == null ) { 318 startStop = 0; 319 } 320 else { 321 startStop = startTime.compareTo( stopTime ); 322 } 323 } 324 325 /** 326 * 実行可能時間内かどうかを判定します。 327 * 328 * 設定された開始時刻と終了時刻に基づいて、現時刻で実行可能かどうか 329 * 判断します。 330 * 331 * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。 332 * 333 * @return (true:実行許可 false:停止) 334 */ 335 private boolean isExecution() { 336 boolean rtnFlag = false; 337 final String time = DateSet.getDate( "HHmmss" ); // 5.5.7.2 (2012/10/09) HybsDateUtil を利用 338 339 if( startStop == 0 ) { 340 rtnFlag = true; 341 } 342 else if( startStop < 0 ) { 343 if( startTime.compareTo( time ) < 0 && 344 time.compareTo( stopTime ) < 0 ) { 345 rtnFlag = true; 346 } 347 } 348 else { // 6.3.9.0 (2015/11/06) 条件は効果がない(findbugs) 349 if( startTime.compareTo( time ) < 0 || 350 time.compareTo( stopTime ) < 0 ) { 351 rtnFlag = true; 352 } 353 } 354 return rtnFlag; 355 } 356 357 /** 358 * このオブジェクトと指定されたオブジェクトの順序を比較します。 359 * このオブジェクトが指定されたオブジェクトより小さい場合は負の整数、 360 * 等しい場合はゼロ、大きい場合は正の整数を返します。 361 * 362 * @param other 比較対象の Object 363 * 364 * @return このオブジェクトが指定されたオブジェクトより小さい場合は負の整数、等しい場合はゼロ、大きい場合は正の整数 365 * @throws ClassCastException 指定されたオブジェクトの型が原因で、この Object と比較できない場合 366 */ 367 @Override // Comparable 368 public int compareTo( final HybsTimerTask other ) { // 4.3.3.6 (2008/11/15) Generics警告対応 369 if( name == null && other.name != null ) { return -1; } 370 if( name != null && other.name == null ) { return 1; } 371 372 if( name != null && other.name != null ) { 373 final int nmComp = name.compareTo( other.name ); 374 if( nmComp != 0 ) { return nmComp; } 375 } 376 377 return uniqKey - other.uniqKey ; 378 } 379 380 /** 381 * このオブジェクトの文字列表現を返します。 382 * 基本的にデバッグ目的に使用します。 383 * 384 * @return このクラスの文字列表現 385 * @og.rtnNotNull 386 */ 387 @Override 388 public String toString() { 389 return name + " [" + uniqKey + "]"; 390 } 391 392 /** 393 * このオブジェクトと他のオブジェクトが等しいかどうかを示します。 394 * 395 * @og.rev 8.4.2.2 (2023/03/17) instanceof を使用した比較方法に統一します。 396 * 397 * @param object 比較対象の参照オブジェクト 398 * 399 * @return 引数に指定されたオブジェクトとこのオブジェクトが等しい場合は true、そうでない場合は false 400 */ 401 @Override 402 public boolean equals( final Object object ) { 403 // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method 404 // 条件反転注意 405// return object != null 406// && getClass().equals( object.getClass() ) 407// && super.equals( object ) 408// && uniqKey == ((HybsTimerTask)object).uniqKey ; 409 410 // 8.4.2.2 (2023/03/17) instanceof を使用した比較方法に統一します。 411// return super.equals( object ) // 6.9.7.0 (2018/05/14) object != null が保障されます。 412// && getClass().equals( object.getClass() ) 413// && uniqKey == ((HybsTimerTask)object).uniqKey ; 414 415 return object instanceof HybsTimerTask 416 && uniqKey == ((HybsTimerTask)object).uniqKey ; 417 } 418 419 /** 420 * オブジェクトが生存しているかどうかを判定します。 421 * 422 * @return 生存しているかどうか。true:生存 / false:キャンセル済み 423 */ 424 public boolean isAlive() { 425 return aliveFlag ; 426 } 427 428 /** 429 * オブジェクトのハッシュコード値を返します。 430 * 431 * @return このオブジェクトのハッシュコード値 432 */ 433 @Override 434 public int hashCode() { 435 return uniqKey ; 436 } 437 438 /** 439 * このタイマータスクのcancel() メソッドをオーバーライドします。 440 * 441 * @return キャンセルが正常に終了できたかどうか 442 * @see java.util.TimerTask#cancel() 443 */ 444 @Override 445 public boolean cancel() { 446 if( aliveFlag ) { 447 System.out.println(); 448 System.out.println( toString() + " " + new Date() + " Stoped" ); 449 aliveFlag = false; // cancelTask を呼ぶ前に必ず『false』にしておく。 450 } 451 return super.cancel(); 452 } 453}