/*
 * 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 java.util.Arrays;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Set;
import java.util.TreeSet;

import org.opengion.fukurou.util.ErrorMessage;
import org.opengion.fukurou.util.StringUtil;
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.resource.ResourceManager;			// 6.4.0.2 (2015/12/11)
import org.opengion.fukurou.util.ToString;						// 6.1.1.0 (2015/01/17)
import static org.opengion.fukurou.util.StringUtil.nval;

/**
 * 登録データの物理チェック(整合性チェック、nullチェック)を行うタグです。
 *
 * コマンドに対応したチェック方式で、指定のカラムをチェックします。
 * command="NEW" の場合は、columns 引数にCSV形式で指定したカラム名より
 * リクエスト情報を取得して、値をチェックします。
 * 引数チェックでは、"%" や "_" などのあいまい検索時に指定する記号を
 * 含むとエラーになるカラムはチェック対象からはずす必要がある為、
 * チェックすべきカラムを指定する必要があります。
 * command="ENTRY" の場合は、columns 引数に無関係に、全てのリクエストされたカラム
 * の値をチェックします。これは、先の検索時の場合と異なり、ENTRYでは
 * データベースに値を設定する為、無条件にチェックする必要があります。
 * nullCheck は、command に無関係に指定のカラムが null (ゼロ文字列)かどうかを
 * 判定します。
 * maxRowCount は、一覧検索時のチェックされた件数が、指定の値を超えた場合に
 * エラーになります。minRowCount は、同様に、最小選択件数(設定値を含む)の指定です。
 * このタグは、エラー時には、それ以降のJSP画面を評価しません。BODY 部に記述された
 * 値は、エラー時のみ表示され、正常時には、なにも表示されません。これは、エラー時の
 * メッセージや、ユーザーにエラー時のアクションを行ってもらう場合の処理(例えば、
 * 画面を戻る為のボタンなど)を表示させます。
 * useColumnLabel を true にセットすると、エラー時のカラム名(ラベル)を、カラムオブジェクトから
 * 取得するようになります。動的カラム実行時や、DBTableModelに対して、ColumnEditor等で
 * ラベルを書き換えた場合に、有効です。false の場合は、基本的にはラベルリソースからの
 * 取得になりますが、ケースによっては、カラムオブジェクトから取得している場合もあります。
 * この属性は、互換性を重視し、初期値が、false になっています。
 *
 * ERR0012 : 指定のデータがセットされていません。(NULLエラー)。key={0}
 * ERR0017 : 選択エラー。選択行数({0} 件)が、最大制限値({1} 件)以上選ばれました。
 * ERR0018 : 選択エラー。選択行数({0} 件)が、最小制限値({1} 件)以下選ばれました。
 * ERR0036 : 選択必須エラー。以下のデータの内どれかは入力してください。key={0}
 * ERR0037 : データ整合性エラー。指定のキーは整合性チェックの結果マッチしませんでした。key={0} val={1} regex={2}
 *
 * command="MODIFY" , "DELETE" 時には、強制的に、minRowCount="1" で処理します。
 *
 * @og.formSample
 * ●形式：&lt;og:columnCheck command = "…" /&gt;
 * ●形式：&lt;og:columnCheck command = "…" &gt;エラー時のみ処理 &lt;/og:columnCheck&gt;
 * ●body：なし/あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
 *
 * ●Tag定義：
 *   &lt;og:columnCheck
 *       command            【TAG】コマンド[NEW/RENEW/ENTRY]をセットします(初期値:NEW)
 *       columns            【TAG】チェックすべきカラム列をCSV形式(CSV形式)で指定します
 *       nullCheck          【TAG】NULL チェックすべきカラム列をCSV形式(CSV形式)りで指定します
 *       mustAnyCheck       【TAG】選択必須カラム(指定のカラムの内最低ひとつがNULLでない)を"AA|BB|CC,XX|YY|ZZ" 形式で指定します
 *       checkType          【TAG】チェック対象のデータ[AUTO/NEW/ENTRY]を指定します(初期値:AUTO)
 *       maxRowCount        【TAG】ENTRY時にチェックで選択された行数の最大値を設定します
 *       minRowCount        【TAG】ENTRY時にチェックで選択された行数の最小値を設定します
 *       tableId            【TAG】(通常は使いません) sessionに登録されている DBTableModel を取り出すキーを指定します
 *       matchKeys          【TAG】正規表現でのマッチングを行うカラム列をCSV形式(CSV形式)で指定します
 *       matchVals          【TAG】正規表現でのマッチングを行うカラム列に対する値(正規表現)をCSV形式(CSV形式)で指定します
 *       realTime           【TAG】(通常は使いません)リアルタイムチェックを行う場合に有効にします(初期値:false)
 *       useStrict          【TAG】NEWの場合に、厳密にチェックするかどうか[true/false]を指定します(初期値:false)
 *       useColumnLabel     【TAG】カラムラベルを使用するかどうか[true/false]を指定します(初期値:false)
 *       checkNames         【TAG】リクエスト変数の正規化を行うカラムをCSV形式で複数指定します
 *       useSLabel          【TAG】7.0.7.0 (2019/12/13) ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
 *   &gt;   ... Body ...
 *   &lt;/og:columnCheck&gt;
 *
 * ●使用例
 * &lt;og:columnCheck
 *     command = "{&#064;command}"
 *     columns = "AAA,BBB,CCC"  DB定義(DBColumnリソース)で定義した項目(桁数,タイプ等)でチェックします。
 *     maxRowCount = "1"        チェックで選ばれた 最大選択件数(設定値を含む)を指定。
 *     minRowCount = "1"        チェックで選ばれた 最小選択件数(設定値を含む)を指定。
 *     nullCheck = "AAA,CCC"    NULLチェックを実行します。
 * /&gt;
 *
 * [エラー時に、BODY部に記述された内容を出力する。正常時には、このBODY部の記述は出力されません。]
 * &lt;og:columnCheck
 *     command = "{&#064;command}"
 *     columns = "AAA,BBB,CCC"      DB定義(DBColumnリソース)で定義した項目(桁数,タイプ等)でチェックします。
 *     nullCheck = "AAA,CCC"        NULLチェックを実行します。
 * &gt;
 *     &lt;form method=&quot;POST&quot; action=&quot;forward.jsp&quot; target=&quot;RESULT&quot;&gt;
 *         &lt;og:input type=&quot;button&quot; onClick=&quot;history.back()&quot; msg=&quot;MSG0049&quot; accesskey=&quot;R&quot; td=&quot;false&quot; /&gt;
 *     &lt;/form&gt;
 * &lt;/og:columnCheck&gt;
 *
 * mustAnyCheck 属性に、選択必須カラムを指定します。
 *      例：mustAnyCheck="AA|BB|CC"
 *          AA,BB,CC のカラムで選択必須(すべてがnullならエラー)
 *      例：mustAnyCheck="AA|BB|CC,XX|YY|ZZ"
 *          AA,BB,CC のセットと、XX,YY,ZZのセットでそれぞれ選択必須。
 *      例：mustAnyCheck="AA|XX,AA|YY,AA|ZZ"
 *          AA に値があればすべて成立。そうでない場合は、XX と YY と ZZ がすべて必須。
 *      例：mustAnyCheck="AA|BB,BB|CC,AA|CC"
 *          AA,BB,CC の内、どれか２つが必須。AAが成立すればBBかCCが必須。同様に、
 *          BBが成立すれば、AAかCCが必須。
 *
 *  例：query.jsp
 *        &lt;og:column name="AA" mustAny="true" /&gt;
 *        &lt;og:column name="BB" mustAny="true" /&gt;
 *        &lt;og:column name="XX" mustAny="XYZ"  /&gt;
 *        &lt;og:column name="YY" mustAny="XYZ"  /&gt;
 *      result.jsp
 *        &lt;og:columnCheck mustAnyCheck="AA|BB,XX|YY" /&gt;
 *      custom/custom.css
 *          .XYZ { background-color: Green; }
 *
 *  例:動的カラムで、entry.jsp でのチェックを行う場合。
 *     entry.jsp
 *        &lt;og:columnCheck command="NEW" columns="*" useColumnLabel="true" /&gt;
 *
 *     useColumnLabel で、動的に作成されたカラム(SAVE=TRUEでキャッシュ済み)を使って
 *     チェックします。command="NEW" なので、対象カラムを指定するのに、"*" ですべてを選択します。
 *
 * @og.group 画面登録
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class ColumnCheckTag extends CommonTagSupport {
	/** このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "7.0.7.0 (2019/12/13)" ;
	private static final long serialVersionUID = 707020191213L ;

	/** command 引数に渡す事の出来る コマンド  新規 {@value} */
	public static final String CMD_NEW	= "NEW" ;
	/** command 引数に渡す事の出来る コマンド  再検索 {@value}  */
	public static final String CMD_RENEW = "RENEW" ;
	/** command 引数に渡す事の出来る コマンド  エントリー {@value} */
	public static final String CMD_ENTRY   = "ENTRY" ;
	/** command 引数に渡す事の出来る コマンド リスト  */

	// 6.4.3.2 (2016/02/19) ENTRY時にチェックする対象を、tableId指定のテーブルのカラムに限定します。
	// 4.3.1.1 (2008/08/23) transient 追加

	private String		tableId		= HybsSystem.TBL_MDL_KEY;		// 3.5.4.3 (2004/01/05)
	private String		command		= CMD_NEW;	// 無指定時は、チェックを行う。
	private String[]	columns		;
	private String[]	nullCheck	;
	private String[]	mustAnyCheck;			// 3.8.0.9 (2005/10/17)
	private int			maxRowCount	= -1 ;		// 初期値として，無制限を指定
	private int			minRowCount	= -1 ;		// 初期値として，無制限を指定
	private String		checkType	= "AUTO";
	private String		bodyString	;			// 3.5.4.2 (2003/12/15)
	private String[]	matchKeys	;			// 4.0.0 (2005/11/30)
	private String[]	matchVals	;			// 4.0.0 (2005/11/30)
	private boolean		isRealTime	;			// 4.3.7.0 (2009/06/01)
	private boolean		isStrict	;			// 5.2.2.0 (2010/11/01) NEWの場合に、厳密にチェックするフラグを追加

	private boolean		isColumnLabel;			// 5.4.3.4 (2012/01/12) true の場合に、カラムラベルを使用します。

	private String		checkNames	; 			// 5.4.3.8 (2012/01/24)

	private boolean		useSLabel	;			// 7.0.7.0 (2019/12/13) ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)

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

	/**
	 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
	 *
	 * @og.rev 3.5.4.2 (2003/12/15) エラー時に、BODY部に記述された内容を出力する。
	 * @og.rev 5.0.0.2 (2009/09/15) xss対応⇒チェックする
	 * @og.rev 5.7.8.0 (2014/07/04) caseKey,caseVal,caseNN,caseNull 属性を追加
	 *
	 * @return	後続処理の指示( EVAL_BODY_BUFFERED )
	 */
	@Override
	public int doStartTag() {
		// 5.0.0.2 (2009/09/15) XSSチェックしない⇒する
		// useXssCheck( false );

		// 5.7.8.0 (2014/07/04) 追加
		return useTag() ? EVAL_BODY_BUFFERED : SKIP_BODY ;
	}

	/**
	 * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
	 *
	 * @og.rev 3.5.4.2 (2003/12/15) エラー時に、BODY部に記述された内容を出力する。
	 *
	 * @return	後続処理の指示(SKIP_BODY)
	 */
	@Override
	public int doAfterBody() {
		bodyString = getBodyString();

		return SKIP_BODY ;
	}

	/**
	 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
	 *
	 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
	 * @og.rev 3.4.0.3 (2003/09/10) command="NEW" でエラー発生時には、DBTableModel をクリアする。
	 * @og.rev 3.5.4.2 (2003/12/15) HTMLTableViewForm クラス名変更(⇒ ViewForm_HTMLTable)
	 * @og.rev 3.5.4.2 (2003/12/15) エラー時に、BODY部に記述された内容を出力する。
	 * @og.rev 3.5.4.3 (2004/01/05) tableId 属性を追加。
	 * @og.rev 3.5.4.4 (2004/01/16) エラー結果を表示するテーブル形式のフォーム修正
	 * @og.rev 3.5.5.2 (2004/04/02) TaglibUtil.makeHTMLErrorTable メソッドを利用
	 * @og.rev 4.1.2.1 (2008/03/13) table 属性を追加。
	 * @og.rev 4.3.3.0 (2008/10/01) viewSimple属性追加
	 * @og.rev 4.3.7.0 (2009/06/01) viewSimple属性名称変更 ⇒ isRealTime
	 * @og.rev 5.6.8.3 (2013/09/27) checkTypeがAutoの場合のセットをここで行い、tableModelチェックをcheckTypeで行う。
	 * @og.rev 5.7.8.0 (2014/07/04) caseKey,caseVal,caseNN,caseNull 属性を追加
	 * @og.rev 6.4.3.2 (2016/02/19) ENTRY時にチェックする対象を、tableId指定のテーブルのカラムに限定します。
	 * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doEndTag() {
		debugPrint();		// 4.0.0 (2005/02/28)

		// 5.7.8.0 (2014/07/04) caseKey,caseVal,caseNN,caseNull 属性を追加
		if( !useTag() ) { return EVAL_PAGE ; }		// ページの残りを評価する。

		int rtnCode = EVAL_PAGE;

		// 6.4.3.2 (2016/02/19) ENTRY時にチェックする対象を、tableId指定のテーブルのカラムに限定します。

		// 5.6.8.3 (2013/09/27) チェックタイプのautoを入れる位置変更
		if( "AUTO".equals( checkType ) ) { checkType = command; }

		// 6.4.3.2 (2016/02/19) ENTRY時にチェックする対象を、tableId指定のテーブルのカラムに限定します。
			// 3.5.5.2 (2004/04/02) TaglibUtil.makeHTMLErrorTable メソッドを利用
			final ErrorMessage errMsg = makeErrorDBTable();
			if( errMsg.getKekka() >= ErrorMessage.NG ) {
				if( bodyString != null ) { jspPrint( bodyString ); }	// 3.5.4.2 (2003/12/15)

				// 4.3.3.0 (2008/10/01)
				// 4.3.7.0 (2009/06/01)
				// 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
//				if( isRealTime ) { jspPrint( TaglibUtil.makeHTMLSimpleErrorList( errMsg, getResource() ) ); }
//				else {             jspPrint( TaglibUtil.makeHTMLErrorTable(      errMsg, getResource() ) ); }
				if( isRealTime ) { jspPrint( TaglibUtil.makeHTMLSimpleErrorList( errMsg, getResource(),useSLabel ) ); }
				else {             jspPrint( TaglibUtil.makeHTMLErrorTable(      errMsg, getResource(),useSLabel ) ); }

				if( CMD_NEW.equals( command ) ) {
					removeObject( tableId );
				}
				rtnCode = SKIP_PAGE ;
			}
			else if( errMsg.getKekka() == ErrorMessage.WARNING ) {
				// 4.3.3.0 (2008/10/01)
				// 4.3.7.0 (2009/06/01)
				// 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
//				if( isRealTime ) { jspPrint( TaglibUtil.makeHTMLSimpleErrorList( errMsg, getResource() ) ); }
//				else {             jspPrint( TaglibUtil.makeHTMLErrorTable(      errMsg, getResource() ) ); }
				if( isRealTime ) { jspPrint( TaglibUtil.makeHTMLSimpleErrorList( errMsg, getResource(),useSLabel ) ); }
				else {             jspPrint( TaglibUtil.makeHTMLErrorTable(      errMsg, getResource(),useSLabel ) ); }
			}

		return rtnCode ;
	}

	/**
	 * タグリブオブジェクトをリリースします。
	 *
	 * キャッシュされて再利用されるので、フィールドの初期設定を行います。
	 *
	 * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
	 * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
	 * @og.rev 3.5.4.2 (2003/12/15) エラー時に、BODY部に記述された内容を出力する。
	 * @og.rev 3.5.4.3 (2004/01/05) tableId 属性を追加。
	 * @og.rev 3.8.0.9 (2005/10/17) mustAnyCheck 属性を追加。
	 * @og.rev 4.1.2.1 (2008/03/13) table 属性を追加。
	 * @og.rev 4.3.3.0 (2008/10/01) viewSimple属性追加
	 * @og.rev 4.3.7.0 (2009/06/01) viewSimple属性名称変更 ⇒ isRealTime
	 * @og.rev 5.2.2.0 (2010/11/01) NEWの場合に、厳密にチェックするフラグを追加
	 * @og.rev 5.4.3.4 (2012/01/12) isColumnLabelを追加
	 * @og.rev 6.4.3.2 (2016/02/19) ENTRY時にチェックする対象を、tableId指定のテーブルのカラムに限定します。
	 * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
	 */
	@Override
	protected void release2() {
		super.release2();
		command		= CMD_NEW;	// 無指定時は、チェックを行う。
		columns		= null;
		nullCheck	= null;
		maxRowCount	= -1 ;		// 初期値として，無制限を指定
		minRowCount	= -1 ;		// 初期値として，無制限を指定
		checkType	= "AUTO";
		bodyString	= null ;	// 3.5.4.2 (2003/12/15)
		tableId		= HybsSystem.TBL_MDL_KEY;		// 3.5.4.3 (2004/01/05)
		mustAnyCheck= null;		// 3.8.0.9 (2005/10/17)
		matchKeys	= null;		// 4.0.0 (2005/11/30)
		matchVals	= null;		// 4.0.0 (2005/11/30)
		isRealTime	= false;	// 4.3.7.0 (2009/06/01)
		isStrict	= false;	// 5.2.2.0 (2010/11/01) NEWの場合に、厳密にチェックするフラグを追加
		isColumnLabel= false;	// 5.4.3.4 (2012/01/12) true の場合に、カラムラベルを使用します。
		checkNames	= null; 	// 5.4.3.8 (2012/01/24)
		useSLabel	= false;	// 7.0.7.0 (2019/12/13) ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
	}

	/**
	 * DBColumn オブジェクトを作成して、DBColumn#valueCheck( String )で
	 * チェックを行う。その結果の、ErrorMessage オブジェクトを DBTableModel に
	 * 取り込んで、エラーの場合は、その表示を行う。
	 * 表示方法は、そのまま ViewForm オブジェクトを作成して、表示を行う。
	 *
	 * @og.rev 3.5.5.2 (2004/04/02) リターン値を、DBTableModel から ErrorMessage に変更
	 * @og.rev 4.0.0.0 (2005/01/31) リターン値の ErrorMessage は、必ず存在する。
	 * @og.rev 4.1.2.1 (2008/03/13) command="MODIFY" , "DELETE" 時には、強制的に、minRowCount="1" で処理します。
	 * @og.rev 5.6.8.3 (2013/09/27) checkTypeのAuto時設定位置をdoEndTagでするように変更
	 *
	 * @return	エラーメッセージのテーブルモデル
	 * @og.rtnNotNull
	 */
	private ErrorMessage makeErrorDBTable() {
		ErrorMessage errMsg = new ErrorMessage();

		//if( "AUTO".equals( checkType ) ) { checkType = command; } // 5.6.8.3 (2013/09/27) move
		if( CMD_ENTRY.equals( checkType ) ) {
			errMsg.setTitle( "Request Column Error!" );
			errMsg = makeEntryErrorMessage( errMsg );
			errMsg = makeMaxRowCountErrorMessage( errMsg );
			errMsg = makeMinRowCountErrorMessage( errMsg );
		}
		else if( CMD_NEW.equals( checkType ) ) {
			errMsg.setTitle( "Entry Column Error!" );
			errMsg = makeErrorMessage( errMsg );
			errMsg = makeMaxRowCountErrorMessage( errMsg );
			errMsg = makeMinRowCountErrorMessage( errMsg );
		}
		else if( minRowCount >= 0 || maxRowCount >= 0) {	// -1 は制限無し
			errMsg.setTitle( "Row Count Error Limited Error!" );
			errMsg = makeMaxRowCountErrorMessage( errMsg );
			errMsg = makeMinRowCountErrorMessage( errMsg );
		}
	 	// 4.1.2.1 (2008/03/13) command="MODIFY" , "DELETE" 時には、強制的に、minRowCount="1" で処理します。
		// 6.3.9.0 (2015/11/06) 条件は効果がない(findbugs)
		else if( "MODIFY,DELETE".indexOf( checkType ) >= 0 ) {
			minRowCount = 1;
			errMsg = makeMinRowCountErrorMessage( errMsg );
		}
		return errMsg;
	}

	/**
	 * ErrorMessageをセットします。
	 * 引数のカラム名配列よりリクエスト情報を取得して、値をチェックします。
	 * DBColumn#valueCheck( String ) の結果のErrorMessageをすべて append
	 * していきます。
	 *
	 * @og.rev 3.8.0.9 (2005/10/17) 選択必須 mustAnyCheck のチェック追加
	 * @og.rev 3.8.1.0 (2005/10/24) リクエスト情報の正規化変換(DBColumn#valueSet(String))中止
	 * @og.rev 3.8.5.3 (2006/06/30) リクエストに % , _ が含まれたときは、削除します。
	 * @og.rev 4.1.2.1 (2008/03/13) must , mustAny の自動取得追加
	 * @og.rev 5.0.0.2 (2009/09/15) 個別にxssチェックをfalse
	 * @og.rev 5.1.9.0 (2010/08/01) 同じ名前の項目は、1つにまとめる(ラジオボタン等)
	 * @og.rev 5.2.0.0 (2010/09/01) リアルタイムチェックの場合は、must,mustAnyの自動チェックは行わない
	 * @og.rev 5.2.2.0 (2010/11/01) DBColumn#valueCheck で、甘いチェックを行うように、引数に isStrict を追加
	 * @og.rev 5.4.3.4 (2012/01/12) getLabel( String )を、リソースからに統一するとともに、isColumnLabel 対応を行う。
	 * @og.rev 5.4.3.8 (2012/01/28) checkNames対応
	 * @og.rev 6.4.0.2 (2015/12/11) ResourceManagerの取得を、先に行っておく。
	 * @og.rev 6.8.4.2 (2017/12/25) カラムチェックで、#valueSet(String) で、ｴﾗｰが発生した場合でも、#valueCheck(String) を行うようにします。
	 *
	 * @param	errMsg	ErrorMessageオブジェクト
	 *
	 * @return	カラムキー ＋ 値 のエラーメッセージオブジェクト
	 */
	private ErrorMessage makeErrorMessage( final ErrorMessage errMsg ) {

	 	// 4.1.2.1 (2008/03/13) must , mustAny の自動取得追加
		// request から取出す 注意：mustAny 以外の自由形式の値は所得していません。
		// 5.2.0.0 (2010/09/01) リアルタイムチェックの場合は、must,mustAnyの自動チェックは行わない
		//  (基本的にパラメーターを送らない限り自動チェックは動かないが、RequestCacheにより動くことがある)
		if( !isRealTime ) {
			if( nullCheck == null ) {
				nullCheck = getRequestValues( HybsSystem.MUST_KEY + "must" );
				// 5.1.9.0 (2010/08/01) 同じ名前の項目は、1つにまとめる(ラジオボタン等)
				if( nullCheck != null ) {
					final Set<String> ss = new TreeSet<>();
					ss.addAll( Arrays.asList( nullCheck ) );
					nullCheck = ss.toArray( new String[ss.size()] );		// 5.1.9.0 (2010/08/01) K.H
				}
			}
			if( mustAnyCheck == null ) {
				final String[] mustAnyReq = getRequestValues( HybsSystem.MUST_KEY + "mustAny" );
				if( mustAnyReq != null && mustAnyReq.length > 0 ) {
					mustAnyCheck = new String[] { StringUtil.array2line( mustAnyReq,"|" ) };
				}
			}
		}

		// 6.4.0.2 (2015/12/11) ResourceManagerの取得を、先に行っておく。
		final ResourceManager resource = getResource();

		if( nullCheck != null && nullCheck.length != 0 ) {
			for( int i=0; i<nullCheck.length; i++ ) {
				final String clmKey = nullCheck[i];		// 5.4.3.4 (2012/01/12)
				// String val  = getRequestValue( nullCheck[i] );
				final String val  = getRequestValue( clmKey, false ); // 5.0.0.2 (2009/09/15)
				if( val == null || val.isEmpty() ) {
					// 5.4.3.4 (2012/01/12) isColumnLabel 追加
					final String label = isColumnLabel ? getDBColumn( clmKey ).getLabel() : resource.getLabel( clmKey );
					// ERR0012 : 指定のデータがセットされていません。(NULLエラー)。key={0}
					errMsg.addMessage( 0,ErrorMessage.NG,"ERR0012",label );
				}
			}
		}
		// 3.8.0.9 (2005/10/17) 選択必須 mustAnyCheck のチェック追加
		if( mustAnyCheck != null && mustAnyCheck.length != 0 ) {
			final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );		// 6.1.0.0 (2014/12/26) refactoring
			for( int i=0; i<mustAnyCheck.length; i++ ) {
				boolean flag = false;
				final String[] mustSub = StringUtil.csv2Array( mustAnyCheck[i],'|' );
				for( int j=0; j<mustSub.length; j++ ) {
					// String val  = getRequestValue( mustSub[j] );
					final String val  = getRequestValue( mustSub[j], false ); // 5.0.0.2 (2009/09/15)
					if( val != null && val.length() > 0 ) {
						flag = true; break;		// ひとつでもnullでなければ、OK
					}
				}
				if( ! flag ) {
					buf.setLength(0);							// 6.1.0.0 (2014/12/26) refactoring
					for( int j=0; j<mustSub.length; j++ ) {
						final String clmKey = mustSub[j];		// 5.4.3.4 (2012/01/12)
						// 5.4.3.4 (2012/01/12) isColumnLabel 追加
						final String label = isColumnLabel ? getDBColumn( clmKey ).getLabel() : resource.getLabel( clmKey );
						buf.append( label ).append( ',' );		// 6.0.2.5 (2014/10/31) char を append する。
					}
					// ERR0036 : 選択必須エラー。以下のデータの内どれかは入力してください。key={0}
					errMsg.addMessage( 0,ErrorMessage.NG,"ERR0036",buf.toString() );
				}
			}
		}
		if( columns != null && columns.length != 0 ) {
			for( int i=0; i<columns.length; i++ ) {
	 			// 3.8.1.0 (2005/10/24) リクエスト情報の正規化変換(DBColumn#valueSet(String))中止
				// String clmVal = getRequestValue( columns[i] );
				String clmVal = getRequestValue( columns[i], false ); // 5.0.0.2 (2009/09/15)
				if( clmVal != null && clmVal.length() > 0 ) {
					clmVal = StringUtil.replace( clmVal,"%","" );		// 3.8.5.3 (2006/06/30)
					clmVal = StringUtil.replace( clmVal,"_","" );		// 3.8.5.3 (2006/06/30)
					final DBColumn dbColumn = getDBColumn( columns[i] );
					// 5.4.3.8 (2012/01/24) checkNames対応
					if( ( "," + checkNames + "," ).indexOf( "," + columns[i] + "," ) >= 0 ) {
						// 6.8.4.2 (2017/12/25) カラムチェックで、#valueSet(String) で、ｴﾗｰが発生した場合でも、#valueCheck(String) を行うようにします。
						try {
							final String val = dbColumn.valueSet( clmVal );
							if( val != null ) { clmVal = val; }
						}
						catch( RuntimeException ex ) {
							;	// #valueSet(String) で、ｴﾗｰが発生した場合でも、#valueCheck(String) を行うようにします。
						}
					}
	 				// 5.2.2.0 (2010/11/01) DBColumn#valueCheck で、甘いチェックを行うように、引数に isStrict を追加
					errMsg.append( dbColumn.valueCheck( clmVal,isStrict ) );
				}
			}
		}
		// 4.0.0 (2005/11/30) 正規表現チェックの追加
		// 6.9.8.0 (2018/05/28) FindBugs:コンストラクタで初期化されていないフィールドを null チェックなしで null 値を利用している
