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