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         * オブジェクト生成毎に、+1 されて、内部に持っています。
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         * これに、0 を設定すると、エラー時に即 終了します。
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         * 開始時刻、終了時刻は、24時間制でしか指定できません。(日付指定できない)
283         * そのため、朝7:00から夜22:00などの 開始<終了 の時は単純な範囲チェックで
284         * 判断できますが、夜22:00から朝7:00に実行したい場合は、異なるチェックが
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}