//		if( matchKeys != null && matchKeys.length != 0 ) {
		if( matchKeys != null && matchKeys.length > 0 && matchVals != null && matchVals.length > 0 ) {
			for( int i=0; i<matchKeys.length; i++ ) {
				final String clmKey = matchKeys[i];		// 5.4.3.4 (2012/01/12)
				// String val  = getRequestValue( matchKeys[i] );
				final String val  = getRequestValue( clmKey, false ); // 5.0.0.2 (2009/09/15)
				if( val != null && ! val.matches( matchVals[i] ) ) {
					// 5.4.3.4 (2012/01/12) isColumnLabel 追加
					final String label = isColumnLabel ? getDBColumn( clmKey ).getLabel() : resource.getLabel( clmKey );
					// ERR0037 : データ整合性エラー。指定のキーは整合性チェックの結果マッチしませんでした。key={0} val={1} regex={2}
					errMsg.addMessage( 0,ErrorMessage.NG,"ERR0037",label,val,matchVals[i] );
				}
			}
		}

		return errMsg;
	}

	/**
	 * エントリーデータのErrorMessageをセットします。
	 * 引数のカラム名配列よりエントリーデータ形式のリクエスト情報を取得して、
	 * 値をチェックします。
	 * DBColumn#valueCheck( String ) の結果のErrorMessageをすべて append
	 * していきます。
	 *
	 * @og.rev 3.1.0.0 (2003/03/20) 名前と行番号の区切り記号を "^" から "__" に変更。
	 * @og.rev 3.5.5.0 (2004/03/12) 名前と行番号の区切り記号("__")を、HybsSystem.JOINT_STRING  に変更。
	 * @og.rev 3.8.0.9 (2005/10/17) 選択必須 mustAnyCheck のチェック追加
	 * @og.rev 4.1.2.1 (2008/03/13) must , mustAny の自動取得追加
	 * @og.rev 4.3.6.4 (2009/05/01) 削除時に必ずmustAnyチェックエラーになるバグを修正(書込み可能行のみを処理する
	 * @og.rev 4.3.7.0 (2009/06/01) リアルタイムチェックの場合は、must,mustAnyの自動チェックは行わない
	 * @og.rev 5.0.0.2 (2009/09/15) xssチェック
	 * @og.rev 5.4.3.4 (2012/01/12) getLabel( String )を、リソースからに統一するとともに、isColumnLabel 対応を行う。
	 * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
	 * @og.rev 6.4.0.2 (2015/12/11) ResourceManagerの取得を、先に行っておく。
	 * @og.rev 6.4.3.2 (2016/02/19) ENTRY時にチェックする対象を、tableId指定のテーブルのカラムに限定します。
	 * @og.rev 6.8.4.2 (2017/12/25) カラムチェックで、#valueSet(String) で、ｴﾗｰが発生した場合でも、#valueCheck(String) を行うようにします。
	 * @og.rev 6.9.3.1 (2018/04/02) カラムチェックで、mustAnyのチェック方法改善
	 *
	 * @param	errMsg	ErrorMessageオブジェクト
	 *
	 * @return	カラムキー ＋ 値 のエラーメッセージオブジェクト
	 */
	private ErrorMessage makeEntryErrorMessage( final ErrorMessage errMsg ) {
		final int[] rowNo = getParameterRows();
		if( rowNo.length == 0 ) { return errMsg; }

		// 6.4.3.2 (2016/02/19) ENTRY時にチェックする対象を、tableId指定のテーブルのカラムに限定します。
		final DBTableModel table = (DBTableModel)getObject( tableId );
		if( table == null ) {
			final String errMsgStr = "検索結果のオブジェクトが存在しません。"
							+ " checkType=[" + checkType + "] , tableId=[" + tableId + "]" ;
			throw new HybsSystemException( errMsgStr );
		}

	 	// 4.1.2.1 (2008/03/13) must , mustAny の自動取得追加
		// table から取出す (ソート済み)
		// 4.3.7.0 (2009/06/01) リアルタイムチェックの場合は、must,mustAnyの自動チェックは行わない
		if( !isRealTime ) {
				if( nullCheck	 == null ) { nullCheck	  = table.getMustArray();	 }
				if( mustAnyCheck == null ) { mustAnyCheck = table.getMustAnyArray(); }
		}

		// 3.8.0.9 (2005/10/17) 選択必須 mustAnyCheck のチェック追加
		boolean[][] rowAnyOne = null;
		// 4.3.6.4 (2009/05/01)
		boolean[] rowForCheck = null;
		if( mustAnyCheck != null && mustAnyCheck.length != 0 ) {
			rowAnyOne   = new boolean[rowNo.length][mustAnyCheck.length];
			rowForCheck = new boolean[rowNo.length];
	//		for( int i=0; i<rowNo.length; i++ ) {
	//			Arrays.fill( rowAnyOne[i],false );
	//		}
		}

		// 6.4.3.2 (2016/02/19) tableId 単位にチェックするが、互換性のため、標準の tableId の処理は、従来どおりとする。
		final boolean useTid = ! HybsSystem.TBL_MDL_KEY.equals( tableId );		// 反転：tableId を使っている＝標準のtableIdではない。

		DBColumn dbColumn = null;	// 5.4.3.4 (2012/01/12) isColumnLabel 対応
		final Enumeration<?> enume = getParameterNames();		// 4.3.3.6 (2008/11/15) Generics警告対応
		while( enume.hasMoreElements() ) {
			final String key  = (String)(enume.nextElement());
			final int    idx  = key.lastIndexOf(HybsSystem.JOINT_STRING);

			if( idx > 0 ) {
				final String column = key.substring(0,idx);
				// 6.4.3.2 (2016/02/19) ENTRY時にチェックする対象を、tableId指定のテーブルのカラムに限定します。
				final int clmNo = table.getColumnNo( column,false );	// エラーを出さない。
				if( useTid && clmNo < 0 ) { continue; }					// 6.4.3.2 (2016/02/19) tableId指定のテーブルのカラムに存在しない場合は、スルーする。

				final int    row    = Integer.parseInt( key.substring(idx + 2) );
				final String val    = getRequestValue( key, false );	// 5.0.0.2 (2009/09/15)

				final int i = Arrays.binarySearch( rowNo,row );
				if( i >= 0 ) {
					// 5.4.3.4 (2012/01/12) isColumnLabel 対応
					// 6.4.3.2 (2016/02/19) tableはnullチェック済みで、clmNoは先に求めている。
					dbColumn = isColumnLabel && clmNo >= 0 ? table.getDBColumn( clmNo ) : getDBColumn( column );

					// 6.8.4.2 (2017/12/25) カラムチェックで、#valueSet(String) で、ｴﾗｰが発生した場合でも、#valueCheck(String) を行うようにします。
					String val2 = val;
					try {
						val2 = dbColumn.valueSet( val );
					}
					catch( RuntimeException ex ) {
						;	// #valueSet(String) で、ｴﾗｰが発生した場合でも、#valueCheck(String) を行うようにします。
					}

					errMsg.append( row+1,dbColumn.valueCheck( val2 ) );

					if( nullCheck != null && nullCheck.length != 0 ) {
						final int j = Arrays.binarySearch( nullCheck,column );	// 6.9.3.1 (2018/04/02) ﾘｸｴｽﾄｶﾗﾑが、nullCheck対象ｶﾗﾑの場合、正のｱﾄﾞﾚｽ
						if( j>=0 && ( val2 == null || val2.isEmpty() )) {
							// ERR0012 : 指定のデータがセットされていません。(NULLエラー)。key={0}
							errMsg.addMessage( row+1,ErrorMessage.NG,"ERR0012",dbColumn.getLabel() );
						}
					}

					// 3.8.0.9 (2005/10/17) 選択必須 mustAnyCheck のチェック追加 (mustAnyCheck="AA|BB|CC,XX|YY|ZZ" という形式を、ｶﾝﾏで分解した配列)
					if( rowAnyOne != null ) {
						// 6.9.3.1 (2018/04/02) データが飛んでこないかどうかの判定
						for( int j=0; j<mustAnyCheck.length; j++ ) {
							if( mustAnyCheck[j].indexOf( column ) >= 0 ) {
								if( val2 == null || val2.isEmpty() ) {
									rowForCheck[i] = true;		// (trueは、処理対象)
								}
								else {
									rowAnyOne[i][j] = true;		// どれかが存在(trueは、処理対象外)
								}
							}

//							if( !rowAnyOne[i][j] &&
//								mustAnyCheck[j].indexOf( column ) >= 0 &&
//								val2 != null && val2.length() > 0 ) {
//									rowAnyOne[i][j] = true;	// どれかが存在(trueは、処理対象外)
//							}
						}
//						// 4.3.6.4 (2009/05/01)
//						rowForCheck[i] = true;		// (trueは、処理対象)
					}

					// 4.0.0 (2005/11/30) 正規表現チェックの追加
					// 6.9.8.0 (2018/05/28) FindBugs:コンストラクタで初期化されていないフィールドを null チェックなしで null 値を利用している
//					if( matchKeys != null && matchKeys.length != 0 ) {
					if( matchKeys != null && matchKeys.length > 0 && matchVals != null && matchVals.length > 0 ) {
						for( int j=0; j<matchKeys.length; j++ ) {
							if( column.equals( matchKeys[j] ) ) {
								if( val2 != null && ! val2.matches( matchVals[j] ) ) {
									// 互換性はなくなっているが、正規表現チェックは余り使っていないので、統一しておく。
									// 5.4.3.4 (2012/01/12) isColumnLabel 対応
									// 6.4.3.2 (2016/02/19) dbColumnは、先に、取得済み。

									// ERR0037 : データ整合性エラー。指定のキーは整合性チェックの結果マッチしませんでした。key={0} val={1} regex={2}
									errMsg.addMessage( row+1,ErrorMessage.NG,"ERR0037",dbColumn.getLabel(),val2,matchVals[i] );
								}
								break;		// 発見すれば、ループ終了
							}
						}
					}
				}
			}
		}

		// 6.4.0.2 (2015/12/11) ResourceManagerの取得を、先に行っておく。
		final ResourceManager resource = getResource();

		// 3.8.0.9 (2005/10/17) 選択必須 mustAnyCheck のチェック追加
		if( rowAnyOne != null ) {
			final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );	// 6.1.0.0 (2014/12/26) refactoring
			for( int row=0; row<rowAnyOne.length; row++ ) {
				// 4.3.6.4 (2009/05/01) 書込み可能行のみを処理する
				if( rowForCheck[row] ) {
					for( int i=0; i<mustAnyCheck.length; i++ ) {
						if( !rowAnyOne[row][i] ) {
							final String[] mustSub = StringUtil.csv2Array( mustAnyCheck[i], '|' );

							buf.setLength(0);											// 6.1.0.0 (2014/12/26) refactoring
							buf.append( "row=[" ).append( rowNo[row]+1 ).append( "] " );
							for( int j=0; j<mustSub.length; j++ ) {
								// ここの処理だけ、他と異なるのは、互換性重視のため。(選択必須は利用頻度が高いので。)
								// 5.4.3.4 (2012/01/12) isColumnLabel 対応
								String label = null ;
								// 6.9.8.0 (2018/05/28) FindBugs:null でないことがわかっている値の冗長な null チェック
//								if( isColumnLabel && table != null ) {
								if( isColumnLabel ) {									// tableは、nullチェック済み
									final int clmNo = table.getColumnNo( mustSub[j],false );	// エラーを出さない。
									if( clmNo >= 0 ) {
										dbColumn = table.getDBColumn( clmNo );
									}
									if( dbColumn == null ) {
										dbColumn = getDBColumn( mustSub[j] );
									}
									label = dbColumn.getLabel();
								}
								else {
									label = resource.getLabel( mustSub[j] );			// 6.4.0.2 (2015/12/11) 互換性のための処置。
								}
								buf.append( label ).append( '|' );		// 6.0.2.5 (2014/10/31) char を append する。
							}
							// ERR0036 : 選択必須エラー。以下のデータの内どれかは入力してください。key={0}
							errMsg.addMessage( rowNo[row]+1, ErrorMessage.NG, "ERR0036", buf.toString() );
						}
					}
				}
			}
		}

		return errMsg;
	}

	/**
	 * ErrorMessageをセットします。
	 * リクエストされた件数の最大値に制限を加えます。
	 * １件だけにしたい場合は，通常はViewでチェックボックスを使用せずに
	 * ラジオボタンを使用してください。
	 *
	 * @param	errMsg	ErrorMessageオブジェクト
	 *
	 * @return	カラムキー ＋ 値 のエラーメッセージオブジェクト
	 */
	private ErrorMessage makeMaxRowCountErrorMessage( final ErrorMessage errMsg ) {
		if( maxRowCount < 0 ) { return errMsg; }	// 無制限

		// 件数制限のチェック
		final int[] rowNo = getParameterRows();
		final int rowCount = rowNo.length ;
		if( rowCount > maxRowCount ) {
			// ERR0017 : 選択エラー。選択行数({0} 件)が、最大制限値({1} 件)以上選ばれました。
			final String arg0 = String.valueOf( rowCount );
			final String arg1 = String.valueOf( maxRowCount );
			errMsg.addMessage( 0,ErrorMessage.NG,"ERR0017",arg0,arg1 );
		}

		return errMsg;
	}

	/**
	 * ErrorMessageをセットします。
	 * リクエストされた件数の最小値に制限を加えます。
	 * １件だけにしたい場合は，通常はViewでチェックボックスを使用せずに
	 * ラジオボタンを使用してください。
	 *
	 * @param	errMsg	ErrorMessageオブジェクト
	 *
	 * @return	カラムキー ＋ 値 のエラーメッセージオブジェクト
	 */
	private ErrorMessage makeMinRowCountErrorMessage( final ErrorMessage errMsg ) {
		if( minRowCount < 0 ) { return errMsg; }	// 無制限

		// 件数制限のチェック
		final int[] rowNo = getParameterRows();
		final int rowCount = rowNo.length ;
		if( rowCount < minRowCount ) {
			// ERR0018 : 選択エラー。選択行数({0} 件)が、最小制限値({1} 件)以下選ばれました。
			final String arg0 = String.valueOf( rowCount );
			final String arg1 = String.valueOf( minRowCount );
			errMsg.addMessage( 0,ErrorMessage.NG,"ERR0018",arg0,arg1 );
		}

		return errMsg;
	}

	/**
	 * 【TAG】チェックすべきカラム列をCSV形式(CSV形式)で指定します。
	 *
	 * @og.tag columns="AAA,BBB,CCC,DDD"
	 * 分解方法は、通常のパラメータ取得後に、CSV分解します。
	 * "*" を指定すると、command="NEW" のときの判定にすべてのリクエスト文字列を
	 * チェック対象とします。通常は、必要分だけ指定しますが、動的カラムなどの
	 * 場合は、カラム名を予め指定できないため、"*" で指定できるようにします。
	 * その場合、"h_" , "hX_" , maxRowCount , command , pageSize , pagePlus , debug ,
	 * GAMENID , BACK_JSPID , BACK_GAMENID の予約語は、対象から除きます。
	 *
	 * ※ 6.4.0.2 (2015/12/11)
	 *    columns="*" のときのカラムは、リクエスト変数から、上記の予約語も除きますが、
	 *    ResourceManager に存在しない(ﾘｿｰｽ未登録)カラムも除きます。
	 *
	 * @og.rev 3.5.6.2 (2004/07/05) 先に配列に分解してからリクエスト変数の値を取得
	 * @og.rev 3.8.8.5 (2007/03/09) 通常のパラメータ取得後に、CSV分解に戻します。
	 * @og.rev 5.4.3.4 (2012/01/12) command="NEW" のときの動的カラム対応( "*" ですべてのリクエスト)
	 * @og.rev 6.4.0.2 (2015/12/11) columns="*" のときのカラムは、ﾘｿｰｽに存在する分のみとする。
	 *
	 * @param   clms カラム列(CSV形式)
	 */
	public void setColumns( final String clms ) {
		columns = StringUtil.csv2Array( getRequestParameter( clms ) );
		if( columns.length == 0 ) { columns = null; }

		// 5.4.3.4 (2012/01/12) command="NEW" のときの動的カラム対応( "*" ですべてのリクエスト)
		if( columns != null && "*".equals( columns[0] ) ) {
			final Set<String> clmSet = new TreeSet<>();		// リクエストはバラバラなので、とりあえずソートしておきます。

			// 6.4.0.2 (2015/12/11) columns="*" のときのカラムは、ﾘｿｰｽに存在する分のみとする。
			final ResourceManager resource = getResource();

			final Enumeration<?> enume = getParameterNames();		// Generics警告対応
			while( enume.hasMoreElements() ) {
				final String clm  = (String)(enume.nextElement());
				// 予約語以外を登録します。
				// 6.9.7.0 (2018/05/14) PMD These nested if statements could be combined
//				if( clm != null && !clm.isEmpty() && !clm.startsWith( "h_" ) && !clm.startsWith( "hX_" ) ) {
//					// 6.4.0.2 (2015/12/11) columns="*" のときのカラムは、ﾘｿｰｽに存在する分のみとする。
//					if( resource.getDBColumn( clm ) != null ) {		// 存在チェックのみで使わない。
				if( clm != null && !clm.isEmpty() && !clm.startsWith( "h_" ) && !clm.startsWith( "hX_" )
					&& resource.getDBColumn( clm ) != null ) {		// 存在チェックのみで使わない。
						clmSet.add( clm );
//					}
				}
			}
			// 予約語を削除します。
			clmSet.remove( "maxRowCount" );
			clmSet.remove( "command" );
			clmSet.remove( "pageSize" );
			clmSet.remove( "pagePlus" );
			clmSet.remove( "debug" );								// 6.4.0.2 (2015/12/11)
			clmSet.remove( "GAMENID" );
			clmSet.remove( "BACK_JSPID" );
			clmSet.remove( "BACK_GAMENID" );

			columns = clmSet.toArray( new String[clmSet.size()] );
		}
	}

	/**
	 * 【TAG】NULL チェックすべきカラム列をCSV形式(CSV形式)で指定します。
	 *
	 * @og.tag
	 * (must 属性のセットにより、自動処理されます)
	 * nullCheck="AAA,BBB,CCC,DDD"
	 * 分解方法は、通常のパラメータ取得後に、CSV分解します。
	 *
	 * @og.rev 3.5.6.2 (2004/07/05) 先に配列に分解してからリクエスト変数の値を取得
	 * @og.rev 3.8.8.5 (2007/03/09) 通常のパラメータ取得後に、CSV分解に戻します。
	 *
	 * @param   clms カラム列(CSV形式)
	 */
	public void setNullCheck( final String clms ) {
		nullCheck = StringUtil.csv2Array( getRequestParameter( clms ) );
		if( nullCheck.length == 0 ) { nullCheck = null; }
		else {
			Arrays.sort( nullCheck );
		}
	}

	/**
	 * 【TAG】選択必須カラム(指定のカラムの内最低ひとつがNULLでない)を"AA|BB|CC,XX|YY|ZZ" 形式で指定します。
	 *
	 * @og.tag
	 * (mustAny 属性のセットにより、自動処理されます)
	 * 複数のカラム属性の値のうち、どれかが null でない場合は正常とし、
	 * すべてが null の場合を警告します。
	 *
	 *  例：mustAnyCheck="AA|BB|CC"
	 *      AA,BB,CC のカラムで選択必須(すべてがnullならエラー)
	 *  例：mustAnyCheck="AA|BB|CC,XX|YY|ZZ"
	 *      AA,BB,CC のセットと、XX,YY,ZZのセットでそれぞれ選択必須。
	 *  例：mustAnyCheck="AA|XX,AA|YY,AA|ZZ"
	 *      AA に値があればすべて成立。そうでない場合は、XX と YY と ZZ がすべて必須。
	 *  例：mustAnyCheck="AA|BB,BB|CC,AA|CC"
	 *      AA,BB,CC の内、どれか２つが必須。AAが成立すればBBかCCが必須。同様に、
	 *      BBが成立すれば、AAかCCが必須。
	 *
	 * 選択必須は、must と同様に、色づけを行う(query.jsp)画面では、mustAny 属性を
	 * セットします。チェックを行う(result.jsp)画面では、columnCheck タグの
	 * mustAnyCheck 属性に、選択必須カラムを指定します。(上記参照)
	 * column タグ等の mustAny 属性に、mustAny="true" とセットすると、生成される
	 * HTMLは、class="mustAny" が出力されます。エンジン標準では、default.css に
	 * .mustAny が定義されています。( background-color: #CCFFFF; )
	 * なお、mustAny 属性に、true 以外の値をセットした場合(mustAny="XYZ")は、
	 * 生成されるHTMLに、class="XYZ" が出力されます。これは、複数のグループ間で
	 * 色を変えて、選択必須を指定する場合に使用します。色は、custom/custom.css
	 * で指定します。
	 * 分解方法は、通常のパラメータ取得後に、CSV分解します。
	 *
	 * @og.rev 3.8.0.9 (2005/10/17) 新規追加
	 * @og.rev 3.8.8.5 (2007/03/09) 通常のパラメータ取得後に、CSV分解に戻します。
	 *
	 * @param   clms 選択必須カラム
	 */
	public void setMustAnyCheck( final String clms ) {
		mustAnyCheck = StringUtil.csv2Array( getRequestParameter( clms ) );
		if( mustAnyCheck.length == 0 ) { mustAnyCheck = null; }
		else {
			Arrays.sort( mustAnyCheck );
		}
	}

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

	/**
	 * 【TAG】 チェック対象のタイプ[AUTO/NEW/ENTRY]を指定します(初期値:AUTO)。
	 *
	 * @og.tag
	 * 通常のリクエストデータタイプは、キーそのものですが,エントリデータは表形式の
	 * データを一括で登録する為、(キー＋"__" ＋ 行番号)形式を、バラす必要があります。
	 *
	 * ENTRY は、DBTableModelのリクエスト情報をチェックします。
	 * これは、全データが対象になります。(columns/nullCheck 属性は無効)
	 * AUTO は、command が、上記 NEW か ENTRY かを判断して処理を振り分けます。
	 * 初期値は、AUTO です。
	 *
	 * @param   flag チェックタイプ [AUTO/NEW/ENTRY]
	 */
	public void setCheckType( final String flag ) {
		final String ct = getRequestParameter( flag );
		if( ct != null && ct.length() > 0 ) { checkType = ct ; }
	}

	/**
	 * 【TAG】チェックで選択された行数の最大値を設定します(初期値:-1 無制限)。
	 *
	 * @og.tag
	 * 制限をかけたい行数(この件数と同じ場合は正常)を指定します。
	 * 最大選択件数を超えた場合は,エラーメッセージを返します。
	 * 例えば、１件のみを正常とする場合は、maxRowCount="1" とします。
	 *
	 * @param   count 最大件数
	 */
	public void setMaxRowCount( final String count ) {
		maxRowCount = nval( getRequestParameter( count ),maxRowCount );
	}

	/**
	 * 【TAG】チェックで選択された行数の最小値を設定します(初期値:-1 無制限)。
	 *
	 * @og.tag
	 * 最小選択件数を超えない場合は、エラーメッセージを返します。
	 * 例えば、１件のみを正常とする場合は、minRowCount="1" とします。
	 *
	 * @param   count 制限をかけたい行数 (この件数と同じ場合は正常)
	 */
	 public void setMinRowCount( final String count ) {
	 	minRowCount = nval( getRequestParameter( count ), minRowCount );
	 }

	/**
	 * 【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}])。
	 *
	 * @og.rev 6.4.3.2 (2016/02/19) ENTRY時にチェックする対象を、tableId指定のテーブルのカラムに限定します。
	 *
	 * @param	id テーブルID (sessionに登録する時のID)
	 */
	public void setTableId( final String id ) {
		tableId = nval( getRequestParameter( id ),tableId );
	}

	/**
	 * 【TAG】正規表現でのマッチングを行うカラム列をCSV形式(CSV形式)で指定します。
	 *
	 * @og.tag matchKeys="AAA,BBB,CCC,DDD"
	 * matchKeys属性とmatchVals属性の個数は、同じでなければなりません。
	 * 先に配列に分解してからリクエスト変数の値を取得するようにします。
	 * こうする事で、リクエストにCSV形式の値を設定できるようになります。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規作成
	 *
	 * @param   keys カラム列(CSV形式)
	 * @see     #setMatchVals( String )
	 */
	public void setMatchKeys( final String keys ) {
		matchKeys = getCSVParameter( keys );

		if( matchVals != null && matchKeys.length != matchVals.length ) {
			final String errMsg = "matchKeys属性とmatchVals属性の個数が合いません。"
						+ CR
						+ " matchKeys=[" + matchKeys.length + "]:KEYS="
						+ StringUtil.array2csv( matchKeys ) + CR
						+ " matchVals=[" + matchVals.length + "]:VLAS="
						+ StringUtil.array2csv( matchVals ) + CR ;
			throw new HybsSystemException( errMsg );
		}
	}

	/**
	 * 【TAG】正規表現でのマッチングを行うカラム列に対する値(正規表現)をCSV形式(CSV形式)で指定します。
	 *
	 * @og.tag matchVals="AAA,BBB,CCC,DDD"
	 * matchKeys属性とmatchVals属性の個数は、同じでなければなりません。
	 * 先に配列に分解してからリクエスト変数の値を取得するようにします。
	 * こうする事で、リクエストにCSV形式の値を設定できるようになります。
	 *
	 * @og.rev 4.0.0.0 (2005/11/30) 新規作成
	 *
	 * @param   vals カラム列に対する値(正規表現)(CSV形式)
	 * @see     #setMatchKeys( String )
	 */
	public void setMatchVals( final String vals ) {
		matchVals = getCSVParameter( vals );

		if( matchKeys != null && matchKeys.length != matchVals.length ) {
			final String errMsg = "matchKeys属性とmatchVals属性の個数が合いません。"
						+ CR
						+ " matchKeys=[" + matchKeys.length + "]:KEYS="
						+ StringUtil.array2csv( matchKeys ) + CR
						+ " matchVals=[" + matchVals.length + "]:VLAS="
						+ StringUtil.array2csv( matchVals ) + CR ;
			throw new HybsSystemException( errMsg );
		}
	}

	/**
	 * 【TAG】(通常は使いません)リアルタイムチェックを行う場合に有効にします(初期値:false)。
	 *
	 * @og.tag
	 * リアルタイムチェックを行う場合に有効にする属性です。
	 * trueが指定された場合、通常のチェックと比較し、以下の差異があります。
	 * ①エラー結果を簡易フォーマットで出力します。
	 *   (ViewFormType="HTMLSimpleErrorList"で表示されます。)
	 *   この簡易フォーマットで出力した場合は、ラベル(短)の定義で出力され、
	 *   カラム名やデータ等は出力されません。
	 * ②must,mustAny属性のチェックを行いません。
	 *   必須及び選択必須は、視覚的に判別できるため、リアルタイムチェックの
	 *   対象外とします。
	 *
	 * @og.rev 4.3.3.0 (2008/10/01) 新規作成
	 * @og.rev 4.3.7.0 (2009/06/01) viewSimple属性名称変更 ⇒ isRealTime
	 *
	 * @param   flag リアルタイムチェック [true:する/false:しない]
	 */
	public void setRealTime( final String flag ) {
		isRealTime = nval( getRequestParameter( flag ),isRealTime );
	}

	/**
	 * 【TAG】NEWの場合に、厳密にチェックするかどうか[true/false]を指定します(初期値:false)。
	 *
	 * @og.tag
	 * データをチェックするに当たり、あいまい検索などで厳密にチェックすると
	 * エラーになるケースがあるため、command="NEW" のチェック時には、甘い目の
	 * チェックを行っています。DBColumn#valueCheck( String , false )
	 * command="ENTRY" のチェックは、厳密なチェックです。
	 * このフラグは、検索時でも、厳密なチェックを行いたい場合に、true をセットします。
	 *
	 * @og.rev 5.2.2.0 (2010/11/01) 新規作成
	 *
	 * @param   flag 厳密チェックか [true:厳密/false:甘い]
	 */
	public void setUseStrict( final String flag ) {
		isStrict = nval( getRequestParameter( flag ),isStrict );
	}

	/**
	 * 【TAG】カラムラベルを使用するかどうか[true/false]を指定します(初期値:false)。
	 *
	 * @og.tag
	 * カラムラベルはラベルローダーを利用せずにアプリケーション側で
	 * 追加したラベルをResourceManagerにキャッシュしている所から取り出す
	 * かどうかを指定します。
	 * カラムラベルに存在しない場合は、通常のラベルから検索します。
	 *
	 * @og.rev 5.4.3.4 (2012/01/12) 新規作成
	 *
	 * @param   flag カラムラベル使用 [true:する/false:しない]
	 */
	public void setUseColumnLabel( final String flag ) {
		isColumnLabel = nval( getRequestParameter( flag ),isColumnLabel );
	}

	/**
	 * 【TAG】リクエスト変数の正規化を行うカラムをCSV形式で複数指定します。
	 *
	 * @og.tag
	 * カラムチェックで正規化が行われていないプラグインに対して強制的に正規化を行います。
	 * この属性を利用したチェックを行った場合は、queryタグでPL/SQLを動作させる場合にも
	 * 同名属性でカラムの指定を行う必要があります。
	 * (queryタグでcheckNamesを利用しない場合はこの属性はnullにしてください)
	 * この属性はチェックタイプがNEWの場合のみ有効です。
	 * リアルタイムチェックでこの機能を利用したい場合は、columnTag等のoptionAttributes
	 * 属性にrtOption='checkNames=VIEW_DATE'のように記述してください。
	 *
	 * @og.rev 5.4.3.8 (2012/01/24) 新規追加
	 * @og.rev 5.4.4.0 (2012/02/01) コメント修正
	 * @og.rev 5.6.9.4 (2013/10/31) 空白削除を行う
	 * @og.rev 6.9.2.1 (2018/03/12) 使用箇所が、１箇所だけなので、StringUtilから移動する。
	 *
	 * @param	nm 正規化を行うカラム(CSV形式)
	 */
	public void setCheckNames( final String nm ) {
//		checkNames = StringUtil.deleteWhitespace( nval( getRequestParameter( nm ),checkNames ) );	// 5.6.9.4 (2013/10/31)
		final String tmpNm = nval( getRequestParameter( nm ),checkNames );
		checkNames = StringUtil.isNull( tmpNm ) ? checkNames :  tmpNm.replaceAll( "\\s", "" );		// 6.9.2.1 (2018/03/12)
	}

	/**
	 * 【TAG】ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)。
	 *
	 * @og.tag
	 * 通常のｴﾗｰﾒｯｾｰｼﾞは、ﾗﾍﾞﾙ（長）が使われますが、これをﾗﾍﾞﾙ（短）を使いたい場合に、true にセットします。
	 * ここでのラベル（短）は、ﾀｸﾞ修飾なしの、ﾗﾍﾞﾙ（短）です。
	 * 標準はfalse:利用しない=ﾗﾍﾞﾙ（長）です。
	 * true/false以外を指定した場合はfalse扱いとします。
	 *
	 * ﾗﾍﾞﾙﾘｿｰｽの概要説明があれば表示しますが、useSLabel="true" 時は、概要説明を表示しません。
	 *
	 * @og.rev 7.0.7.0 (2019/12/13) 新規追加
	 *
	 * @param prm SLABEL利用 [true:利用する/false:利用しない]
	 */
	public void setUseSLabel( final String prm ) {
		useSLabel = nval( getRequestParameter( prm ),useSLabel );
	}

	/**
	 * このオブジェクトの文字列表現を返します。
	 * 基本的にデバッグ目的に使用します。
	 *
	 * @return このクラスの文字列表現
	 * @og.rtnNotNull
	 */
	@Override
	public String toString() {
		return ToString.title( this.getClass().getName() )
				.println( "VERSION"			,VERSION		)
				.println( "tableId"			,tableId		)
				.println( "command"			,command		)
				.println( "columns"			,columns		)
				.println( "nullCheck"		,nullCheck		)
				.println( "mustAnyCheck"	,mustAnyCheck	)
				.println( "maxRowCount"		,maxRowCount	)
				.println( "minRowCount"		,minRowCount	)
				.println( "checkType"		,checkType		)
				.println( "matchKeys"		,matchKeys		)
				.println( "matchVals"		,matchVals		)
				.println( "realTime"		,isRealTime		)
				.println( "bodyString"		,StringUtil.htmlFilter( bodyString ) )
				.println( "Other..."		,getAttributes().getAttribute() )
				.fixForm().toString() ;
	}
}
