/*
 * Copyright (c) 2009 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.hayabusa.taglib;

import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.SystemManager;
import org.opengion.hayabusa.db.DBColumn;
import org.opengion.hayabusa.db.DBTableModel;
import org.opengion.hayabusa.db.DBTableModelUtil;
import org.opengion.hayabusa.html.ViewForm;
import org.opengion.hayabusa.html.ViewFormFactory;
import org.opengion.hayabusa.resource.ResourceManager;
import org.opengion.fukurou.util.HybsTimerTask;
import org.opengion.fukurou.util.HybsTimerTaskManager;
import org.opengion.fukurou.util.ToString;						// 6.1.1.0 (2015/01/17)
import org.opengion.fukurou.util.ArraySet;						// 6.4.3.4 (2016/03/11)

import static org.opengion.fukurou.util.StringUtil.nval ;

import java.util.Timer;
import java.util.Set;											// 6.4.3.4 (2016/03/11)
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;

/**
 * アプリケーション共有のタイマー機能を用いて、繰り返しスケジュールを設定するタグです。
 *
 * タイマースケジュールは、帳票デーモンや、再編成処理、定期的バッチ処理など、エンジン上の
 * スレッドで動作するスケジュールを登録します。
 * スケジュールすべきクラスは、HybsTimerTask を拡張(extends)しておく必要があります。
 *
 * @og.formSample
 * ●形式：&lt;og:schedule timerTask="･･･" name="･･･" command="[SET|VIEW|REMOVE|CANCEL]" ･･･ /&gt;
 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
 *
 * ●Tag定義：
 *   &lt;og:schedule
 *       command            【TAG】コマンド (SET,VIEW,REMOVE,CANCEL)をセットします(初期値:SET)
 *       timerTask        ○【TAG】処理を実行するクラス名(HybsTimerTask のサブクラス)を指定します(必須)。
 *       name             ○【TAG】名称(ユニークキー)を設定します(必須)。
 *       comment            【TAG】タイマータスクの説明を設定します
 *       singleton          【TAG】Name属性が同一のタスクを２重登録出来ないよう[true/false]にします(初期値:true[出来ない])
 *       delay              【TAG】ミリ秒単位の遅延時間を設定します(初期値:0)
 *       period             【TAG】ミリ秒単位の繰り返し間隔を設定します(初期値:60000)
 *       fixedDelay         【TAG】固定遅延実行を指定するかどうか[true:固定遅延実行/false:固定頻度実行]を設定します(初期値:true)
 *       keys               【TAG】HybsTimerTask に渡す為のキー情報、CSV形式で複数指定します
 *       vals               【TAG】HybsTimerTask に渡す為の値を、CSV形式で複数指定します
 *       prmKeys            【TAG】HybsTimerTask に渡すパラメータのキー情報を、CSV形式で指定します(分解しない)。
 *       prmVals            【TAG】HybsTimerTask に渡すパラメータの値を、CSV形式で指定します(分解しない)。
 *       startTime          【TAG】24時間制(YYMMDD)の開始時刻を設定します(初期値:000000)
 *       stopTime           【TAG】24時間制(YYMMDD)の終了時刻を設定します(初期値:000000)
 *       scope              【TAG】キャッシュする場合のスコープ(local,request,page,session,application)を指定します(初期値:local)
 *       tableId            【TAG】(通常は使いません)結果をDBTableModelに書き込んで、sessionに登録するときのキーを指定します
 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
 *   &gt;   ... Body ...
 *   &lt;/og:schedule&gt;
 *
 * ●使用例
 *      帳票デーモンスケジュール登録
 *      period は、ｍｓ単位で指定する必要があるため、１０００倍しています。
 *      &lt;og:schedule
 *          command     = &quot;{&#064;CMD}&quot;
 *          scope       = &quot;request&quot;
 *          timerTask   = &quot;org.opengion.hayabusa.report.ReportDaemon&quot;
 *          name        = &quot;{&#064;NAME}&quot;
 *          comment     = &quot;Start-up By {&#064;USER.INFO}&quot;
 *          singleton   = &quot;true&quot;
 *          delay       = &quot;0&quot;
 *          period      = &quot;{&#064;PERIOD}000&quot;
 *          fixedDelay  = &quot;true&quot;
 *          keys        = &quot;SYSTEM_ID,DMN_GRP&quot;
 *          vals        = &quot;{&#064;SYSTEM_ID},{&#064;DMN_GRP}&quot;
 *      /&gt;
 *
 * @og.group その他部品
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class ScheduleTag extends CommonTagSupport {
	/** このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "6.4.3.4 (2016/03/11)" ;
	private static final long serialVersionUID = 643420160311L ;

	/** command 引数に渡す事の出来る コマンド  セット {@value} */
	public static final String CMD_SET   = "SET";
	/** command 引数に渡す事の出来る コマンド  ビュー {@value} */
	public static final String CMD_VIEW   = "VIEW";
	/** command 引数に渡す事の出来る コマンド  リムーブ {@value} */
	public static final String CMD_REMOVE   = "REMOVE";
	/** command 引数に渡す事の出来る コマンド  キャンセル {@value} */
	public static final String CMD_CANCEL   = "CANCEL";

	// 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
	private static final Set<String> COMMAND_SET = new ArraySet<>( CMD_SET , CMD_VIEW , CMD_REMOVE , CMD_CANCEL );

	// 3.5.2.0 (2003/10/20) 結果を DBTableModel として、scope 属性に登録する。
	private String		  tableId	   = HybsSystem.TBL_MDL_KEY;

	private String	command		= CMD_SET;
	private String	timerTask	;			// 処理を実行する HybsTimerTask のクラス名を指定します。
	private String	name		;			// タイマータスクの名称(ユニークキー)
	private String	comment		;			// タイマータスクの説明
	private long	delay		;			// タスクが実行される前のミリ秒単位の遅延(初期値:0)
	private long	period		= 60000l;	// 連続するタスク実行のミリ秒単位の時間(初期値:60000 mS)
	private boolean fixedDelay	= true;		// 固定遅延実行(true)/固定頻度実行(false) (初期値:true)
	private int		uniqKey		= -1;		// ありえない値を初期設定しておく。
	private boolean singleton	= true;		// Name属性が同一のタスクを２重登録出来ないようにする(初期値:true)

	private static final long FIXED_RATE_MIN_TIME = 1000;	// 固定頻度実行時の最小繰り返し時間

	private static final String TIMER_KEY		= HybsSystem.SCEDULE_KEY;
	private static final String TIMERTASK_KEY	= HybsSystem.SCEDULE_TASK_KEY;

	// 6.2.5.1 (2015/06/12) CSV形式のkeys,vals引数(CSV引数)対応。
	private String		keys		;			// タイマータスクへ渡すキー配列
	private String		vals		;			// タイマータスクへ渡すバリュー配列

	private String		body		;			// タイマータスクへ渡すボディー要素
	private String		startTime	= "000000";	// 24時間制の開始時刻
	private String		stopTime	= "000000";	// 24時間制の終了時刻

	// 3.5.2.0 (2003/10/20) 結果を DBTableModel として、scope 属性に登録する。
	private String		scope		= "local";	// local は互換性のため。"request","page","session","application"

	// 3.7.0.4 (2005/03/14) 帳票デーモンに、エラー時にスリープして待機する機能を追加
	private final int ERROR_SLEEP_TIME = HybsSystem.sysInt( "REPORT_DAEMON_ERROR_SLEEP_TIME" );

	// 4.0.0 (2006/11/17) HybsTimerTaskManager を static クラスから通常オブジェクトとして管理。
	private static final HybsTimerTaskManager TASK_MANAGER ;			// 6.4.1.1 (2016/01/16) taskManager  → TASK_MANAGER  refactoring

	// 4.0.0 (2005/01/31) Cleanable インターフェースによる初期化処理
	// 4.3.6.2 (2009/04/15) コンテキスト終了時のみclear()されるように対応
	static {
		TASK_MANAGER = new HybsTimerTaskManager();
		// 4.3.6.2 (2009/04/15)
		SystemManager.addCleanable( TASK_MANAGER, true );	// コンテキスト終了時のみ呼び出す
	}

	/**
	 * デフォルトコンストラクター
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
	 */
	public ScheduleTag() { super(); }		// これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。

	/**
	 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
	 *
	 * @og.rev 3.2.2.0 (2003/05/31) HybsTimerTask に対して、設定値を渡せるように変更。
	 *
	 * @return	後続処理の指示( EVAL_BODY_BUFFERED )
	 */
	@Override
	public int doStartTag() {
		return EVAL_BODY_BUFFERED ;	// Body を評価する。( extends BodyTagSupport 時)
	}

	/**
	 * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
	 *
	 * @og.rev 3.2.2.0 (2003/05/31) HybsTimerTask に対して、設定値を渡せるように変更。
	 *
	 * @return	後続処理の指示(SKIP_BODY)
	 */
	@Override
	public int doAfterBody() {
		body = getBodyString();

		return SKIP_BODY ;
	}

	/**
	 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
	 *
	 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
	 * @og.rev 3.6.0.8 (2004/11/19) DBTableModel をセーブする時に、トランザクションチェックを行います。
	 * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doEndTag() {
		debugPrint();		// 4.0.0 (2005/02/28)
		if( !check( command, COMMAND_SET ) ) { return EVAL_PAGE ; }

		if( "session".equals( scope ) ) {
			startQueryTransaction( tableId );		// 3.6.0.8 (2004/11/19)
		}

		// 3.6.0.8 (2004/11/19) トランザクションチェックを行います。
		if( commandExec( command ) ) {
			return EVAL_PAGE ;		// ページの残りを評価する。
		}
		else {
			jspPrint( "ScheduleTag Query処理が割り込まれました。DBTableModel は登録しません。" );
			return SKIP_PAGE;
		}
	}

	/**
	 * タグリブオブジェクトをリリースします。
	 * キャッシュされて再利用されるので、フィールドの初期設定を行います。
	 *
	 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
	 * @og.rev 3.2.2.0 (2003/05/31) HybsTimerTask に対して、設定値を渡せるように変更。
	 * @og.rev 3.5.2.0 (2003/10/20) 結果を DBTableModel として、scope 属性に登録する。
	 */
	@Override
	protected void release2() {
		super.release2();
		command		= CMD_SET;
		timerTask	= null;		// 処理を実行する HybsTimerTask のクラス名を指定します。
		name		= null;		// タイマータスクの名称(ユニークキー)
		comment		= null;		// タイマータスクの説明
		delay		= 0;		// タスクが実行される前のミリ秒単位の遅延(初期値:0)
		period		= 60000;	// 連続するタスク実行のミリ秒単位の時間(初期値:60000 mS)
		fixedDelay	= true;		// 固定遅延実行(true)/固定頻度実行(false) (初期値:true)
		uniqKey		= -1;		// ありえない値を初期設定しておく。
		singleton	= true;		// Name属性が同一のタスクを２重登録出来ないようにする(初期値:true)
		keys		= null;		// タイマータスクへ渡すキー配列
		vals		= null;		// タイマータスクへ渡すバリュー配列
		startTime	= "000000";	// 24時間制の開始時刻
		stopTime	= "000000";	// 24時間制の終了時刻
		tableId		= HybsSystem.TBL_MDL_KEY;		//
		scope		= "local";	// local は互換性のため。"request","page","session","application"
	}

	/**
	 * コマンドを実行します。
	 *
	 * コマンドは,HTMLから(SET/VIEW/REMOVE/CANCEL)指定されますので,setCommand()メソッドで
	 * 登録します。
	 * コマンドを登録すると同時に,実行も行ないます。
	 *
	 * @og.rev 3.5.2.0 (2003/10/20) viewAttribute()メソッドを、全てで実行します。
	 * @og.rev 3.6.0.8 (2004/11/19) 正常に登録できたかどうかを、返します。
	 * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( setMsg() ⇒ setLbl )
	 *
	 * @param   command コマンド (public static final 宣言されている文字列)
	 * @see		<a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.ScheduleTag.CMD_SET">コマンド定数</a>
	 *
	 * @return 正常かどうか(true:正常/false:異常)
	 */
	protected boolean commandExec( final String command ) {
		if( CMD_SET.equals( command ) ) {
			setAttribute();
			setLbl( "MSG0059" );	// 登録しました。
			jspPrint( getMsglbl() );
		}
		else if( CMD_VIEW.equals( command ) ) {
			jspPrint( String.valueOf( TASK_MANAGER.size() ) );
			setLbl( "MSG0033" );	// 　件検索しました。
			jspPrint( getMsglbl() );
		}
		else if( CMD_REMOVE.equals( command ) ) {
			removeAttribute();
			setLbl( "MSG0061" );	// 削除しました。
			jspPrint( getMsglbl() );
		}
		else if( CMD_CANCEL.equals( command ) ) {
			cancelAttribute();
			setLbl( "MSG0063" );	// 完了しました。
			jspPrint( getMsglbl() );
		}
		return viewAttribute();
	}

	/**
	 * HybsTimerTask を登録します。
	 *
	 * @og.rev 3.2.2.0 (2003/05/31) HybsTimerTask に対して、設定値を渡せるように変更。
	 * @og.rev 3.6.0.7 (2004/11/06) パラメータをMapで渡すように変更。
	 * @og.rev 3.7.0.4 (2005/03/14) HybsTimerTask に setErrorSleepSec メソッドの追加
	 * @og.rev 6.2.5.1 (2015/06/12) CSV形式のkeys,vals引数(CSV引数)対応。
	 */
	@SuppressWarnings(value={"unchecked"})
	private void setAttribute() {
		// シングルトンで、かつ、すでに、同一名称のタスクが
		// 含まれている場合は、セットしない。
		if( singleton && TASK_MANAGER.contains( name ) ) { return ; }

		// 6.2.5.1 (2015/06/12) CSV形式のkeys,vals引数(CSV引数)対応。
		final Map<String,String> param = getCSVParameter( keys,vals );

		final HybsTimerTask task = HybsSystem.newInstance( timerTask );
		TASK_MANAGER.addTask( task );

		task.setName( name );
		task.setComment( comment );
		task.setParameter( param );		// 3.6.0.7 (2004/11/06)
		task.setBody( body );
		task.setStartTime( startTime );
		task.setStopTime( stopTime );
		task.setErrorSleepSec( ERROR_SLEEP_TIME );	// 3.7.0.4 (2005/03/14)
		task.initDaemon();

		// 3.6.1.0 (2005/01/05) Timer 同一スレッドのため、個別に作成する。
		Map<String,Timer> timerMap = (Map<String,Timer>)getContextAttribute( TIMER_KEY );
		if( timerMap == null ) { timerMap = new HashMap<>(); }

		Timer timer = timerMap.get( name );
		if( timer == null ) { timer = new Timer( true ); }

		if( fixedDelay ) {
			if( period > 0 ) { timer.schedule( task,delay,period ); }
			else             { timer.schedule( task,delay ); }
		}
		else {
			if( period < FIXED_RATE_MIN_TIME ) { period = FIXED_RATE_MIN_TIME; }
			timer.scheduleAtFixedRate( task,delay,period );
		}

		// 3.6.1.0 (2005/01/05) Timer 同一スレッドのため、個別に作成する。
		timerMap.put( name,timer );
		setContextAttribute( TIMER_KEY,timerMap );
	}

	/**
	 * HybsTimerTask を一覧表示します。
	 *
	 * @og.rev 3.5.2.0 (2003/10/20) 結果を DBTableModel として、scope 属性に登録する。
	 * @og.rev 3.5.6.1 (2004/06/25) lang 言語コード 属性を削除します。
	 * @og.rev 3.6.0.8 (2004/11/19) DBTableModel をセーブする時に、トランザクションチェックを行います。
	 * @og.rev 3.6.0.8 (2004/11/19) 正常に登録できたかどうかを、返します。
	 *
	 * @return 正常かどうか(true:正常/false:異常)
	 */
	private boolean viewAttribute() {
		final HybsTimerTask[] tasks = TASK_MANAGER.toArray();
		final DBTableModel table = makeDBTable( tasks );

		if( "local".equals( scope ) ) {
			if( table != null ) {
				final ViewForm form = ViewFormFactory.newInstance( "HTMLTable" );
				form.clear();
				form.init( table );
				jspPrint( form.create() );
			}
		}
		else {
			super.setScope( scope );		// 3.6.0.9 (2004/12/03)
			// 3.6.0.8 (2004/11/19) トランザクションチェックを行います。
			return commitTableObject( tableId, table );
		}
		return true;
	}

	/**
	 * HybsTimerTask を削除します。
	 *
	 * @og.rev 3.2.2.0 (2003/05/31) キャンセルを名前でもできる様にロジック追加。
	 *
	 */
	private void removeAttribute() {
		if( uniqKey >= 0 ) {
			TASK_MANAGER.cancelTask( uniqKey );
		}
		else {
			TASK_MANAGER.cancelTask( name );
		}
	}

	/**
	 * Timer そのものをキャンセルします。
	 *
	 * すべての、HybsTimerTask は、削除されます。
	 *
	 * @og.rev 3.6.1.0 (2005/01/05) Timer 同一スレッドのため、個別に作成する。
	 */
	@SuppressWarnings(value={"unchecked"})
	private void cancelAttribute() {
		TASK_MANAGER.clear();

		// 3.6.1.0 (2005/01/05)
		final Map<String,Timer> timerMap = (Map<String,Timer>)getContextAttribute( TIMER_KEY );
		if( timerMap != null ) {
			final Iterator<Timer> iterator = timerMap.values().iterator();	// 4.3.3.6 (2008/11/15) Generics警告対応
			while( iterator.hasNext() ) {
				(iterator.next()).cancel();	// 4.3.3.6 (2008/11/15) Generics警告対応
			}
			timerMap.clear();
		}
		removeContextAttribute( TIMER_KEY );
	}

	/**
	 * 【TAG】コマンド (SET,VIEW,REMOVE,CANCEL)をセットします(初期値:SET)。
	 *
	 * @og.tag
	 * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される
	 * フィールド定数値のいづれかを、指定できます。
	 * 何も設定されない、または、null の場合は、"SET" が初期値にセットされます。
	 *
	 * @param	cmd コマンド (public static final 宣言されている文字列)
	 * @see		<a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.ScheduleTag.CMD_SET">コマンド定数</a>
	 */
	public void setCommand( final String cmd ) {
		command = nval( getRequestParameter( cmd ),command );
	}

	/**
	 * 【TAG】処理を実行するクラス名(HybsTimerTask のサブクラス)を指定します。
	 *
	 * @og.tag 処理を実行する HybsTimerTask のクラス名を指定します。
	 *
	 * @param   val クラス名
	 */
	public void setTimerTask( final String val ) {
		timerTask = getRequestParameter( val );
	}

	/**
	 * 【TAG】名称(ユニークキー)を設定します。
	 *
	 * @og.tag タイマータスクの名称(ユニークキー)を設定します。
	 *
	 * @param   nm タイマータスクの名称
	 */
	public void setName( final String nm ) {
		name = getRequestParameter( nm );
	}

	/**
	 * 【TAG】タイマータスクの説明を設定します。
	 *
	 * @og.tag タイマータスクの説明を設定します。
	 *
	 * @param   cmt タイマータスクの説明
	 */
	public void setComment( final String cmt ) {
		comment = getRequestParameter( cmt );
	}

	/**
	 * 【TAG】ミリ秒単位の遅延時間を設定します(初期値:0)。
	 *
	 * @og.tag タスクが実行される前のミリ秒単位の遅延を設定します(初期値:0)
	 *
	 * @param   val 遅延時間(ms)
	 */
	public void setDelay( final String val ) {
		delay = nval( getRequestParameter( val ),delay );
	}

	/**
	 * 【TAG】ミリ秒単位の繰り返し間隔を設定します(初期値:60000)。
	 *
	 * @og.tag 連続するタスク実行のミリ秒単位の時間を設定します(初期値:60000 mS)
	 *
	 * @param   val 繰り返し間隔(ms)
	 */
	public void setPeriod( final String val ) {
		period = nval( getRequestParameter( val ),period );
	}

	/**
	 * 【TAG】固定遅延実行を指定するかどうか[true:固定遅延実行/false:固定頻度実行]を設定します(初期値:true)。
	 *
	 * @og.tag
	 * 固定遅延実行では、前の実行の実際の実行時間を基準にしてそれぞれの実行がスケジュールされます。
	 * 何らかの理由で実行が遅延した場合 そのあとの実行も遅延されます。
	 * 最終的に、実行の頻度は通常、指定した期間の対応する頻度よりも若干遅くなります
	 *
	 * 固定頻度実行では、最初の実行のスケジュールされた実行時間を基準にしてそれぞれの実行が
	 * スケジュールされます。何らかの理由で実行が遅延した場合、「遅れを取り戻す」ために
	 * 2 つ以上の実行が連続して行われます。最終的に実行の頻度は、指定した期間の対応する頻度と
	 * 同じになります
	 * 初期値は、true:固定遅延実行 です。
	 *
	 * @param   flag 遅延方式指定 [true:固定遅延実行/false:固定頻度実行]
	 */
	public void setFixedDelay( final String flag ) {
		fixedDelay = nval( getRequestParameter( flag ),fixedDelay );
	}

	/**
	 * 【TAG】スケジュールを一意に決めるためのユニーク番号を指定します(初期値:-1)。
	 *
	 * @og.tag
	 * スケジュールを削除したりする場合に、必要なユニーク番号を指定します。
	 * 初期値は、-1:あり得ない値 です。
	 *
	 * @param   no ユニーク番号
	 */
	public void setUniqKey( final String no ) {
		uniqKey = nval( getRequestParameter( no ),uniqKey );
	}

	/**
	 * 【TAG】Name属性が同一のタスクを２重登録出来ないよう[true:禁止/false:なにもない]にします(初期値:true:禁止)。
	 *
	 * @og.tag
	 * 同一種類のタスクを複数同時立上げしたくない場合に、利用します。
	 * 一般に、タイマータスクそのものが、繰り返し実行されますので、
	 * 初期値は、２重登録禁止にしています。
	 *
	 * @param   flag ２重登録不可 [true:禁止/false:なにもない]
	 */
	public void setSingleton( final String flag ) {
		singleton = nval( getRequestParameter( flag ),singleton );
	}

	/**
	 * 【TAG】HybsTimerTask に渡す為のキー情報、CSV形式で複数指定します。
	 *
	 * @og.tag
	 * HybsTimerTask に渡す為の、キー情報をCSV形式で複数指定できます。
	 * vals 属性には、キーに対応する値を、設定してください。
	 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
	 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
	 *
	 * @og.rev 3.2.2.0 (2003/05/31) 新規追加
	 * @og.rev 3.5.6.2 (2004/07/05) CommonTagSupport#getCSVParameter を使用
	 * @og.rev 6.2.5.1 (2015/06/12) CSV形式のkeys,vals引数(CSV引数)対応。
	 *
	 * @param	key キー情報(CSV形式)
	 */
	public void setKeys( final String key ) {
		keys = key;
	}

	/**
	 * 【TAG】HybsTimerTask に渡す為の値を、CSV形式で複数指定します。
	 *
	 * @og.tag
	 * キーに設定した値を、CSV形式で複数して出来ます。
	 * 指定順序は、キーと同じにしておいて下さい。
	 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
	 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
	 *
	 * @og.rev 3.2.2.0 (2003/05/31) 新規追加
	 * @og.rev 3.5.6.2 (2004/07/05) CommonTagSupport#getCSVParameter を使用
	 * @og.rev 6.2.5.1 (2015/06/12) CSV形式のkeys,vals引数(CSV引数)対応。
	 *
	 * @param	val 値(CSV形式)
	 */
	public void setVals( final String val ) {
		vals = val;
	}

	/**
	 * 【TAG】24時間制(YYMMDD)の開始時刻を設定します(初期値:000000)。
	 *
	 * @og.tag
	 * 指定時刻範囲内での実行のみ許可するように開始時刻を設定します。
	 * これは、タイマーで指定した間隔ごとにチェックを入れるので、チェック時間が
	 * 長い場合は、正確に開始時刻から始まるというものではありません。
	 * 初期値は、"000000" です。
	 *
	 * @og.rev 3.2.2.0 (2003/05/31) 新規追加
	 *
	 * @param	st 開始時刻
	 */
	public void setStartTime( final String st ) {
		startTime = nval( getRequestParameter( st ),startTime ) ;
	}

	/**
	 * 【TAG】24時間制(YYMMDD)の終了時刻を設定します(初期値:000000)。
	 *
	 * @og.tag
	 * 指定時刻範囲内での実行のみ許可するように終了時刻を設定します。
	 * これは、タイマーで指定した間隔ごとにチェックを入れるので、チェック時間が
	 * 長い場合は、正確に終了時刻で終了するというものではありません。
	 * (終了時刻を越えてからの新規実行はありません。)
	 * 初期値は、"000000" です。
	 *
	 * @og.rev 3.2.2.0 (2003/05/31) 新規追加
	 *
	 * @param	st 終了時刻
	 */
	public void setStopTime( final String st ) {
		stopTime = nval( getRequestParameter( st ),stopTime ) ;
	}

	/**
	 * HybsTimerTask オブジェクト配列より、DBTableModel を作成して返します。
	 * カラム名は、"TaskName","UniqKey","Comment","CreateTime","scheduledTime" です。
	 *
	 * @param   tasks	タイマータスクオブジェクト配列(可変長引数)
	 *
	 * @return	タイマータスクオブジェクトのテーブルモデル。 無ければ null
	 */
	private DBTableModel makeDBTable( final HybsTimerTask... tasks ) {
		if( tasks == null || tasks.length == 0 ) { return null; }		// 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。

		final ResourceManager  resource  = getResource();

		final String[] names = new String[] {
							"TaskName","UniqKey","Comment","CreateTime","scheduledTime"
						};

		final DBTableModel table = DBTableModelUtil.newDBTable();
		table.init( names.length );
		for( int i=0; i<names.length; i++ ) {
			final DBColumn dbColumn = resource.makeDBColumn( names[i] );
			table.setDBColumn( i,dbColumn );
		}

		for( int i=0; i<tasks.length; i++ ) {
			String[] clmVals = new String[names.length];
			clmVals[0] = tasks[i].getName() ;
			clmVals[1] = String.valueOf( tasks[i].getUniqKey() );
			clmVals[2] = tasks[i].getComment() ;
			clmVals[3] = HybsSystem.getDate( tasks[i].getCreateTime() );
			clmVals[4] = HybsSystem.getDate( tasks[i].scheduledExecutionTime() );
			table.addColumnValues( clmVals );
		}

		return table ;
	}

	/**
	 * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
	 *		(初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
	 *
	 * @og.tag
	 * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に
	 * 渡す場合に、通常は、session を利用します。その場合の登録キーです。
	 * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、
	 * この tableId 属性を利用して、メモリ空間を分けます。
	 *		(初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
	 *
	 * @param	id テーブルID (sessionに登録する時のID)
	 */
	public void setTableId( final String id ) {
		tableId = nval( getRequestParameter( id ),tableId );
	}

	/**
	 * 【TAG】キャッシュする場合のスコープ(local,request,page,session,application)を指定します(初期値:local)。
	 *
	 * @og.tag
	 * "local","request","page","session","application" が指定できます。
	 * "local" は、過去のバージョンとの互換性を保つ為の特殊な値です。
	 * 初期値は、"local" です。
	 *
	 * @og.rev 3.5.2.0 (2003/10/20) 新規作成
	 *
	 * @param	scp	スコープ
	 */
	@Override
	public void setScope( final String scp ) {
		scope = nval( getRequestParameter( scp ),scope );
	}

	/**
	 * このオブジェクトの文字列表現を返します。
	 * 基本的にデバッグ目的に使用します。
	 *
	 * @return このクラスの文字列表現
	 * @og.rtnNotNull
	 */
	@Override
	public String toString() {
		return ToString.title( this.getClass().getName() )
				.println( "VERSION"				,VERSION		)
				.println( "tableId"				,tableId		)
				.println( "command"				,command		)
				.println( "timerTask"			,timerTask		)
				.println( "name"				,name			)
				.println( "comment"				,comment		)
				.println( "delay"				,delay			)
				.println( "period"				,period			)
				.println( "fixedDelay"			,fixedDelay		)
				.println( "uniqKey"				,uniqKey		)
				.println( "singleton"			,singleton		)
				.println( "FIXED_RATE_MIN_TIME"	,FIXED_RATE_MIN_TIME)
				.println( "TIMER_KEY"			,TIMER_KEY		)
				.println( "TIMERTASK_KEY"		,TIMERTASK_KEY	)
				.println( "keys"				,keys			)
				.println( "vals"				,vals			)
				.println( "body"				,body			)
				.println( "startTime"			,startTime		)
				.println( "stopTime"			,stopTime		)
				.println( "scope"				,scope			)
				.println( "ERROR_SLEEP_TIME"	,ERROR_SLEEP_TIME)
				.println( "Other..."	,getAttributes().getAttribute() )
				.fixForm().toString() ;
	}
}
