/*
 * 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.fukurou.system.DateSet;							// 6.4.2.0 (2016/01/29)
// import org.opengion.fukurou.util.HybsDateUtil;
import static org.opengion.fukurou.util.StringUtil.nval;

// import java.io.IOException;
// import java.io.ObjectInputStream;
// import java.io.ObjectOutputStream;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.ArrayList;
import java.util.Set;
import java.util.Map;
import java.util.TreeMap;							// 6.2.4.2 (2015/05/29)
import java.text.NumberFormat;						// 6.2.4.2 (2015/05/29)

import javax.servlet.jsp.PageContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.db.DBColumn;
import org.opengion.hayabusa.db.DBTableModel;
import org.opengion.hayabusa.db.Query;
import org.opengion.hayabusa.db.QueryFactory;
import org.opengion.fukurou.util.HybsDateUtil;						// 6.4.2.0 (2016/01/29)
import org.opengion.fukurou.util.StringUtil;
import org.opengion.fukurou.db.Transaction;
// import org.opengion.fukurou.db.TransactionReal;

/**
 * JSP上からキー、値を設定することにより、パラメータとして、値を
 * 取出し可能にするタグです。
 *
 * 通常のリクエスト情報と同じ扱いができます(優先順位は、Valueタグが上位)。
 *
 * 設定した値は、{&#064;XXXX} 形式で 取り出すことができます。
 * また、command ="GET" で 直接画面に値を書き出すことも可能です。
 *
 * ※ このタグは、Transaction タグの対象です。
 *
 * <style type="text/css" >
 *   #valueJavaDoc th { vertical-align:top; margin:0px; padding:0px; }
 *   #valueJavaDoc td { text-align:center;  margin:0px; padding:0px; }
 *  .act {
 *      background-color: #ccffcc;
 *      height : 160px;
 *  }
 *  .cmd {
 *      background-color: #ffcccc;
 *      width  : 80px;
 *  }
 *  .arrow {
 *     border-top:  160px solid #ccffcc;
 *     border-left:  80px solid #ffcccc;
 *     position: absolute;
 *  }
 *  .actarw { margin-left:20px; position: absolute; }
 *  .cmdarw { margin-top:140px; position: absolute; }
 * </style>
 *
 * @og.formSample
 * ●形式：&lt;og:value command="SET" key="ABC" value="123" /&gt;
 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
 *
 * ●Tag定義：
 *   &lt;og:value
 *       command            【TAG】コマンド (SET,GET,REMOVE,CLEAR,SQL,SETTBL,GETTBL,KEYTBL,SETMEM,SQLGET)をセットします(初期値:SET)
 *       action             【TAG】アクション(UPPER,LOWER,MESSAGE,APPEND,ALL_APPEND,MAP,ALL_MAP,MAPOBJ,ALL_MAPOBJ,LIST,ALL_LIST,DAY_WEEK,
 *                                  MERGE,FIRST,ROW_APPEND,REPLACE,SUBSTR,SPLIT,MAX_MIN,ALL_MAX_MIN,EXEC,CASE,ESCAPE,TRIM)をセットします
 *       key                【TAG】パラメータ に登録するキーをセットします
 *       value              【TAG】パラメータ に登録する値をセットします
 *       defaultVal         【TAG】value値がNULLの場合に、この初期値を設定します
 *       nullSet            【廃止】value が NULL の時に、設定するかどうか[true/false]を指定します(初期値:true)
 *       separator          【TAG】各種アクションの文字列を連結/分解する項目区切り文字をセットします(初期値:",")
 *       useMultiRows       【TAG】マルチデータ(複数件検索)を使用するかどうか[true/false]を指定します(初期値:false)
 *       scope              【TAG】キャッシュする場合のスコープ(request,session)を指定します(初期値:request)
 *       tableId            【TAG】sessionから取得する DBTableModelオブジェクトの ID
 *       tblScope           【TAG】DBTableModel から取得する場合のスコープ(request,session)を指定します(初期値:session)
 *       dbid               【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します
 *       xssCheck           【TAG】パラメータの HTMLTag開始/終了文字(&gt;&lt;) 存在チェックを実施するかどうか[true/false]を設定します (初期値:USE_XSS_CHECK[=true])
 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
 *       toVal              【TAG】部分文字列置換の 置換え後の部分文字列(to)を指定します
 *       fromVal            【TAG】部分文字列置換の 置換え前の部分文字列(from)を指定します
 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
 *   &gt;   ... Body ...
 *   &lt;/og:value&gt;
 *
 * ●使用例
 *     ・ &lt;og:value command="SET" key="ABC" value="123" /&gt;
 *     ・ &lt;og:value command="SQL"&gt;SELECT 1 TEST FROM DUAL&lt;/og:value&gt;
 *     ・ &lt;og:value command="SET" key="DEF" value="{&#064;NOCOMMAND}" defaultVal="0000" /&gt;
 *     ・ &lt;og:value command="GET" key="NOKEY" defaultVal="NODATA" /&gt;
 *     ・ &lt;og:value command="SET" key="{&#064;ABC}4" value="TEST1234" /&gt;
 *     ・ &lt;og:value command="GET" key="ABC" /&gt;
 *     ・ &lt;og:value command="SET" action="LOWER" key="LOWERTEST" value="ABCDEF" /&gt;
 *     ・ &lt;og:value command="GET" key="LOWERTEST" /&gt;
 *     ・ &lt;og:value command="GET" action="UPPER" key="LOWERTEST" /&gt;
 *     ・ &lt;og:value command="REMOVE" key="ABC" /&gt;
 *
 * <table border="1px" frame="box" rules="all" width="100%" id="valueJavaDoc">
 *   <caption>command 一覧と使用可能 action の対応表</caption>
 *   <tr>
 *       <th><span class="arrow"></span><span class="actarw">action</span><span class="cmdarw">command</span></th>
 *       <th class="act">UPPER<br />LOWER<br />MESSAGE<br />DAY_WEEK<br />MERGE<br />REPLACE<br />SUBSTR<br />EXEC<br />CASE<br />ESCAPE</th>
 *       <th class="act">APPEND<br />ALL_APPEND</th>
 *       <th class="act">MAP<br />ALL_MAP<br />MAPOBJ<br />ALL_MAPOBJ<br />LIST<br />ALL_LIST</th>
 *       <th class="act">FIRST</th>
 *       <th class="act">ROW_APPEND</th>
 *       <th class="act">SPLIT<br />MAX_MIN<br />ALL_MAX_MIN</th>
 *   </tr>
 *   <tr><td class="cmd">SET    </td><td>○</td><td>○</td><td>×</td><td>×</td><td>×</td><td>○</td></tr>
 *   <tr><td class="cmd">GET    </td><td>○</td><td>×</td><td>×</td><td>×</td><td>×</td><td>×</td></tr>
 *   <tr><td class="cmd">REMOVE </td><td>×</td><td>×</td><td>×</td><td>×</td><td>×</td><td>×</td></tr>
 *   <tr><td class="cmd">CLEAR  </td><td>×</td><td>×</td><td>×</td><td>×</td><td>×</td><td>×</td></tr>
 *   <tr><td class="cmd">SQL    </td><td>×</td><td>×</td><td>○</td><td>×</td><td>○</td><td>×</td></tr>
 *   <tr><td class="cmd">SETTBL </td><td>○</td><td>○</td><td>○</td><td>○</td><td>×</td><td>○</td></tr>
 *   <tr><td class="cmd">GETTBL </td><td>○</td><td>○</td><td>×</td><td>○</td><td>×</td><td>×</td></tr>
 *   <tr><td class="cmd">KEYTBL </td><td>○</td><td>○</td><td>×</td><td>○</td><td>×</td><td>○</td></tr>
 *   <tr><td class="cmd">SETMEM </td><td>○</td><td>○</td><td>×</td><td>×</td><td>×</td><td>○</td></tr>
 *   <tr><td class="cmd">SQLGET </td><td>×</td><td>×</td><td>×</td><td>×</td><td>○</td><td>×</td></tr>
 * </table>
 *
 * @og.group その他部品
 *
 * @version  4.0
 * @author   M.Endou
 * @since    JDK5.0,
 */
public class ValueTag extends CommonTagSupport {
	/** このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "6.4.2.0 (2016/01/29)" ;
	private static final long serialVersionUID = 642020160129L ;

	/** command 引数に渡す事の出来る コマンド  セット {@value} */
	public static final String CMD_SET		= "SET";
	/** command 引数に渡す事の出来る コマンド  ゲット {@value} */
	public static final String CMD_GET		= "GET";
	/** command 引数に渡す事の出来る コマンド  リムーブ {@value} */
	public static final String CMD_REMOVE	= "REMOVE";
	/** command 引数に渡す事の出来る コマンド  クリア {@value} */
	public static final String CMD_CLEAR	= "CLEAR";
	/** command 引数に渡す事の出来る コマンド  ＳＱＬ {@value} */
	public static final String CMD_SQL		= "SQL";
	/** command 引数に渡す事の出来る コマンド  セットテーブル {@value} */
	public static final String CMD_SETTBL	= "SETTBL";
	/** command 引数に渡す事の出来る コマンド  ゲットテーブル {@value} */
	public static final String CMD_GETTBL	= "GETTBL";
	/** command 引数に渡す事の出来る コマンド  キーテーブル {@value} */
	public static final String CMD_KEYTBL	= "KEYTBL";
	/** command 引数に渡す事の出来る コマンド  セットメモリ {@value} */
	public static final String CMD_SETMEM	= "SETMEM";			// 3.7.1.0 (2005/04/15)
	/** command 引数に渡す事の出来る コマンド  ＳＱＬゲット {@value} */
	public static final String CMD_SQLGET	= "SQLGET";			// 5.1.7.0 (2010/06/01) SQLGET対応

	/** command 引数に渡す事の出来る コマンド リスト  */
	private static final String[] COMMAND_LIST = { CMD_SET , CMD_GET , CMD_REMOVE , CMD_SQL , CMD_SETTBL , CMD_GETTBL ,
													CMD_KEYTBL , CMD_CLEAR , CMD_SETMEM, CMD_SQLGET };

