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