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