	/** action 引数に渡す事の出来る アクション  アッパー(大文字化) {@value} */
	public static final String ACT_UPPER		= "UPPER" ;
	/** action 引数に渡す事の出来る アクション  ローワー(小文字化) {@value} */
	public static final String ACT_LOWER		= "LOWER" ;
	/** action 引数に渡す事の出来る アクション  メッセージ変換 {@value} */
	public static final String ACT_MESSAGE		= "MESSAGE" ;
	/** action 引数に渡す事の出来る アクション  データアペンド {@value} */
	public static final String ACT_APPEND		= "APPEND" ;
	/** action 引数に渡す事の出来る アクション  オールアペンド {@value} */
	public static final String ACT_ALL_APPEND	= "ALL_APPEND" ;				// 3.6.1.0 (2005/01/05)
	/** action 引数に渡す事の出来る アクション  MAP {@value} */
	public static final String ACT_MAP			= "MAP" ;						// 5.5.0.3 (2012/03/12)
	/** action 引数に渡す事の出来る アクション  ALL_MAP {@value} */
	public static final String ACT_ALL_MAP		= "ALL_MAP" ;					// 5.5.0.3 (2012/03/12)
	/** action 引数に渡す事の出来る アクション  MAP {@value} */
	public static final String ACT_MAPOBJ		= "MAPOBJ" ;					// 6.2.4.2 (2015/05/29)
	/** action 引数に渡す事の出来る アクション  ALL_MAP {@value} */
	public static final String ACT_ALL_MAPOBJ	= "ALL_MAPOBJ" ;				// 6.2.4.2 (2015/05/29)
	/** action 引数に渡す事の出来る アクション  LIST {@value} */
	public static final String ACT_LIST			= "LIST" ;						// 4.3.7.5 (2009/07/13)
	/** action 引数に渡す事の出来る アクション  ALL_LIST {@value} */
	public static final String ACT_ALL_LIST		= "ALL_LIST" ;					// 4.3.7.5 (2009/07/13)
	/** action 引数に渡す事の出来る アクション  日付前方まるめ {@value} */
	public static final String ACT_DAY_WEEK		= "DAY_WEEK" ;					// 3.7.1.0 (2005/04/15)
	/** action 引数に渡す事の出来る アクション  マージ {@value} */
	public static final String ACT_MERGE		= "MERGE" ;						// 3.7.1.1 (2005/05/23)
	/** action 引数に渡す事の出来る アクション  ファースト {@value} */
	public static final String ACT_FIRST		= "FIRST" ;						// 3.8.0.4 (2005/08/08)
	/** action 引数に渡す事の出来る アクション  縦横回転 {@value} */
	public static final String ACT_ROW_APPEND	= "ROW_APPEND" ;				// 3.8.9.2 (2007/07/28)
	/** action 引数に渡す事の出来る アクション  文字列置換 {@value} */
	public static final String ACT_REPLACE		= "REPLACE" ;					// 5.2.2.0 (2010/11/01)
	/** action 引数に渡す事の出来る アクション  部分文字列 {@value} */
	public static final String ACT_SUBSTR		= "SUBSTR" ;					// 5.2.2.0 (2010/11/01)
	/** action 引数に渡す事の出来る アクション  文字列分割 {@value} */
	public static final String ACT_SPLIT		= "SPLIT" ;						// 5.2.2.0 (2010/11/01)
	/** action 引数に渡す事の出来る アクション  最大_最小値 {@value} */
	public static final String ACT_MAX_MIN		= "MAX_MIN" ;					// 5.6.4.3 (2013/05/24)
	/** action 引数に渡す事の出来る アクション  ALL_最大_最小値 {@value} */
	public static final String ACT_ALL_MAX_MIN	= "ALL_MAX_MIN" ;				// 5.6.4.3 (2013/05/24)
	/** action 引数に渡す事の出来る アクション  計算処理結果 {@value} */
	public static final String ACT_EXEC			= "EXEC" ;						// 5.7.7.2 (2014/06/20)
	/** action 引数に渡す事の出来る アクション  条件分岐 {@value} */
	public static final String ACT_CASE			= "CASE" ;						// 5.7.7.2 (2014/06/20)
	/** action 引数に渡す事の出来る アクション  HTML上のエスケープ文字 {@value} */
	public static final String ACT_ESCAPE		= "ESCAPE" ;					// 6.3.5.0 (2015/08/08)
	/** action 引数に渡す事の出来る アクション  スペース削除 {@value} */
	public static final String ACT_TRIM			= "TRIM" ;						// 6.4.1.2 (2016/01/22)

	/** action 引数に渡す事の出来る アクション リスト  */
	private static final String[] ACTION_LIST = {
		ACT_UPPER , ACT_LOWER , ACT_MESSAGE , ACT_APPEND , ACT_ALL_APPEND , 
		ACT_MAP , ACT_ALL_MAP , ACT_MAPOBJ , ACT_ALL_MAPOBJ , ACT_LIST, ACT_ALL_LIST ,
		ACT_DAY_WEEK , ACT_MERGE , ACT_FIRST , ACT_ROW_APPEND , ACT_REPLACE , ACT_SUBSTR , 
		ACT_SPLIT , ACT_MAX_MIN , ACT_ALL_MAX_MIN , ACT_EXEC , ACT_CASE , ACT_ESCAPE , ACT_TRIM
	};

	private transient DBTableModel table;

	private String		tableId		= HybsSystem.TBL_MDL_KEY;
	private String		command		= CMD_SET;
	private String		key			;
	private String		inValue		;		// 3.5.4.0 (2003/11/25)
	private String		value		;
	private String		defaultVal	;
	private String		action		;
	private String		dbid		;				// 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
	private String		scope		= "request";	// "request","session"
	private String		tblScope	= "session";	// 5.1.2.0 (2010/01/01) DBTableModel の取得先のscope
	private String		separator	= ",";  		// 項目区切り文字
	private boolean		useMultiRows ;				// 3.2.4.0 (2003/06/12) マルチデータ(複数件検索)を使用するかしないか。初期値:使用せず
	private boolean		xssCheck	= HybsSystem.sysBool( "USE_XSS_CHECK" ); // 5.1.7.0 (2010/06/01) XSS対策

	private String	fromVal			;					// 5.2.2.0 (2010/11/01)
	private String	toVal			;					// 5.2.2.0 (2010/11/01)
	private boolean	tmpSelectedAll	;					// 5.6.4.3 (2013/05/24) action="ALL_xxx"を tmpSelectedAll="true" で内部処理します。

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

	/**
	 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
	 *
	 * @og.rev 3.1.7.0 (2003/05/02) isNullSet 属性が true(初期値)のときは、リクエスト情報から値を取得。
	 * @og.rev 3.1.7.0 (2003/05/02) scope 属性を設定するタイミングを、早くする。
	 * @og.rev 3.5.4.0 (2003/11/25) getRequestParameter( value ) メソッドを setValue に移動。
	 * @og.rev 5.1.7.0 (2010/06/01) SQLGET対応
	 * @og.rev 5.1.8.0 (2010/07/01) isNullSet 属性 廃止
	 * @og.rev 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doStartTag() {
		// 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
		if( useTag() ) {
			super.setScope( scope );		// デフォルトscope が "request" なので、再設定している。

	//		if( isNullSet ) {
	//			setUseValue( false );
	//		}

			// 5.1.7.0 (2010/06/01) SQLGET対応
			if( CMD_SQL.equals( command ) || CMD_SET.equals( command ) || CMD_SQLGET.equals( command ) ) {
				return EVAL_BODY_BUFFERED ;		// Body を評価する
			}
		}
		return SKIP_BODY ;				// Body を評価しない
	}

	/**
	 * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
	 *
	 * @og.rev 3.1.1.0 (2003/03/28) ボディの内容を取得する処理を、CommonTagSupport で行う。
	 * @og.rev 3.6.0.8 (2004/11/19) エラー発生時に確実にリリースされるように try finally 追加
	 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
	 * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更
	 * @og.rev 5.1.7.0 (2010/06/01) SQLGET対応
	 * @og.rev 5.1.7.0 (2010/06/01) XSS解除対応
	 * @og.rev 5.1.9.0 (2010/08/01) TransactionTag 対応。上位に TransactionTag があれば、そこからConnection をもらう。
	 * @og.rev 5.2.1.0 (2010/10/01) command="SET" action="APPEND"でvalueをbody部に書いた場合に動作しないバグを修正
	 * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
	 * @og.rev 5.3.8.0 (2011/08/01) Transaction発生箇所でclose()
	 * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
	 * @og.rev 6.3.6.1 (2015/08/28) QueryFactory.close( Query ) 廃止。Queryはキャッシュしません。
	 *
	 * @return	後続処理の指示(SKIP_BODY)
	 */
	@Override
	public int doAfterBody() {
		if( value == null || value.length() <= 0 ) {
			// 5.1.7.0 (2010/06/01) XSS対策
			useXssCheck( xssCheck );

			value = getBodyString();
			// 5.2.1.0 (2010/10/01)
			inValue = getBodyRawString();

			// 5.1.7.0 (2010/06/01) SQLGET対応
			if( CMD_SQL.equals( command ) || CMD_SQLGET.equals( command ) ) {
//				final Query query = QueryFactory.newInstance();		// 4.0.0 (2005/01/31)
//				Transaction tran = null;
//				try {
				// 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
				try( final Transaction tran = getTransaction() ) {
					final Query query = QueryFactory.newInstance();		// 4.0.0 (2005/01/31)
					value = value.trim();

//					// 5.1.9.0 (2010/08/01) TransactionTag 対応
//					final TransactionTag tranTag = (TransactionTag)findAncestorWithClass( this,TransactionTag.class );
//					if( tranTag == null ) {
//						tran = new TransactionReal( getApplicationInfo() );		// 5.3.7.0 (2011/07/01) 引数変更
//					}
//					else {
//						tran = tranTag.getTransaction();
//					}
//					query.setTransaction( dbid,tran );			// 5.1.9.0 (2010/08/01) TransactionTag 対応
					query.setConnection( tran.getConnection( dbid ) );			// 6.3.6.1 (2015/08/28)
					query.setResourceManager( getResource() );	// 4.0.0 (2005/01/31)
					query.setStatement( value );
					query.execute();

					table = query.getDBTableModel();
//					query.commit();				// 6.3.6.1 (2015/08/28)
					tran.commit();				// 6.3.6.1 (2015/08/28)
				}
//				finally {
//					QueryFactory.close( query );
//					if( tran != null ) { tran.close(); }		// 5.3.8.0 (2011/08/01) Transaction発生箇所でclose()
//				}
			}
		}

		return SKIP_BODY ;
	}

	/**
	 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) DBTableModelの値をSET/GETできる command , action を追加。
	 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
	 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
	 * @og.rev 3.1.5.0 (2003/04/22) DBTableModel が存在するときのみ実行するロジックになっていたバグ対応。
	 * @og.rev 5.1.2.0 (2010/01/01) DBTableModel の取得先の tblScope を追加。
	 * @og.rev 5.1.7.0 (2010/06/01) SQLGET対応
	 * @og.rev 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doEndTag() {
		debugPrint();		// 4.0.0 (2005/02/28)
		// 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
		if( useTag() ) {
			if( check( command, COMMAND_LIST ) ) {
				if( CMD_SETTBL.equals( command ) ||
					CMD_GETTBL.equals( command ) ||
					CMD_KEYTBL.equals( command ) ) {
	//					table = (DBTableModel)getSessionAttribute( tableId );
						// 5.1.2.0 (2010/01/01) DBTableModel の取得先の tblScope を追加。
						if( "session".equals( tblScope ) ) { table = (DBTableModel) getSessionAttribute( tableId ); }
						else if( "request".equals( tblScope ) ) { table = (DBTableModel) getRequestAttribute( tableId ); }
						else {
							final String errMsg = "このスコープはサポートされていません。[" + tblScope + "]";
							throw new IllegalArgumentException( errMsg );
						}
				}
			}

			commandExec( command );

			// 5.1.7.0 (2010/06/01) SQLGET対応
			if( CMD_GET.equals( command ) || CMD_GETTBL.equals( command ) || CMD_SQLGET.equals( command ) ) {
				if( value != null ) { jspPrint( value ); }
			}
		}
		return EVAL_PAGE ;
	}

	/**
	 * タグリブオブジェクトをリリースします。
	 * キャッシュされて再利用されるので、フィールドの初期設定を行います。
	 *
	 * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
	 * @og.rev 3.1.0.1 (2003/03/26) DBTableModelの値をSET/GETできる command , action を追加。
	 * @og.rev 3.1.0.1 (2003/03/26) query 属性を削除します。
	 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
	 * @og.rev 3.2.4.0 (2003/06/12) マルチデータ(複数件検索)を使用するかしないか。
	 * @og.rev 3.5.4.0 (2003/11/25) inValue 変数の追加
	 * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
	 * @og.rev 5.1.2.0 (2010/01/01) DBTableModel の取得先の tblScope を追加。
	 * @og.rev 5.1.7.0 (2010/06/01) XSS解除対応
	 * @og.rev 5.1.8.0 (2010/07/01) isNullSet 属性 廃止
	 * @og.rev 5.2.2.0 (2010/11/01) fromVal , toVal 属性 追加
	 * @og.rev 5.6.4.3 (2013/05/24) parameter 属性は、未使用なので削除
	 * @og.rev 5.6.4.3 (2013/05/24) tmpSelectedAll 属性追加。action="ALL_xxx"を tmpSelectedAll="true" に置き換えます。
	 *
	 */
	@Override
	protected void release2() {
		super.release2();
		tableId		= HybsSystem.TBL_MDL_KEY;
		command		= CMD_SET;
		key			= null;
		value		= null;
		defaultVal	= null;
		action		= null;
		table		= null;
		dbid		= null;
		scope		= "request";	// "request","session"
		tblScope	= "session";	// 5.1.2.0 (2010/01/01) DBTableModel の取得先のscope
		separator	= ",";
		useMultiRows = false;
		tmpSelectedAll	= false;	// 5.6.4.3 (2013/05/24)
		inValue		= null;			// 3.5.4.0 (2003/11/25)
		xssCheck	= HybsSystem.sysBool( "USE_XSS_CHECK" );	// 5.1.7.0 (2010/06/01) XSS解除対応
		fromVal		= null;			// 5.2.2.0 (2010/11/01)
		toVal		= null;			// 5.2.2.0 (2010/11/01)
	}

	/**
	 * コマンドを実行します。
	 *
	 * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される
	 * フィールド定数値のいづれかを、指定できます。
	 * コマンドを登録すると同時に,実行も行ないます。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) command に、SETTBL / GETTBL / KEYTBL / CLEAR を追加。
	 * @og.rev 3.1.0.1 (2003/03/26) query 属性を削除します。
	 * @og.rev 3.1.7.0 (2003/05/02) scope 属性を設定するタイミングを、早くする。
	 * @og.rev 3.7.1.0 (2005/04/15) command に、SETMEM を追加。
	 * @og.rev 5.1.7.0 (2010/06/01) SQLGET対応
	 *
	 * @param	command	コマンド (public static final 宣言されている文字列)
	 * @see		<a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.ValueTag.CMD_GET">コマンド定数</a>
	 */
	private void commandExec( final String command ) {

		if( CMD_SQL.equals( command ) ) {
			setSQLAttribute( table );
		}
		else if( CMD_SQLGET.equals( command ) ) {
			value = getSQLAttribute( table );
		}
		else if( CMD_SET.equals( command ) ) {
			value = nval( value, defaultVal );
			setAttribute( key,value,action );
		}
		else if( CMD_GET.equals( command ) ) {
			value = getAttribute( key,action );
		}
		else if( CMD_REMOVE.equals( command ) ) {
			removeAttribute( key );
		}
		else if( CMD_CLEAR.equals( command ) ) {
			clearAttribute( key );
		}
		else if( CMD_SETTBL.equals( command ) ) {
			setTableAttribute( table,key,action );
		}
		else if( CMD_GETTBL.equals( command ) ) {
			value = getTableAttribute( table,key,action );
		}
		else if( CMD_KEYTBL.equals( command ) ) {
			setKeyTableAttribute( table,key,value,action );
		}
		else if( CMD_SETMEM.equals( command ) ) {		// 3.7.1.0 (2005/04/15)
			value = nval( value, defaultVal );
			setAttribute( key,value,action );
			setRequestCacheData( key,(String)getObject( key ) );
		}
	}

	/**
	 * アクションを実行します。
	 *
	 * コマンドは action 属性で指定します。
	 * action コマンド が、 null の場合は、なにも実行しません。
	 *
	 * @og.rev 3.0.1.3 (2003/03/11) MESSAGE action を追加
	 * @og.rev 3.1.0.1 (2003/03/26) 引数を与えて処理する様に変更する。
	 * @og.rev 3.7.1.0 (2005/04/15) action に、DAY_WEEK を追加。
	 * @og.rev 3.7.1.1 (2005/05/23) action に、MERGE を追加。
	 * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( getResource().getMessage ⇒ getResource().getLabel )
	 * @og.rev 5.2.2.0 (2010/11/01) ACT_MERGE 時には、カンマで分解、separator で合成を行います。
	 * @og.rev 5.2.2.0 (2010/11/01) ACT_REPLACE 処理を新規追加します。
	 * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。
	 * @og.rev 5.6.6.1 (2013/07/12) value が null の場合は、無視します。
	 * @og.rev 5.7.7.2 (2014/06/20) EXEC と CASE アクションを追加
	 * @og.rev 6.3.1.1 (2015/07/10) action="REPLACE" の、fromVal,toVal は、カンマ区切りで指定可能にする。
	 * @og.rev 6.3.1.1 (2015/07/10) action="ESCAPE" 追加
	 * @og.rev 6.3.5.0 (2015/08/08) action="ESCAPE" 追加
	 * @og.rev 6.3.9.0 (2015/11/06) 文字列配列を toString() する。
	 * @og.rev 6.4.1.2 (2016/01/22) TRIM アクションを追加。
	 * @og.rev 6.4.2.0 (2016/01/29) HybsDateUtil.getCalendar( String ) を直接利用するように修正します。
	 *
	 * @param action	コマンド (public static final 宣言されている文字列)
	 * @param value		旧の値
	 *
	 * @return	処理後の値
	 */
	private String actionExec( final String action,final String value ) {
		String rtn = value;

	 	// 5.6.6.1 (2013/07/12) value が null の場合は、無視します。
		if( action == null || value == null ) { return rtn; }

		if( ACT_UPPER.equals( action ) ) {
			// Localeを共通管理するようになった場合、String.toUpperCase( Locale locale )使用の事
			rtn = value.toUpperCase(Locale.JAPAN);
		}
		else if( ACT_LOWER.equals( action ) ) {
			// Localeを共通管理するようになった場合、String.toLowerCase( Locale locale )使用の事
			rtn = value.toLowerCase(Locale.JAPAN);
		}
		else if( ACT_MESSAGE.equals( action ) ) {
			// 引数をメッセージリソースのキーとして、メッセージ変換する。
			rtn = getResource().getLabel( value );
		}
		else if( ACT_DAY_WEEK.equals( action ) ) {
			// 日付型文字列(YYYYMMDD) の入力データを、開始日を月曜日にセットします。
			// SUNDAY=1 , MONDAY=2 になります。月曜日との差だけ、前に戻します。
			// 指定日が日曜日の場合は、次の日(月曜日)に進めます。
//			final Calendar ymd = HybsSystem.getCalendar( value );
			final Calendar ymd = HybsDateUtil.getCalendar( value );				// 6.4.2.0 (2016/01/29)
			final int shu = ymd.get( Calendar.DAY_OF_WEEK ) - Calendar.MONDAY ;

			if( shu != 0 ) { ymd.add( Calendar.DATE, -shu ); }

			rtn = DateSet.getDate( ymd.getTimeInMillis() , "yyyyMMdd" );		// 5.5.7.2 (2012/10/09) HybsDateUtil を利用
		}
		// 3.7.1.1 (2005/05/23)
		else if( ACT_MERGE.equals( action ) ) {
			// 引数をカンマで文字列配列に分解します。
			final String[] str = StringUtil.csv2Array( value );
			final Set<String> set = new LinkedHashSet<>();
			for( int i=0; i<str.length; i++ ) {
				if( str[i] != null && str[i].length() > 0 ) {
					set.add( str[i] );
				}
			}

			// 分解後、マージ(Setで)されます。 登録順は、キープします。
			rtn = StringUtil.iterator2line( set.iterator(),separator );	// 5.2.2.0 (2010/11/01) separator 使用
		}
		// 5.2.2.0 (2010/11/01) ACT_REPLACE 処理を新規追加
		else if( ACT_REPLACE.equals( action ) ) {
			// value.replaceAll( from, to ) という文法で処理します。
			// 6.0.2.5 (2014/10/31) null でないことがわかっている値の冗長な null チェックがあります。
			if( fromVal != null && toVal != null ) {
//				rtn = value.replaceAll( fromVal, toVal );
				// 6.3.1.1 (2015/07/10) カンマ区切り可能にする。
				if( fromVal.indexOf( ',' ) < 0 ) {
					rtn = value.replaceAll( fromVal, toVal );
				}
				else {
					final String[] frmStr = fromVal.split( "," );
					final String[] toStr  = toVal.split( "," );
					if( frmStr.length == toStr.length ) {
						for( int i=0; i<frmStr.length; i++ ) {
							rtn = rtn.replaceAll( frmStr[i], toStr[i] );
						}
					}
					else {
						final String errMsg = "REPLACE時の fromValのカンマの数が、toValの数と一致しません。"
										// 6.3.9.0 (2015/11/06) 文字列配列を toString() する。
//										+ CR + " fromVal=[" + frmStr + "] , toVal=[" + toVal + "] , value=[" + value + "]";
										+ CR + " fromVal=[" + String.join( ",",frmStr ) + "] , toVal=[" + toVal + "] , value=[" + value + "]";
						throw new HybsSystemException( errMsg );
					}
				}
			}
		}
		// 5.2.2.0 (2010/11/01) SUBSTR 処理を新規追加
		else if( ACT_SUBSTR.equals( action ) ) {
			// value.substring( from, to ) という文法で処理します。
			// 6.0.2.5 (2014/10/31) null でないことがわかっている値の冗長な null チェックがあります。
				final int from = ( fromVal == null || fromVal.isEmpty() ) ? 0              : Integer.parseInt( fromVal );
				final int to   = (   toVal == null || toVal.isEmpty()   ) ? value.length() : Integer.parseInt( toVal );

				rtn = value.substring( from, to );
		}
		// 5.7.7.2 (2014/06/20) CASE 処理を新規追加
		else if( ACT_CASE.equals( action ) ) {
			// fromVal="A:1 B:2 C:3 D:4" 形式
			if( fromVal != null && fromVal.length()>0 ) {
				final String[] keys = StringUtil.csv2Array( fromVal , ' ' );
				for( int i=0; i<keys.length; i++ ) {
					final int idx = keys[i].indexOf( ':' );
					if( idx >= 0 ) {									// 分解した値にコロン(:)がなければ、パス
						final String key = keys[i].substring( 0,idx );	// 左辺(キー)
						if( value.equalsIgnoreCase( key ) ) {
							rtn = keys[i].substring( idx+1 );			// 右辺(値)
							break;
						}
					}
				}
			}
		}
		// 5.7.7.2 (2014/06/20) EXEC 処理を新規追加
		else if( ACT_EXEC.equals( action ) ) {
			final ScriptEngine jsEngine = new ScriptEngineManager().getEngineByName( "JavaScript" );
			try {
				final Object obj = jsEngine.eval( value );
				rtn = String.valueOf( obj );
			}
			catch( ScriptException ex ) {
				final String errMsg = "JavaScript式のパースに失敗しました。[" + value + "]";
				throw new HybsSystemException( errMsg , ex );
			}
		}
		// 6.3.5.0 (2015/08/08) action="ESCAPE" 追加
		else if( ACT_ESCAPE.equals( action ) ) {
			rtn = StringUtil.htmlFilter( value );
		}
		// 6.4.1.2 (2016/01/22) TRIM アクションを追加。
		else if( ACT_TRIM.equals( action ) ) {
			rtn = value.trim();
		}

		return rtn;
	}

	/**
	 * 指定のスコープの内部キャッシュ情報を、キーで登録します。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) 引数を与えて処理する様に変更する。
	 * @og.rev 3.5.4.0 (2003/11/25) APPENDアクションを有効にします。
	 * @og.rev 3.5.6.5 (2004/08/09) APPEND時のセパレータを外部指定の変数を使用
	 * @og.rev 5.1.8.0 (2010/07/01) isNullSet 属性 廃止
	 * @og.rev 5.2.2.0 (2010/11/01) ACT_SPLIT 追加
	 * @og.rev 5.6.4.3 (2013/05/24) ACT_MAX_MIN アクションの追加
	 * @og.rev 5.6.6.1 (2013/07/12) value が null の場合は、無視します。
	 *
	 * @param key		キー
	 * @param value		値
	 * @param action	アクション
	 */
	private void setAttribute( final String key,final String value,final String action ) {
		if( key == null || key.isEmpty() ) {
			final String errMsg = "key がセットされていません。"
						+ " command=" + command + " , action=" + action
						+ " , value=" + value ;			// 5.1.8.0 (2010/07/01) errMsg 修正
			throw new HybsSystemException( errMsg );
		}

		// 5.1.8.0 (2010/07/01) isNullSet 属性 廃止
	 	// 5.6.6.1 (2013/07/12) value が null の場合は、無視します。
		// 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
		if( value == null ) {
			setObject( key, null );			// 5.6.6.1 (2013/07/12) value が null の場合
		}
		else {
//		if( value != null ) {
			if( ACT_APPEND.equals( action ) ) {
				final String[] array = getRequestParameterValues( inValue );
				setObject( key, StringUtil.array2line( array,separator ) );
			}
	 		// 5.2.2.0 (2010/11/01) ACT_SPLIT 追加
			else if( ACT_SPLIT.equals( action ) )  {
				final String[] array = value.split( separator );
				setObject( key , array[0] );		// キー自体には、分割時の先頭の文字列を設定しておく。
				for( int i=0; i<array.length; i++ ) {
					setObject( key + i , array[i] );
				}
			}
	 		// 5.6.4.3 (2013/05/24) ACT_MAX_MIN アクションの追加
			else if( ACT_MAX_MIN.equals( action ) )  {
				final String[] array = value.split( separator );

				// command="SET" では、数字型としてのみ処理します。
				double minNum = Double.MAX_VALUE ;
				double maxNum = Double.MIN_VALUE ;
				double sumNum = 0d ;
				int    cntSum = 0;		// 平均計算に有効な件数

				for( int i=0; i<array.length; i++ ) {
					final String val = array[i].trim().replaceAll( ",","" );		// 数字型フォーマットのカンマを取り除く
					if( val.isEmpty() ) { continue; }		// ゼロ文字列の場合は、取り直し

					final double tmp = Double.parseDouble( val );
					if( minNum > tmp ) { minNum = tmp; }
					if( maxNum < tmp ) { maxNum = tmp; }
					sumNum += tmp ;  cntSum++ ;
				}

				// command="SET" の場合は、数字型の場合のみ使用します。
				if( cntSum > 0 ) {
					final NumberFormat nf = NumberFormat.getInstance();
					nf.setGroupingUsed( false );					// カンマ編集なし
					nf.setMaximumFractionDigits(2);					// 最大小数部は２桁
					nf.setMinimumFractionDigits(0);					// できれば、整数表示

					setObject( "MIN." + key,nf.format( minNum ) );		// Double.toString( minNum ) の代わり。
					setObject( "MAX." + key,nf.format( maxNum ) );
					setObject( "SUM." + key,nf.format( sumNum ) );
					setObject( "AVG." + key,nf.format( sumNum/cntSum ) );
				}
				else {
					setObject( "MIN." + key,nval( defaultVal , "" ) );
					setObject( "MAX." + key,nval( defaultVal , "" ) );
					setObject( "SUM." + key,nval( defaultVal , "" ) );
					setObject( "AVG." + key,nval( defaultVal , "" ) );
				}
			}
			else {
				setObject( key, actionExec( action,value ) );
			}
		}
//		else {
//			setObject( key, null );			// 5.6.6.1 (2013/07/12) value が null の場合
//		}
	}

	/**
	 * 指定のスコープの内部キャッシュ情報を、キーで取得します。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) 引数を与えて処理する様に変更する。
	 *
	 * @param key		キー
	 * @param action	アクション
	 *
	 * @return	キーに対する内部キャッシュ情報
	 */
	private String getAttribute( final String key,final String action ) {
		if( key == null || key.isEmpty() ) {
			final String errMsg = "key がセットされていません。"
						+ " command=" + command + " , action=" + action;	// 5.1.8.0 (2010/07/01) errMsg 修正
			throw new HybsSystemException( errMsg );
		}

		String rtn = defaultVal;
		final Object obj = pageContext.findAttribute( key );
		if( obj != null ) { rtn = obj.toString(); }

		return actionExec( action,rtn );
	}

	/**
	 * 指定のスコープの内部キャッシュ情報を削除します。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) 引数を与えて処理する様に変更する。
	 *
	 * @param key		キー
	 */
	private void removeAttribute( final String key ) {
		if( key == null || key.isEmpty() ) {
			final String errMsg = "key がセットされていません。"
						+ " command=" + command ;			// 5.1.8.0 (2010/07/01) errMsg 修正
			throw new HybsSystemException( errMsg );
		}
		removeObject( key );
	}

	/**
	 * セッション/アプリケーションスコープのキャッシュ情報をクリアします。
	 *
	 * このクリアは、キーの前方一致で、大文字小文字の区別をせずにクリアします。
	 * また、キーが null の場合は、"X_" で始めるもの以外のすべての値をクリアします。
	 * また、Ｗｅｂエンジン内部で使用しているキーは、ここではクリアできません。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) クリアコマンドの追加。
	 * @og.rev 4.3.4.0 (2008/12/01) PageContextのスコープをクラス変数としてアクセス
	 *
	 * @param key		キー
	 */
	private void clearAttribute( final String key ) {

		String lowKey = null;
		if( key != null ) { lowKey = key.toLowerCase(Locale.JAPAN); }

		Enumeration<String> ekeys = pageContext.getAttributeNamesInScope( PageContext.APPLICATION_SCOPE );		// 4.3.3.6 (2008/11/15) Generics警告対応
		while ( ekeys.hasMoreElements() ) {
			final String ekey = ekeys.nextElement().toLowerCase(Locale.JAPAN);		// 4.3.3.6 (2008/11/15) Generics警告対応
			if( ( ! ekey.startsWith( "h_") && ! ekey.startsWith( "x_") ) &&
				(  lowKey == null || ekey.startsWith( key ) ) ) {
					pageContext.removeAttribute( ekey, PageContext.APPLICATION_SCOPE ) ;
			}
		}

		ekeys = pageContext.getAttributeNamesInScope( PageContext.SESSION_SCOPE );
		while ( ekeys.hasMoreElements() ) {
			final String ekey = String.valueOf( ekeys.nextElement() ).toLowerCase(Locale.JAPAN);
			if( ( ! ekey.startsWith( "h_") && ! ekey.startsWith( "x_") ) &&
				(  lowKey == null || ekey.startsWith( key ) ) ) {
					pageContext.removeAttribute( ekey, PageContext.SESSION_SCOPE ) ;
			}
		}
	}

	/**
	 * 指定のスコープの内部キャッシュ情報を、指定のSQL文より作成します。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) 引数を与えて処理する様に変更する。
	 * @og.rev 3.2.4.0 (2003/06/12) マルチデータ(複数件検索)を使用するかしないか。
	 * @og.rev 3.8.6.0 (2006/08/07) nullSet="true"(初期値)の時は、検索結果がゼロ件時に "" をセットする。
	 * @og.rev 3.8.9.2 (2007/07/28) action="ROW_APPEND" 追加
	 * @og.rev 4.3.7.5 (2009/07/13) ACT_LIST、ACT_ALL_LIST アクションの追加
	 * @og.rev 5.1.8.0 (2010/07/01) isNullSet 属性 廃止
	 * @og.rev 5.5.0.3 (2012/03/12) ACT_MAP アクションの追加
	 * @og.rev 5.6.4.3 (2013/05/24) tmpSelectedAll 属性追加。action="ALL_xxx"を tmpSelectedAll="true" に置き換えます。
	 * @og.rev 6.2.4.2 (2015/05/29) ACT_MAPOBJ アクションの追加
	 * @og.rev 6.2.6.0 (2015/06/19) キーの判定に、isEmpty() が漏れていた。
	 *
	 * @param table DBTableModelオブジェクト
	 */
	private void setSQLAttribute( final DBTableModel table ) {
		if( table == null ) {		// 3.8.6.0 (2006/08/07)
			return;
		}

		final int clmCnt = table.getColumnCount();
		final int rowCnt = table.getRowCount();
		String sqlkey ;
		String sqlval ;
		String sufix = "";

		if( ACT_ROW_APPEND.equals( action ) ) {
			final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );	// 6.1.0.0 (2014/12/26) refactoring
			for( int clm=0; clm<clmCnt; clm++ ) {
				buf.setLength(0);
				for( int row=0; row<rowCnt; row++ ) {
					sqlval = table.getValue( row, clm );
					if( row > 0 ) { buf.append( separator ); }
					buf.append( sqlval );
				}
				sqlkey = table.getColumnName( clm );
				setObject( sqlkey , buf.toString() );
			}
		}
	 	// 4.3.7.5 (2009/07/13) ACT_LIST、ACT_ALL_LIST アクションの追加
		else if( ACT_LIST.equals( action ) ) {
			for( int clm=0; clm<clmCnt; clm++ ) {
				final ArrayList<String> list = new ArrayList<>();
				for( int row=0; row<rowCnt; row++ ) {
					sqlval = table.getValue( row, clm );
					list.add( sqlval );
				}
				sqlkey = table.getColumnName( clm );
				setObject( sqlkey , list );
			}
		}
	 	// 5.5.0.3 (2012/03/12) ACT_MAP アクションの追加
		else if( ACT_MAP.equals( action )  ) {
			if( clmCnt < 2 ) {
				final String errMsg = "action=MAP 時には、カラムは、２つ以上必要です。カラム数=[" + clmCnt + "]";
				throw new IllegalArgumentException( errMsg );
			}
			for( int row=0; row<rowCnt; row++ ) {
				sqlkey = table.getValue( row, 0 );			// 0番目カラムがキー
				sqlval = table.getValue( row, 1 );			// 1番目カラムが値
				setObject( sqlkey , sqlval );
			}
		}
		// 6.2.4.2 (2015/05/29) ACT_MAPOBJ アクションの追加
		else if( ACT_MAPOBJ.equals( action )  ) {
			if( clmCnt < 2 ) {
				final String errMsg = "action=MAPOBJ 時には、カラムは、２つ以上必要です。カラム数=[" + clmCnt + "]";
				throw new IllegalArgumentException( errMsg );
			}
			if( key == null || key.isEmpty() ) {			// 6.2.6.0 (2015/06/19)
				key = table.getColumnName( 0 );				// key が指定されていない場合は、最初のカラム名
			}
			final Map<String,String> mapObj = new TreeMap<>();
			for( int row=0; row<rowCnt; row++ ) {
				sqlkey = table.getValue( row, 0 );			// 0番目カラムがMapのキー
				sqlval = table.getValue( row, 1 );			// 1番目カラムがMapの値
				mapObj.put( sqlkey,sqlval );
			}
			setObject( key , mapObj );
		}
		else {
			// 5.1.8.0 (2010/07/01) isNullSet 属性 廃止
			if( rowCnt == 0 ) {
				if( useMultiRows ) { sufix = "0" ; }
				for( int clm=0; clm<clmCnt; clm++ ) {
					sqlkey = table.getColumnName( clm );
					sqlval = "";
					setObject( sqlkey + sufix, sqlval );
				}
			}
			else {
				for( int row=0; row<rowCnt; row++ ) {
					if( useMultiRows ) { sufix = String.valueOf( row ) ; }
					for( int clm=0; clm<clmCnt; clm++ ) {
						sqlkey = table.getColumnName( clm );
						sqlval = table.getValue( row, clm );
						setObject( sqlkey + sufix, sqlval );
					}
					if( ! useMultiRows ) { break; }
				}
			}
		}
	}

	/**
	 * 指定のSQL文の結果を文字列として画面に出力します。
	 * 画面に出力される項目は、1項目だけで2項目以降は無視されます。
	 *
	 * @og.rev 5.1.7.0 (2010/06/01) SQLGET対応
	 *
	 * @param table DBTableModelオブジェクト
	 *
	 * @return SQL文の結果文字列
	 */
	private String getSQLAttribute( final DBTableModel table ) {
		if( table == null ) {		// 3.8.6.0 (2006/08/07)
			return "";
		}

		final int rowCnt = table.getRowCount();
		final String rtn;
		if( ACT_ROW_APPEND.equals( action ) ) {
			final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
			for( int row=0; row<rowCnt; row++ ) {
				if( row > 0 ) { buf.append( separator ); }
				buf.append( table.getValue( row, 0 ) );
			}
			rtn = buf.toString();
		}
		else if( rowCnt == 0 ) {
			rtn = "";
		}
		else {
			rtn = table.getValue( 0, 0 );
		}

		return rtn;
	}

	/**
	 * 指定のスコープの内部キャッシュ情報に、DBTableModel の選択された値を登録します。
	 *
	 * 複数選択行が存在する場合は、先頭行を処理します。ただし、action="APPEND"の
	 * 場合は、separator属性で指定された文字を使用して、連結します。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) 新規作成
	 * @og.rev 3.5.6.5 (2004/08/09) ACT_APPEND 時の処理変更
	 * @og.rev 3.6.1.0 (2005/01/05) ACT_ALL_APPEND アクションの追加
	 * @og.rev 4.3.7.5 (2009/07/13) ACT_LIST、ACT_ALL_LIST アクションの追加
	 * @og.rev 5.1.6.0 (2010/05/01) ALL_APPENDで選択行がない場合に処理されないバグを修正
	 * @og.rev 5.5.0.3 (2012/03/12) ACT_MAP アクションの追加
	 * @og.rev 5.6.4.3 (2013/05/24) ACT_MAX_MIN,ACT_ALL_MAX_MIN アクションの追加
	 * @og.rev 5.6.4.3 (2013/05/24) tmpSelectedAll 属性追加。action="ALL_xxx"を tmpSelectedAll="true" に置き換えます。
	 * @og.rev 6.2.4.2 (2015/05/29) ACT_MAPOBJ アクションの追加
	 *
	 * @param table		DBTableModelオブジェクト
	 * @param key		キー
	 * @param action	アクション
	 */
	private void setTableAttribute( final DBTableModel table,final String key,final String action ) {
		if( table == null || table.getRowCount() == 0 || table.getColumnCount() == 0 ) { return ; }

		final int[] rowNo = getParameterRows();
		// 5.1.6.0 (2010/05/01)
		if( rowNo.length == 0 ) { return; }				// 5.6.4.3 (2013/05/24) tmpSelectedAll 属性を追加したので、0件判定が使える。

		final String[] keys ;
		if( key == null || key.isEmpty() ) {
			keys = table.getNames();
		}
		else {
			keys = new String[] { key } ;
		}

		// 5.6.4.3 (2013/05/24) tmpSelectedAll で、ロジックの共通化
		if( ACT_APPEND.equals( action ) ) {
			final StringBuilder val = new StringBuilder( BUFFER_MIDDLE );	// 6.1.0.0 (2014/12/26) refactoring
			for( int i=0; i<keys.length; i++ ) {
				final int clm = table.getColumnNo( keys[i] );
				val.setLength(0);
				val.append( table.getValue( rowNo[0],clm ) );
				for( int j=1; j<rowNo.length; j++ ) {
					val.append( separator );
					val.append( table.getValue( rowNo[j],clm ) );
				}
				setObject( keys[i],val.toString() );
			}
		}

	 	// 5.5.0.3 (2012/03/12) ACT_MAP アクションの追加
		else if( ACT_MAP.equals( action ) ) {
			int keyClm = table.getColumnNo( key   ,false );
			int valClm = table.getColumnNo( value ,false );

			if( keyClm < 0 ) { keyClm = 0; }	// キーとなるカラムが指定されていない場合は、最初のカラム
			if( valClm < 0 ) { valClm = 1; }	// 値となるカラムが指定されていない場合は、２番目のカラム

			for( int j=0; j<rowNo.length; j++ ) {
				final String mapkey = table.getValue( rowNo[j], keyClm );
				final String mapval = table.getValue( rowNo[j], valClm );
				setObject( mapkey , mapval );
			}
		}

		// 6.2.4.2 (2015/05/29) ACT_MAPOBJ アクションの追加
		else if( ACT_MAPOBJ.equals( action )  ) {
			int keyClm = table.getColumnNo( key   ,false );
			int valClm = table.getColumnNo( value ,false );

			if( keyClm < 0 ) { keyClm = 0; }	// キーとなるカラムが指定されていない場合は、最初のカラム
			if( valClm < 0 ) { valClm = 1; }	// 値となるカラムが指定されていない場合は、２番目のカラム

			final Map<String,String> mapObj = new TreeMap<>();
			for( int j=0; j<rowNo.length; j++ ) {
				final String mapkey = table.getValue( rowNo[j], keyClm );
				final String mapval = table.getValue( rowNo[j], valClm );
				mapObj.put( mapkey,mapval );
			}
			setObject( key , mapObj );
		}

	 	// 4.3.7.5 (2009/07/13) ACT_LIST アクションの追加
		else if( ACT_LIST.equals( action ) ) {
			for( int i=0; i<keys.length; i++ ) {
				final int clm = table.getColumnNo( keys[i] );
				final ArrayList<String> list = new ArrayList<>();
				for( int j=0; j<rowNo.length; j++ ) {
					list.add( table.getValue( rowNo[j],clm ) );
				}
				setObject( keys[i],list );
			}
		}

	 	// 5.6.4.3 (2013/05/24) ACT_MAX_MIN アクションの追加
		else if( ACT_MAX_MIN.equals( action ) ) {
			NumberFormat nf = null;
			for( int i=0; i<keys.length; i++ ) {
				final int clm = table.getColumnNo( keys[i] );
				final DBColumn clmObj = table.getDBColumn( clm );
				final String clsNm = clmObj.getClassName();			// NUMBER,INTEGER,DECIMAL が数字型。

				final boolean numFlag = "NUMBER,INTEGER,DECIMAL".indexOf( clsNm ) >= 0 ;		// 数字型:true

				String minVal = null ;
				String maxVal = null ;
				double minNum = Double.MAX_VALUE ;
				double maxNum = Double.MIN_VALUE ;
				double sumNum = 0d ;
				int    cntSum = 0;		// 平均計算に有効な件数

				for( int j=0; j<rowNo.length; j++ ) {
					final String val = table.getValue( rowNo[j],clm );
					if( val != null && val.length() > 0 ) {
						// 数字として比較
						if( numFlag ) {
							final double tmp = Double.parseDouble( val );
							if( minNum > tmp ) { minNum = tmp; minVal = val; }
							if( maxNum < tmp ) { maxNum = tmp; maxVal = val; }
							sumNum += tmp ;  cntSum++ ;
						}
						else {
							// 文字列として比較
							if( minVal == null || minVal.compareTo( val ) > 0 ) { minVal = val; }	// 最初のデータは、必ずセットする。
							if( maxVal == null || maxVal.compareTo( val ) < 0 ) { maxVal = val; }	// 最初のデータは、必ずセットする。
						}
					}
				}
				if( minVal == null ) { minVal = nval( defaultVal , "" ); }		// 最後まで値が決まらなければ、""(空文字列) にする。
				if( maxVal == null ) { maxVal = nval( defaultVal , "" ); }		// 最後まで値が決まらなければ、""(空文字列) にする。
				setObject( "MIN." + keys[i],minVal );
				setObject( "MAX." + keys[i],maxVal );

				// SUM と AVG は、数字型の場合のみセットします。
				if( cntSum > 0 ) {
					if( nf == null ) {
						nf = NumberFormat.getInstance();
						nf.setGroupingUsed( false );					// カンマ編集なし
						nf.setMaximumFractionDigits(2);					// 最大小数部は２桁
						nf.setMinimumFractionDigits(0);					// できれば、整数表示
					}
					setObject( "SUM." + keys[i],nf.format( sumNum ) );		// Double.toString( sumNum ) の代わり。
					setObject( "AVG." + keys[i],nf.format( sumNum/cntSum ) );
				}
				else {
					setObject( "SUM." + keys[i],nval( defaultVal , "" ) );
					setObject( "AVG." + keys[i],nval( defaultVal , "" ) );
				}
			}
		}
		else {
			for( int i=0; i<keys.length; i++ ) {
				final int clm = table.getColumnNo( keys[i] );
				setAttribute( keys[i],table.getValue( rowNo[0],clm ),action );
			}
		}
	}

	/**
	 * DBTableModel の選択された値を取得します。
	 *
	 * 複数選択行が存在する場合は、先頭行を処理します。ただし、action="APPEND"の
	 * 場合は、separator属性で指定された文字を使用して、連結します。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) 新規作成
	 * @og.rev 3.5.6.5 (2004/08/09) ACT_APPEND 時の処理変更
	 * @og.rev 3.6.1.0 (2005/01/05) ACT_ALL_APPEND アクションの追加
	 * @og.rev 5.1.6.0 (2010/05/01) ALL_APPENDで選択行がない場合に処理されないバグを修正
	 * @og.rev 5.6.4.3 (2013/05/24) tmpSelectedAll 属性追加。action="ALL_xxx"を tmpSelectedAll="true" に置き換えます。
	 *
	 * @param	table	DBTableModelオブジェクト
	 * @param	key		キー
	 * @param	action	アクション
	 *
	 * @return	DBTableModelの選択された値
	 */
	private String getTableAttribute( final DBTableModel table,final String key,final String action ) {
		if( table == null ) {
			final String errMsg = "table がセットされていません。"
						+ " command=" + command + " , action=" + action
						+ " , key=" + key ;			// 5.1.8.0 (2010/07/01) errMsg 修正
			throw new HybsSystemException( errMsg );
		}

		if( key == null || key.isEmpty() ) {
			final String errMsg = "key がセットされていません。"
						+ " command=" + command + " , action=" + action;			// 5.1.8.0 (2010/07/01) errMsg 修正
			throw new HybsSystemException( errMsg );
		}

		final int[] rowNo = getParameterRows();
		// 5.1.6.0 (2010/05/01)
		if( rowNo.length == 0 ) { return "" ; }				// 5.6.4.3 (2013/05/24) tmpSelectedAll 属性を追加したので、0件判定が使える。

		// 3.6.1.0 (2005/01/05) ACT_ALL_APPEND アクションの追加
		final int clm = table.getColumnNo( key );
		if( ACT_APPEND.equals( action ) ) {
			final StringBuilder val = new StringBuilder( BUFFER_MIDDLE );
			val.append( table.getValue( rowNo[0],clm ) );
			for( int j=1; j<rowNo.length; j++ ) {
				val.append( separator );
				val.append( table.getValue( rowNo[j],clm ) );
			}
			return val.toString() ;
		}
		else {
			return actionExec( action,table.getValue( rowNo[0],clm ) );
		}
	}

	/**
	 * 指定のスコープの内部キャッシュ情報に、DBTableModel の選択された値を登録します。
	 *
	 * これは、key で指定したカラムの値をキーとして、value で指定したカラムの値を
	 * value 値として設定します。
	 * setTableAttribute が、カラム(横持ち)データを処理するのに対して、
	 * ロウ(縦持ち)データを処理することが出来ます。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) 新規作成
	 * @og.rev 3.3.3.3 (2003/08/06) key 情報がデータの値になっていた。バグ修正。
	 * @og.rev 3.5.6.5 (2004/08/09) ACT_APPEND 時の処理変更
	 *
	 * @param table		DBTableModelオブジェクト
	 * @param key		キー
	 * @param value		値
	 * @param action	アクション
	 */
	private void setKeyTableAttribute( final DBTableModel table,final String key,final String value,final String action ) {
		if( table == null ) { return ; }

		if( key == null || key.isEmpty() ) {
			final String errMsg = "key がセットされていません。"
						+ " command=" + command + " , action=" + action
						+ " , value=" + value ;			// 5.1.8.0 (2010/07/01) errMsg 修正
			throw new HybsSystemException( errMsg );
		}

		final int[] rowNo = getParameterRows();
		if( rowNo.length == 0 ) { return ; }

		final int[] valClm ;
		if( value == null || value.isEmpty() ) {
			final String[] vals = table.getNames();
			valClm = new int[vals.length];
			for( int i=0; i<vals.length; i++ ) {
				valClm[i] = table.getColumnNo( vals[i] );
			}
		}
		else {
			valClm = new int[] { table.getColumnNo( value ) } ;
		}

		// 3.3.3.3 (2003/08/06) key 情報がデータの値になっていた。バグ修正。
		// 3.5.6.5 (2004/08/09) ロジック変更
		final StringBuilder val = new StringBuilder( BUFFER_MIDDLE );	// 6.1.0.0 (2014/12/26) refactoring
		for( int j=0; j<rowNo.length; j++ ) {
			final String rowKey = key + j ;
			if( ACT_APPEND.equals( action ) ) {
				val.setLength(0);
				val.append( table.getValue( rowNo[j],valClm[0] ) );
				for( int i=1; i<valClm.length; i++ ) {
					val.append( separator );
					val.append( table.getValue( rowNo[j],valClm[i] ) );
				}
				setObject( rowKey,val.toString() );
			}
			else {
				setAttribute( rowKey,table.getValue( rowNo[j],valClm[0] ),action );
			}
		}
	}

	/**
	 * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を処理の対象とします。
	 *
	 * action="FIRST" 処理と、tmpSelectedAll 属性追加に伴う処理を、Override します。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) 新規作成
	 * @og.rev 4.0.0.0 (2005/01/31) メイン処理を、super class で対応
	 * @og.rev 3.8.0.4 (2005/08/08) action="FIRST" 機能の追加
	 * @og.rev 5.6.4.3 (2013/05/24) tmpSelectedAll 属性の追加に伴い、全件選択状態のデータを作成します。
	 *
	 * @return	選択行の配列
	 * @og.rtnNotNull
	 */
	@Override
	protected int[] getParameterRows() {
		final int[] rowNo ;
		// 3.8.0.4 (2005/08/08) action="FIRST" 機能の追加
		if( ACT_FIRST.equals( action ) ) {
			rowNo = new int[] { 0 };
		}
		// 5.6.4.3 (2013/05/24) tmpSelectedAll 属性の追加
		else if( tmpSelectedAll ) {
			final int rowCnt = table.getRowCount();
			rowNo = new int[ rowCnt ];
			for( int i=0; i<rowCnt; i++ ) {
				rowNo[i] = i;
			}
		}
		else {
			rowNo = super.getParameterRows() ;
		}
		return rowNo ;
	}

	/**
	 * 【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】コマンド (SET,GET,REMOVE,SQL,SETTBL,GETTBL,KEYTBL,CLEAR,SETMEM)をセットします(初期値:SET)。
	 *
	 * @og.tag
	 * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される
	 * フィールド定数値のいづれかを、指定できます。
	 * 何も設定されない、または、null の場合は、"SET" が初期値にセットされます。
	 *
	 * CLEAR 以外のすべての処理は、指定のスコープの内部キャッシュ情報に対して行われます。
	 * <table border="1" frame="box" rules="all" >
	 *   <caption>コマンド 一覧</caption>
	 *   <tr><th>command </th><th>名称          </th><th>機能</th></tr>
	 *   <tr><td>SET    </td><td>セット         </td><td>指定のキーに、value値を登録します。</td></tr>
	 *   <tr><td>GET    </td><td>ゲット         </td><td>指定のキーの値を画面に出力します。</td></tr>
	 *   <tr><td>REMOVE </td><td>リムーブ       </td><td>指定のキーの値を削除します。</td></tr>
	 *   <tr><td>CLEAR  </td><td>クリア         </td><td>セッション/アプリケーションスコープのキャッシュ情報をクリアします。</td></tr>
	 *   <tr><td>SQL    </td><td>ＳＱＬ         </td><td>指定のSQL文の実行結果を、カラム名をキーとして設定します。</td></tr>
	 *   <tr><td>SQLGET </td><td>ＳＱＬゲット   </td><td>指定のSQL文の実行結果を、画面に出力します。(2項目以降は無視されます)。</td></tr>
	 *   <tr><td>SETTBL </td><td>セットテーブル </td><td>指定のキーに、DBTableModel の選択されたカラム(横持ち)の値を登録します。</td></tr>
	 *   <tr><td>GETTBL </td><td>ゲットテーブル </td><td>指定のキーに、DBTableModel の選択されたカラム(横持ち)の値を画面に出力します。</td></tr>
	 *   <tr><td>KEYTBL </td><td>キーテーブル   </td><td>指定のキーに、DBTableModel の選択されたロウ(縦持ち)の値を登録します。</td></tr>
	 *   <tr><td>SETMEM </td><td>セットメモリ   </td><td>指定のキーに、value値を内部キャッシュに登録します。</td></tr>
	 * </table>
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) 指定のコマンド以外は、エラーとするように変更。
	 * @og.rev 3.5.6.2 (2004/07/05) 文字列の連結にStringBuilderを使用します。
	 * @og.rev 6.3.4.0 (2015/08/01) Arrays.toString から String.join に置き換え。
	 *
	 * @param	cmd コマンド (public static final 宣言されている文字列)
	 * @see		<a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.ValueTag.CMD_GET">コマンド定数</a>
	 */
	public void setCommand( final String cmd ) {
		command = nval( getRequestParameter( cmd ),command ).toUpperCase(Locale.JAPAN);

		if( !check( command, COMMAND_LIST ) ) {
			final String errMsg = "指定のコマンドは実行できません。コマンドエラー"	+ CR
								+ "command=[" + command + "] "							+ CR
								+ "commandList=[" + String.join( ", " , COMMAND_LIST ) + "]" ;
			throw new HybsSystemException( errMsg );

//			final StringBuilder errMsg = new StringBuilder( BUFFER_MIDDLE )
//				.append( "指定のコマンドは実行できません。コマンドエラー" )
//				.append( CR )
//				.append( "command=[" ).append( command ).append( "] " )
//				.append( CR );
//			for( int i=0; i<COMMAND_LIST.length; i++ ) {
//				errMsg.append( " | " ).append( COMMAND_LIST[i] );
//			}
//			errMsg.append( " | " );
//			throw new HybsSystemException( errMsg.toString() );
		}
	}

	/**
	 * 【TAG】アクション(UPPER,LOWER,MESSAGE,APPEND,ALL_APPEND,MAP,ALL_MAP,LIST,ALL_LIST,
	 *        DAY_WEEK,MERGE,FIRST,ROW_APPEND,REPLACE,SUBSTR,SPLIT,MAX_MIN,ALL_MAX_MIN,EXEC,CASE)をセットします。
	 *
	 * @og.tag
	 * アクションは,HTMLから(get/post)指定されますので,ACT_xxx で設定される
	 * フィールド定数値のいづれかを、指定できます。
	 * 無指定の場合は、なにもしません。
	 *
	 * <table border="1" frame="box" rules="all" >
	 *   <caption>アクション 一覧</caption>
	 *   <tr><th>action     </th><th>名称                    </th><th>機能</th></tr>
	 *   <tr><td>UPPER      </td><td>アッパー(大文字化)      </td><td>value値を大文字に変換します。</td></tr>
	 *   <tr><td>LOWER      </td><td>ローワー(小文字化)      </td><td>value値を小文字に変換します。</td></tr>
	 *   <tr><td>MESSAGE    </td><td>メッセージ変換          </td><td>引数をメッセージリソースのキーとして、メッセージ変換します。</td></tr>
	 *   <tr><td>APPEND     </td><td>データアペンド          </td><td>複数リクエストや複数選択時に値を連結します。</td></tr>
	 *   <tr><td>ALL_APPEND </td><td>オールアペンド          </td><td>SETTBL,GETTBL 時に、チェック行以外の全行を対象に値の連結を行います。</td></tr>
	 *   <tr><td>MAP        </td><td>マップ                  </td><td>検索結果やTableModelのkeyをキーに、valueを値に一括設定します。</td></tr>
	 *   <tr><td>ALL_MAP    </td><td>オールマップ            </td><td>全行を対象に検索結果やTableModelのkeyをキーに、valueを値に一括設定します。</td></tr>
	 *   <tr><td>MAPOBJ     </td><td>マップオブジェクト      </td><td>検索結果やTableModelのkeyに、キーと値のMapを設定します。</td></tr>
	 *   <tr><td>ALL_MAPOBJ </td><td>オールマップオブジェクト</td><td>全行を対象に検索結果やTableModelのkeyに、キーと値のMapを設定します。</td></tr>
	 *   <tr><td>LIST       </td><td>リスト                  </td><td>複数リクエストや複数選択時に値をArrayListにセットします。</td></tr>
	 *   <tr><td>ALL_LIST   </td><td>オールリスト            </td><td>全行を対象に値をArrayListにセットします。</td></tr>
	 *   <tr><td>DAY_WEEK   </td><td>日付前方まるめ          </td><td>日付型文字列(YYYYMMDD) の値を、月曜日に変換します。</td></tr>
	 *   <tr><td>           </td><td>                        </td><td>指定日が日曜日の場合は、次の日(月曜日)に進めます。その他は、週始めに戻します。</td></tr>
	 *   <tr><td>MERGE      </td><td>データのマージ          </td><td>重複を除く、ユニークな値に、マージします。(カンマで分解、separatorで合成)</td></tr>
	 *   <tr><td>FIRST      </td><td>１件目取得              </td><td>最初の１件目を強制的に選択状態にして、処理を行います。</td></tr>
	 *   <tr><td>ROW_APPEND </td><td>検索結果の連結          </td><td>検索結果の行方向のデータを連結します。</td></tr>
	 *   <tr><td>REPLACE    </td><td>文字列置換              </td><td>value の値から、指定された正規表現(from)の部分文字列を、部分文字列(to)で置換します。</td></tr>
	 *   <tr><td>SUBSTR     </td><td>部分文字列              </td><td>value の値から、指定された(from)から(to)の部分文字列を作成します。</td></tr>
	 *   <tr><td>SPLIT      </td><td>文字列分割              </td><td>value の値から、指定されたseparatorで分割した文字列を作成します。(key+0～連番)</td></tr>
	 *   <tr><td>MAX_MIN    </td><td>最大_最小値             </td><td>選択行のkeyのカラムの最小値,最大値を、MIN.キー、MAX.キー の値にセットします。※１</td></tr>
	 *   <tr><td>ALL_MAX_MIN</td><td>最大_最小値             </td><td>全行を対象にkeyのカラムの最小値,最大値を、MIN.キー、MAX.キー の値にセットします。※１</td></tr>
	 *   <tr><td>EXEC       </td><td>計算結果                </td><td>value またはBODY部の値を、JavaScriptで計算した結果をセットします。</td></tr>
	 *   <tr><td>CASE       </td><td>条件分岐                </td><td>fromVal="A:1 B:2 C:3 D:4" 形式の値を元に、value値(左辺)に一致する右辺をセットします。※２</td></tr>
	 *   <tr><td>ESCAPE     </td><td>エスケープ文字          </td><td>HTML上のエスケープ文字に変換します。</td></tr>
	 *   <tr><td>TRIM       </td><td>スペース削除            </td><td>両端空白文字(スペース、タブ、改行等)を削除します。</td></tr>
	 * </table>
	 *
	 * ※１ MAX_MIN,ALL_MAX_MIN  については、DBTableModelのカラムのCLS_NAMEが、NUMBER,INTEGER,DECIMAL の場合は、数字型(double)に変換して比較します。
	 *    数字型(double)の場合だけ、合計(SUM.キー) と 平均(AVG.キー)計算も同時に行います。
	 *    それ以外の場合は、文字列比較を行います。（command="SETTBL" のみ）
	 *    command="SET" の場合は、数字型(double)として、value の値を、separator で分解したうえで、最大、最小、合計、平均 を計算し、
	 *    それぞれを、MIN.キー、MAX.キー、SUM.キー、AVG.キー 変数にセットします。
	 *    数字に変換できなかった場合は、エラーになります。
	 *    null は、無視され(平均を求める場合の母数としても無視)、すべてが nulll の場合は、ゼロ文字列("")になります。
	 *    ゼロ文字列("") の場合に、defaultVal 属性が設定されていると、defaultVal が設定されます。
	 * ※２ CASE は、fromVal="A:1 B:2 C:3 D:4" 形式の値に対して、コロン(:)で分解し、value値(左辺)が、一致する右辺を返します。
	 *    fromVal の値は、スペースで分割され、コロン(:)が存在する左辺(キー)と右辺(値)に分解し、value値とキーを比較し、
	 *    一致すれば、右辺の値を返します。
	 *    valueがnullの場合、defaultVal が設定されており、その値で、fromVal の値と比較します。
	 *    一致する値がなければ、元の value が返されます。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) 指定のアクション以外は、エラーとするように変更。
	 * @og.rev 3.5.6.2 (2004/07/05) 文字列の連結にStringBuilderを使用します。
	 * @og.rev 4.3.7.5 (2009/07/13) ACT_LIST、ACT_ALL_LIST アクションの追加(JavaDocのみ修正)
	 * @og.rev 5.6.4.3 (2013/05/24) ACTMAX_MIN アクションの追加(JavaDocのみ修正)
	 * @og.rev 5.6.4.3 (2013/05/24) tmpSelectedAll 属性追加にともなう修正。action="ALL_xxx"は、tmpSelectedAll=true にします。
	 * @og.rev 5.7.7.2 (2014/06/20) EXEC と CASE アクションを追加
	 * @og.rev 6.2.4.2 (2015/05/29) MAPOBJ , ALL_MAPOBJ アクションの追加
	 * @og.rev 6.3.4.0 (2015/08/01) Arrays.toString から String.join に置き換え。
	 * @og.rev 6.4.1.2 (2016/01/22) TRIM アクションを追加。
	 *
	 * @param	act アクション (public static final 宣言されている文字列)
	 * @see		<a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.ValueTag.ACT_APPEND">アクション定数</a>
	 */
	public void setAction( final String act ) {
		action = nval( getRequestParameter( act ),action );

		if( action != null && !check( action, ACTION_LIST ) ) {
			final String errMsg = "指定のアクションは実行できません。アクションエラー"	+ CR
								+ "action=[" + action + "] "							+ CR
								+ "actionList=[" + String.join( ", " , ACTION_LIST ) + "]" ;
			throw new HybsSystemException( errMsg );

//			final StringBuilder errMsg = new StringBuilder( BUFFER_MIDDLE )
//				.append( "指定のアクションは実行できません。アクションエラー" )
//				.append( CR )
//				.append( "action=[" ).append( action ).append( "] " )
//				.append( CR );
//			for( int i=0; i<ACTION_LIST.length; i++ ) {
//				errMsg.append( " | " ).append( ACTION_LIST[i] );
//			}
//			errMsg.append( " | " );
//			throw new HybsSystemException( errMsg.toString() );
		}

		// 5.6.4.3 (2013/05/24) tmpSelectedAll 属性追加。action="ALL_xxx"を tmpSelectedAll="true" に置き換えます。
		if( action != null && action.startsWith( "ALL_" ) ) {
			action      = action.substring( 4 );	// "ALL_" の４文字分削除
			tmpSelectedAll = true;
		}
	}

	/**
	 * 【TAG】パラメータ に登録するキーをセットします。
	 *
	 * @og.tag パラメータ に登録するキーをセットします。
	 *
	 * @og.rev 3.0.1.3 (2003/03/11) キーを toUpperCase している箇所を削除
	 * @og.rev 6.2.6.0 (2015/06/19) キーのnull判定は行わない。(個別のメソッド内で実施している。)
	 *
	 * @param	key1 登録キー
	 */
	public void setKey( final String key1 ) {
		key = nval( getRequestParameter( key1 ),key ) ;
	}

	/**
	 * 【TAG】パラメータ に登録する値をセットします。
	 *
	 * @og.tag パラメータ に登録する値をセットします。
	 *
	 * @og.rev 3.1.7.0 (2003/05/02) isNullSet 属性が true(初期値)のときは、リクエスト情報から値を取得。
	 * @og.rev 3.5.4.0 (2003/11/25) getRequestParameter( value ) メソッドを setValue に移動。
	 * @og.rev 5.1.8.0 (2010/07/01) isNullSet 属性 廃止
	 *
	 * @param	val	登録値
	 */
	public void setValue( final String val ) {
		inValue = val;		// 3.5.4.0 (2003/11/25) 入力変数も、キープしておく。
		value = getRequestParameter( inValue );
	}

	/**
	 * 【TAG】value属性に値がセットされていないとき使用する、初期値を指定します。
	 *
	 * @og.tag
	 * value属性に値がセットされていないときに、この初期値を使用します。
	 *
	 * @param	val 初期値
	 */
	public void setDefaultVal( final String val ) {
		defaultVal = getRequestParameter( val );
	}

	/**
	 * 【廃止】value が NULL の時に、設定するかどうか[true/false]を指定します(初期値:true)。
	 *
	 * @og.tag
	 * true の場合は, null のときでもセットします。
	 * false の場合は, null のときは、既存の値を置き換えません。
	 * 初期値は、null のときでもセットするです。 ("true")
	 *
	 * @og.rev 5.1.8.0 (2010/07/01) isNullSet 属性 廃止
	 *
	 * @param   flag NULL時設定有無 [true:設定する/それ以外:設定しない]
	 * @deprecated 5.1.8.0 (2010/07/01) 廃止。
	 */
	@Deprecated public void setNullSet( final String flag ) {
		// 廃止予定
	}

	/**
	 * 【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します。
	 *
	 * @og.tag Queryオブジェクトを作成する時のDB接続IDを指定します。
	 *
	 * @param	id データベース接続ID
	 */
	public void setDbid( final String id ) {
		dbid = nval( getRequestParameter( id ),dbid );
	}

	/**
	 * 【TAG】キャッシュする場合のスコープ(request,session)を指定します(初期値:request)。
	 *
	 * @og.tag
	 * "request","session" が指定できます。
	 * 初期値は、 "request" です。
	 *
	 * @param	scp	スコープ
	 */
	@Override
	public void setScope( final String scp ) {
		scope = nval( getRequestParameter( scp ),scope );
	}

	/**
	 * 【TAG】DBTableModel から取得する場合のスコープ(request,session)を指定します(初期値:session)。
	 *
	 * @og.tag
	 * "request","session" が指定できます。
	 * 初期値は、 "session" です。
	 *
	 * @og.rev 5.1.2.0 (2010/01/01) DBTableModel の取得先のscope
	 *
	 * @param	scp	スコープ
	 */
	public void setTblScope( final String scp ) {
		tblScope = nval( getRequestParameter( scp ),tblScope );
	}

	/**
	 * 【TAG】マルチデータ(複数件検索)を使用するかどうか[true/false]を指定します(初期値:false)。
	 *
	 * @og.tag
	 * command="SQL" の場合に、複数行検索した結果を、キー＋行番号 というキーを作成して
	 * 値を設定するかどうかを指定します。
	 * false の場合は、従来どおり、検索カラム名がキーになります。
	 * 初期値は、false です。
	 *
	 * @og.rev 3.2.4.0 (2003/06/12) 新規追加
	 *
	 * @param   flag 複数件検索 [true:使用する/false:使用しない]
	 */
	public void setUseMultiRows( final String flag ) {
		useMultiRows = nval( getRequestParameter( flag ),useMultiRows );
	}

	/**
	 * 【TAG】各種アクションの文字列を連結/分解する項目区切り文字をセットします(初期値:",")。
	 *
	 * @og.tag
	 * 各種アクションに基づく処理において、文字列の区切りを指定するのに使用します。
	 * APPEND、ROW_APPEND 時には、文字列の連結に使用します。
	 * MERGE の場合は、カンマで分解後、このセパレータでMERGE処理を行い、再び、連結します。
	 * 初期値は、"," に設定されています。
	 *
	 * @og.rev 3.5.6.5 (2004/08/09) 新規追加
	 *
	 * @param   sepa 項目区切り文字 (初期値:",")
	 */
	public void setSeparator( final String sepa ) {
		separator = nval( getRequestParameter( sepa ),separator );
	}

	/**
	 * 【TAG】パラメータの HTMLTag開始/終了文字(&gt;&lt;) 存在チェックを実施するかどうか[true/false]を設定します
	 *		(初期値:USE_XSS_CHECK[={@og.value SystemData#USE_XSS_CHECK}])。
	 *
	 * @og.tag
	 * クロスサイトスクリプティング(XSS)対策の一環としてless/greater than signについてのチェックを行います。
	 * (&gt;&lt;) が含まれていたエラーにする(true)／かノーチェックか(false)を指定します。
	 * (初期値:システム定数のUSE_XSS_CHECK[={@og.value SystemData#USE_XSS_CHECK}])。
	 *
	 * @og.rev 5.1.7.0 (2010/06/01) 新規追加
	 *
	 * @param	flag	XSSチェック [true:する/false:しない]
	 * @see		org.opengion.hayabusa.common.SystemData#USE_XSS_CHECK
	 */
	public void setXssCheck( final String flag ) {
		xssCheck = nval( getRequestParameter( flag ),xssCheck );
	}

	/**
	 * 【TAG】部分文字列置換の 置換え前の部分文字列(from)を指定します。
	 *
	 * @og.tag
	 * value の値から、指定された正規表現(from)に一致する、この文字列の各部分文字列に対し、
	 * 指定された文字列(to)で置換します。
	 * value.replaceAll( from, to ) という文法で処理します。
	 *
	 * ※ action="CASE" 時は、fromVal="A:1 B:2 C:3 D:4" 形式で指定可能です。
	 * ※ action="SUBSTR" 時は、fromVal は、数字 のみ設定可能です。
	 * ※ action="REPLACE" 時は、fromVal は、カンマ区切りで、複数のリプレースキーを指定できます。。
	 *            例: @1,@2,@3・・
	 *
	 * @og.rev 5.2.2.0 (2010/11/01) 新規追加
	 *
	 * @param	from	置換え前の部分文字列
	 * @see		#setToVal(String)
	 */
	public void setFromVal( final String from ) {
		fromVal = nval( getRequestParameter( from ),fromVal );
	}

	/**
	 * 【TAG】部分文字列置換の 置換え後の部分文字列(to)を指定します。
	 *
	 * @og.tag
	 * value の値から、指定された正規表現(from)に一致する、この文字列の各部分文字列に対し、
	 * 指定された文字列(to)で置換します。
	 * value.replaceAll( from, to ) という文法で処理します。
	 *
	 * ※ action="SUBSTR" 時は、toVal は、数字 のみ設定可能です。
	 * ※ action="REPLACE" 時は、toVal は、カンマ区切りで、複数の置換え後の文字列を指定できます。。
	 *            例: VLA1,VAL2,VAL・・
	 *
	 * @og.rev 5.2.2.0 (2010/11/01) 新規追加
	 *
	 * @param	to	置換え後の部分文字列
	 * @see		#setFromVal(String)
	 */
	public void setToVal( final String to ) {
		toVal = nval( getRequestParameter( to ),toVal );
	}

//	/**
//	 * シリアライズ用のカスタムシリアライズ書き込みメソッド。
//	 *
//	 * @og.rev 4.0.0.0 (2006/09/31) 新規追加
//	 * @serialData 一部のオブジェクトは、シリアライズされません。
//	 *
//	 * @param	strm	ObjectOutputStreamオブジェクト
//	 * @throws IOException	入出力エラーが発生した場合
//	 */
//	private void writeObject( final ObjectOutputStream strm ) throws IOException {
//		strm.defaultWriteObject();
//	}

//	/**
//	 * シリアライズ用のカスタムシリアライズ読み込みメソッド
//	 *
//	 * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。
//	 *
//	 * @og.rev 4.0.0.0 (2006/09/31) 新規追加
//	 * @serialData 一部のオブジェクトは、シリアライズされません。
//	 *
//	 * @param	strm	ObjectInputStreamオブジェクト
//	 * @see #release2()
//	 * @throws IOException	シリアライズに関する入出力エラーが発生した場合
//	 * @throws ClassNotFoundException	クラスを見つけることができなかった場合
//	 */
//	private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException {
//		strm.defaultReadObject();
//	}

	/**
	 * このオブジェクトの文字列表現を返します。
	 * 基本的にデバッグ目的に使用します。
	 *
	 * @og.rev 4.3.4.0 (2008/12/01) PageContextのスコープをクラス変数としてアクセス
	 * @og.rev 5.1.8.0 (2010/07/01) isNullSet 属性 廃止
	 *
	 * @return このクラスの文字列表現
	 * @og.rtnNotNull
	 */
	@Override
	public String toString() {
		final String rtnStr = org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
				.println( "VERSION"			,VERSION		)
				.println( "tableId"			,tableId		)
				.println( "command"			,command		)
				.println( "key"				,key			)
				.println( "inValue"			,inValue		)
				.println( "value"			,value			)
				.println( "defaultVal"		,defaultVal		)
				.println( "action"			,action			)
				.println( "dbid"			,dbid			)
				.println( "scope"			,scope			)
				.println( "separator"		,separator		)
				.println( "useMultiRows"	,useMultiRows	)
//				.println( "COMMAND_LIST"	,COMMAND_LIST	)
//				.println( "ACTION_LIST"		,ACTION_LIST	)
				.println( "Other..."	,getAttributes().getAttribute() )
				.fixForm().toString() ;

		final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE )
			.append( rtnStr )
			.append( CR )
			.append( "====================================" ).append( CR )
			.append( "APPLICATION_SCOPE:" ).append( CR );

		Enumeration<String> ekeys = pageContext.getAttributeNamesInScope( PageContext.APPLICATION_SCOPE );	// 4.3.3.6 (2008/11/15) Generics警告対応
		while ( ekeys.hasMoreElements() ) {
			final String ekey = ekeys.nextElement();		// 4.3.3.6 (2008/11/15) Generics警告対応
			// 6.0.2.5 (2014/10/31) char を append する。
			rtn.append( "  key=[" ).append( ekey )
				.append( "] value=[" )
				.append( pageContext.getAttribute( ekey,PageContext.APPLICATION_SCOPE ) )
				.append( ']' ).append( CR );
		}

		rtn.append( "SESSION_SCOPE:" ).append( CR );
		ekeys = pageContext.getAttributeNamesInScope( PageContext.SESSION_SCOPE );
		while ( ekeys.hasMoreElements() ) {
			final String ekey = String.valueOf( ekeys.nextElement() );
			// 6.0.2.5 (2014/10/31) char を append する。
			rtn.append( "  key=[" ).append( ekey )
				.append( "] value=[" )
				.append( pageContext.getAttribute( ekey,PageContext.SESSION_SCOPE ) )
				.append( ']' ).append( CR );
		}

		rtn.append( "REQUEST_SCOPE:" ).append( CR );
		ekeys = pageContext.getAttributeNamesInScope( PageContext.REQUEST_SCOPE );
		while ( ekeys.hasMoreElements() ) {
			final String ekey = String.valueOf( ekeys.nextElement() );
			// 6.0.2.5 (2014/10/31) char を append する。
			rtn.append( "  key=[" ).append( ekey )
				.append( "] value=[" )
				.append( pageContext.getAttribute( ekey,PageContext.REQUEST_SCOPE ) )
				.append( ']' ).append( CR );
		}

		rtn.append( "PAGE_SCOPE:" ).append( CR );
		ekeys = pageContext.getAttributeNamesInScope( PageContext.PAGE_SCOPE );
		while ( ekeys.hasMoreElements() ) {
			final String ekey = String.valueOf( ekeys.nextElement() );
			// 6.0.2.5 (2014/10/31) char を append する。
			rtn.append( "  key=[" ).append( ekey )
				.append( "] value=[" )
				.append( pageContext.getAttribute( ekey,PageContext.PAGE_SCOPE ) )
				.append( ']' ).append( CR );
		}
		rtn.append( "====================================" ).append( CR );

		return rtn.toString();
	}
}
