/*
 * 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.io.File;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.opengion.fukurou.system.Closer;
import org.opengion.fukurou.util.ArraySet;
import org.opengion.fukurou.util.ErrorMessage;
import org.opengion.fukurou.util.FileUtil;
import org.opengion.fukurou.util.HttpConnect;
import org.opengion.fukurou.util.JSONScan;
import org.opengion.fukurou.util.StringUtil;
import org.opengion.fukurou.util.ToString;
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.DBTableModelUtil;

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

/**
 * IOr (Information Organizer) に接続し、取得したﾃﾞｰﾀﾍﾞｰｽを表示するﾀｸﾞです。
 *
 * IOr へﾃﾞｰﾀ取得を要求して受取った JSON形式 の文字列を、DBTableModel にｾｯﾄします。
 * IOr から取得したﾃﾞｰﾀより loadFile が優先されます。
 *
 * このﾀｸﾞの結果（DBTableModel）は、通常の QueryTag と同様に
 * ViewFormTag で一覧表示や、WriteTableTag でﾌｧｲﾙ出力が可能です。
 *
 * SystemData の USE_SQL_INJECTION_CHECK が true か、quotCheck 属性が true の場合は、
 * SQLｲﾝｼﾞｪｸｼｮﾝ対策用のｼﾝｸﾞﾙｸｫｰﾄﾁｪｯｸを行います。ﾘｸｴｽﾄ引数に
 * ｼﾝｸﾞﾙｸｫｰﾄ(')が含まれると、ｴﾗｰになります。
 * 同様にUSE_XSS_CHECKがtrueか、xssCheck属性がtrueの場合は、
 * ｸﾛｽｻｲﾄｽｽｸﾘﾌﾟﾃｨﾝｸﾞ(XSS)対策のためless/greater than signのﾁｪｯｸを行います。
 *
 * 実行後にﾘｸｴｽﾄﾊﾟﾗﾒｰﾀに以下の値がｾｯﾄされます。
 *   DB.COUNT    : 実行結果の件数
 *   DB.ERR_CODE : 実行結果のｴﾗｰｺｰﾄﾞ
 *   DB.ERR_MSG  : 実行結果のｴﾗｰﾒｯｾｰｼﾞ
 *
 * ※ このﾀｸﾞは、Transaction ﾀｸﾞの対象です。
 *
 * @og.formSample
 * ●形式：
 *     &lt;og:iorQuery
 *         url           = "http://･･･ "    必須
 *         authURL       = "http://･･･ "    必須
 *         authUserPass  = "admin:******"   必須
 *         appliName     = "ﾃﾞｰﾀﾃｰﾌﾞﾙ名"
 *     &gt;
 *     &lt;/og:iorQuery&gt;
 *
 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
 *
 * ●Tag定義：
 *   &lt;og:iorQuery
 *       url              ○【TAG】ｱｸｾｽする URL を指定します (必須)
 *       proxyHost          【TAG】ﾌﾟﾛｷｼ経由で接続する場合の、ﾌﾟﾛｷｼﾎｽﾄ名を指定します
 *       proxyPort          【TAG】ﾌﾟﾛｷｼ経由で接続する場合の、ﾌﾟﾛｷｼﾎﾟｰﾄ番号を指定します
 *       timeout            【TAG】通信ﾘﾝｸのｵｰﾌﾟﾝ時に、指定された秒単位のﾀｲﾑ･ｱｳﾄ値を使用します
 *                                  (初期値:URL_CONNECT_TIMEOUT[={@og.value SystemData#URL_CONNECT_TIMEOUT}])
 *       authURL          ○【TAG】JSONｺｰﾄﾞで認証するURLを指定します (必須)
 *       authUserPass     ○【TAG】Basic認証を使用して接続する場合のﾕｰｻﾞｰ:ﾊﾟｽﾜｰﾄﾞを指定します (必須)
 *       companyId          【TAG】企業IDを指定します
 *       appliName        ○【TAG】ｱﾌﾟﾘｹｰｼｮﾝの名前を指定します
 *       display            【TAG】接続の結果を表示するかどうかを指定します (初期値:false)
 *       saveFile           【TAG】接続の結果をﾌｧｲﾙに保存します
 *       loadFile           【TAG】ﾌｧｲﾙからURL接続結果に相当するﾃﾞｰﾀを読み取ります
 *       command            【TAG】ｺﾏﾝﾄﾞ(NEW,RENEW)をｾｯﾄします
 *       scope              【TAG】ｷｬｯｼｭする場合のｽｺｰﾌﾟ[request/page/session/application]を指定します (初期値:session)
 *       displayMsg         【TAG】検索結果を画面上に表示するﾒｯｾｰｼﾞﾘｿｰｽIDを指定します (初期値:VIEW_DISPLAY_MSG[=])
 *       notfoundMsg        【TAG】検索結果がｾﾞﾛ件の場合に表示するﾒｯｾｰｼﾞﾘｿｰｽIDを指定します
 *                                  (初期値:MSG0077[対象ﾃﾞｰﾀはありませんでした])
 *       stopZero           【TAG】検索結果が０件のとき処理を続行するかどうか[true/false]を指定します (初期値:false[続行する])
 *       tableId            【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのｷｰを指定します
 *       stopError          【TAG】処理ｴﾗｰの時に処理を中止するかどうか[true/false]を設定します (初期値:true)
 *       dispError          【TAG】ｴﾗｰ時にﾒｯｾｰｼﾞを表示するか[true/false]を設定します。通常はstopErrorと併用 (初期値:true)
 *       quotCheck          【TAG】ﾘｸｴｽﾄ情報の ｼﾝｸﾞﾙｸｫｰﾄ(') 存在ﾁｪｯｸを実施するかどうか[true/false]を設定します
 *                                  (初期値:USE_SQL_INJECTION_CHECK)
 *       xssCheck           【TAG】ﾘｸｴｽﾄ情報の HTMLTag開始/終了文字(&gt;&lt;) 存在ﾁｪｯｸを実施するかどうか[true/false]を設定します
 *                                  (初期値:USE_XSS_CHECK[=true])
 *       mainTrans          【TAG】(通常は使いません)ﾀｸﾞで処理される処理がﾒｲﾝとなるﾄﾗﾝｻﾞｸｼｮﾝ処理かどうかを指定します (初期値:false)
 *       useBeforeHtmlTag   【TAG】処理時間(queryTime)などの情報出力[true:有効/false:無効]を指定します (初期値:true)
 *       useTimeView        【TAG】処理時間を表示する TimeView を表示するかどうかを指定します
 *                                  (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])
 *       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:iorQuery&gt;
 *
 * ●使用例
 *     &lt;og:iorQuery
 *         url           = "http://･･･ "
 *         authURL       = "http://･･･ "
 *         authUserPass  = "admin:******"
 *         appliName     = "ﾃﾞｰﾀﾃｰﾌﾞﾙ名"
 *     &gt;
 *         &lt;og:iorParam
 *             key  = "where_lk"  value  = "{'PN':'{&#064;PN}%','TANI':'{&#064;TANI}'}"  /&gt;
 *     &lt;/og:iorQuery&gt;
 *
 * @og.rev 8.0.2.0 (2021/11/30) 新規作成
 * @og.group その他部品
 *
 * @version  8.0
 * @author   LEE.M
 * @since    JDK17.0,
 */
public class IorQueryTag extends CommonTagSupport {
	/** このﾌﾟﾛｸﾞﾗﾑのVERSION文字列を設定します。 {@value} */
	private static final String VERSION = "8.0.2.0 (2021/11/30)" ;
	private static final long serialVersionUID = 802020211130L ;

	/** command 引数に渡す事の出来る ｺﾏﾝﾄﾞ  新規 {@value} */
	public static final String CMD_NEW		= "NEW";											// ｺﾏﾝﾄﾞ(新規)
	/** command 引数に渡す事の出来る ｺﾏﾝﾄﾞ  再検索 {@value} */
	public static final String CMD_RENEW	= "RENEW";											// ｺﾏﾝﾄﾞ(再検索)
	// String配列 から、Setに置き換えます。
	private static final Set<String> COMMAND_SET = new ArraySet<>( CMD_NEW, CMD_RENEW );		// ｺﾏﾝﾄﾞ(Set)

	/** ｴﾗｰﾒｯｾｰｼﾞID */
	protected static final String ERR_MSG_ID	= HybsSystem.ERR_MSG_KEY;

	// IOr 応答結果のｷｰ
	private   static final String IOR_HTTP_STTS	= "status";										// ｽﾃｰﾀｽ
	private   static final String IOR_HTTP_MSG	= "message";									// ｴﾗｰﾒｯｾｰｼﾞ
	/** ﾍｯﾀﾞ配列のﾗﾍﾞﾙ */
	protected static final String IOR_DISP_LBL	= "display_label";								// ﾍｯﾀﾞ配列のﾗﾍﾞﾙ
	/** ﾍｯﾀﾞ配列のｷｰ */
	protected static final String IOR_DISP_KEY	= "display";									// ﾍｯﾀﾞ配列のｷｰ
	private   static final String IOR_SQL_CNT	= "count";										// 実行件数

	// JSONによるﾌｪｰｽﾞ認証ﾌｫｰﾏｯﾄ
	private static final String AUTH_JSON_FMT	= "{\"userInfo\":{\"companyId\":\"%s\",\"userId\":\"%s\",\"password\":\"%s\"}}";

	/** JSONｺｰﾄﾞ */
	protected final Map<String,String> mapParam = new LinkedHashMap<>();
	/** ﾃｰﾌﾞﾙﾓﾃﾞﾙ */
	protected transient DBTableModel table;

	/** 接続するURL */
	private   String	urlStr				;
	/** ﾌﾟﾛｷｼﾎｽﾄ名 */
	private   String	proxyHost			= HybsSystem.sys( "HTTP_PROXY_HOST" );
	/** ﾌﾟﾛｷｼﾎﾟｰﾄ番号 */
	private   int		proxyPort			= HybsSystem.sysInt( "HTTP_PROXY_PORT" );
	/** 接続ﾀｲﾑｱｳﾄ時間 */
	private   int		timeout				= HybsSystem.sysInt( "URL_CONNECT_TIMEOUT" );
	/** JSONｺｰﾄﾞで認証するURL */
	private   String	authURL				;
	/** ﾕｰｻﾞｰ:ﾊﾟｽﾜｰﾄﾞ */
	private   String	authUserPass		;
	/** 企業ID */
	private   String	companyId			= HybsSystem.sys( "IOR_COMPANYID" );
	/** ｱﾌﾟﾘ名 */
	private   String	appliName			;
	/** 結果の表示可否 */
	private   boolean	display				;
	/** 保存ﾌｧｲﾙ */
	private   String	saveFile			;
	/** 読取ﾌｧｲﾙ */
	protected String	loadFile			;
	/** ｺﾏﾝﾄﾞ */
	private   String	command				= CMD_NEW;
	/** ﾃﾞｨｽﾌﾟﾚｲﾒｯｾｰｼﾞ */
	private   String	displayMsg			= HybsSystem.sys( "VIEW_DISPLAY_MSG" );
	/** 対象ﾃﾞｰﾀはありませんでした。 */
	private   String	notfoundMsg			= "MSG0077";
	/** 処理の停止可否 */
	private   boolean	stopZero			;
	/** ﾃｰﾌﾞﾙﾓﾃﾞﾙID */
	protected String	tableId				= HybsSystem.TBL_MDL_KEY;
	/** ｴﾗｰ時の処理中止可否 */
	protected boolean	stopError			= true;
	/** 画面上のｴﾗｰ出力可否 */
	private   boolean	dispError			= true;
	/** ｸｵｰﾄﾁｪｯｸ */
	protected boolean	quotCheck			= HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );
	/** XSSﾁｪｯｸ */
	private   boolean	xssCheck			= HybsSystem.sysBool( "USE_XSS_CHECK" );
	/** 処理時間(queryTime)などの情報出力の可否 */
	private   boolean	useBeforeHtmlTag	= true;
	/** ﾀｲﾑﾊﾞｰの使用可否 */
	protected boolean	useTimeView			= HybsSystem.sysBool( "VIEW_USE_TIMEBAR" );

	/** ﾕｰｻﾞｰ */
	private   String	user				;
	/** ﾊﾟｽﾜｰﾄﾞ */
	private   String	pass				;
	/** BODY部 */
	protected String	postData			;
	/** 取得ﾃﾞｰﾀ */
	protected String	rtnData				;
	/** 実行件数 */
	protected int		executeCount		;
	/** 現在時刻 */
	protected long		dyStart				;
	/** DBLastSqlの処理見直し */
	private   boolean	isMainTrans			= true;
	/** ﾌｧｲﾙURL */
	private   String	fileURL				= HybsSystem.sys( "FILE_URL" );

	/**
	 * ﾃﾞﾌｫﾙﾄｺﾝｽﾄﾗｸﾀｰ
	 *
	 */
	public IorQueryTag() { super(); }	// これも、自動的に呼ばれるが、空のﾒｿｯﾄﾞを作成すると警告されるので、明示的にしておきます。

	/**
	 * Taglibの開始ﾀｸﾞが見つかったときに処理する doStartTag() を ｵｰﾊﾞｰﾗｲﾄﾞします。
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doStartTag() {
		if( !useTag() ) { return SKIP_BODY ; }

		useXssCheck( xssCheck );
		dyStart = System.currentTimeMillis();									// 現在時刻

		if( ! check( command, COMMAND_SET ) ) {
			table = (DBTableModel)getObject( tableId );
			if( table == null )	{ executeCount = 0; }
			else				{ executeCount = table.getRowCount(); }
			return SKIP_BODY;
		}

		useMainTrans( isMainTrans );
		startQueryTransaction( tableId );

		// scope="session" の場合のみ、削除します。
		if( "session".equals( getScope() ) ) {
			removeSessionAttribute( tableId );
			removeSessionAttribute( HybsSystem.VIEWFORM_KEY );
		}

		// ﾕｰｻﾞｰ:ﾊﾟｽﾜｰﾄﾞ から ﾕｰｻﾞｰとﾊﾟｽﾜｰﾄﾞを取得します。
		checkUsrPw();

		// 読取ﾌｧｲﾙ指定無し
		if( loadFile == null ) {
			// JSON形式の共通要求ｷｰを設定します。
			setComJson();
		}
		return EVAL_BODY_BUFFERED;												// Body を評価する (extends BodyTagSupport 時)
	}

	/**
	 * Taglibのﾀｸﾞ本体を処理する doAfterBody() を ｵｰﾊﾞｰﾗｲﾄﾞします。
	 *
	 * @return	後続処理の指示(SKIP_BODY)
	 */
	@Override
	public int doAfterBody() {
		// useQuotCheck() によるSQLｲﾝｼﾞｪｸｼｮﾝ対策
		useQuotCheck( quotCheck );

		postData = getBodyString();

		return SKIP_BODY;
	}

	/**
	 * Taglibの終了ﾀｸﾞが見つかったときに処理する doEndTag() を ｵｰﾊﾞｰﾗｲﾄﾞします。
	 *
	 * @return	後続処理の指示
	 */
	@Override
	public int doEndTag() {
		debugPrint();
		if( !useTag() ) { return EVAL_PAGE; }

		int errCode = ErrorMessage.OK;											// ｴﾗｰｺｰﾄﾞ
		if( check( command, COMMAND_SET ) ) {
			// URLに対して応答結果を取得します。
			rtnData = outJson();

			// IOr の応答結果を特定のｷｰﾜｰﾄﾞで分割します。
			final SplitReqJson splitJson = new SplitReqJson( rtnData );

			// 応答結果の HTTPｽﾃｰﾀｽｺｰﾄﾞ を設定します。
			final String rtnStts = splitJson.getSttsJson();
			errCode = getStatus( rtnStts );

			if( errCode == ErrorMessage.OK ) {
				// 応答結果の 実行件数 を取得します。
				final String rtnCnt = splitJson.getCntJson();
				executeCount = getCount( rtnCnt );
				if( ! stopZero ) {
					// ﾃｰﾌﾞﾙﾓﾃﾞﾙ作成します。
					table = makeDBTable( splitJson );
					// 処理後のﾒｯｾｰｼﾞを作成します。
					errCode = makeMessage();
				}
			}
		}

		final int rtnCode;
		// 異常
		if( errCode >= ErrorMessage.NG ) {
			rtnCode = stopError ? SKIP_PAGE : EVAL_PAGE ;
		}
		// 正常／警告
		else {
			// 実行件数 = ｾﾞﾛ 且つ stopZero = true
			rtnCode = executeCount == 0 && stopZero ? SKIP_PAGE : EVAL_PAGE ;
		}

		// 処理時間(queryTime)などの情報出力の有効/無効を指定します。
		if( useTimeView && useBeforeHtmlTag ) {
			final long dyTime = System.currentTimeMillis() - dyStart;
			jspPrint( "<div id=\"queryTime\" value=\"" + (dyTime) + "\"></div>" );
		}
		return rtnCode;
	}

	/**
	 * ﾀｸﾞﾘﾌﾞｵﾌﾞｼﾞｪｸﾄをﾘﾘｰｽします。
	 * ｷｬｯｼｭされて再利用されるので、ﾌｨｰﾙﾄﾞの初期設定を行います。
	 */
	@Override
	protected void release2() {
		super.release2();
		mapParam.clear();														// JSONｺｰﾄﾞのｸﾘｱ
		table				= null;												// ﾃｰﾌﾞﾙﾓﾃﾞﾙ
		urlStr				= null;												// 接続するURL
		proxyHost			= HybsSystem.sys( "HTTP_PROXY_HOST" );				// ﾌﾟﾛｷｼﾎｽﾄ名
		proxyPort			= HybsSystem.sysInt( "HTTP_PROXY_PORT" );			// ﾌﾟﾛｷｼﾎﾟｰﾄ番号
		timeout				= HybsSystem.sysInt( "URL_CONNECT_TIMEOUT" );		// 接続ﾀｲﾑｱｳﾄ時間
		authURL				= null;												// JSONｺｰﾄﾞで認証するURL
		authUserPass		= null;												// ﾕｰｻﾞｰ:ﾊﾟｽﾜｰﾄﾞ
		companyId			= HybsSystem.sys( "IOR_COMPANYID" );				// 企業ID
		appliName			= null;												// ｱﾌﾟﾘ名
		display				= false;											// 結果の表示可否
		saveFile			= null;												// 保存ﾌｧｲﾙ
		loadFile			= null;												// 読取ﾌｧｲﾙ
		command				= CMD_NEW;											// ｺﾏﾝﾄﾞ
		displayMsg			= HybsSystem.sys( "VIEW_DISPLAY_MSG" );				// ﾃﾞｨｽﾌﾟﾚｲﾒｯｾｰｼﾞ
		notfoundMsg			= "MSG0077";										// 対象ﾃﾞｰﾀはありませんでした。
		stopZero			= false;											// 処理の停止可否
		tableId				= HybsSystem.TBL_MDL_KEY;							// ﾃｰﾌﾞﾙﾓﾃﾞﾙ
		stopError			= true;												// ｴﾗｰ時の処理中止可否
		dispError			= true;												// 画面上のｴﾗｰ出力可否
		quotCheck			= HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );	// ｸｵｰﾄﾁｪｯｸ
		xssCheck			= HybsSystem.sysBool( "USE_XSS_CHECK" );			// XSSﾁｪｯｸ
		useBeforeHtmlTag	= true;												// 処理時間(queryTime)などの情報出力の可否
		useTimeView			= HybsSystem.sysBool( "VIEW_USE_TIMEBAR" );			// ﾀｲﾑﾊﾞｰの使用可否

		user				= null;												// ﾕｰｻﾞｰ
		pass				= null;												// ﾊﾟｽﾜｰﾄﾞ
		postData			= null;												// BODY部
		rtnData				= null;												// 取得ﾃﾞｰﾀ
		executeCount		= 0;												// 実行件数
		dyStart				= 0;												// 現在時刻
		isMainTrans			= true;												// DBLastSqlの処理見直し
		fileURL				= HybsSystem.sys( "FILE_URL" );						// ﾌｧｲﾙURL
	}

	/**
	 * IorQuery ｵﾌﾞｼﾞｪｸﾄに渡すﾊﾟﾗﾒｰﾀをﾏｯﾋﾟﾝｸﾞします。
	 *
	 * IorParamTag ｸﾗｽよりｾｯﾄされます。
	 * 但し、以下のｷｰに対して IorParamTag では指定できません。
	 * company_id、user_id、session_id、report_name、method
	 *
	 * @param	key	ﾊﾟﾗﾒｰﾀｷｰ
	 * @param	val	ﾊﾟﾗﾒｰﾀ値
	 */
	protected void addParam( final String key, final String val ) {
		if( mapParam.containsKey( key ) ){
			final String errMsg = key + "のｷｰが重複しています。";
			throw new HybsSystemException( errMsg );
		}
		else {
			mapParam.put( key, val );
		}
	}

	/**
	 * ﾕｰｻﾞｰ:ﾊﾟｽﾜｰﾄﾞ から ﾕｰｻﾞｰとﾊﾟｽﾜｰﾄﾞを分割します。
	 */
	protected void checkUsrPw() {
		if( authUserPass.contains(":") ) {
			// ﾕｰｻﾞｰ:ﾊﾟｽﾜｰﾄﾞを分割します。
			final String[] prm = StringUtil.csv2Array( authUserPass, ':' ,2 );
			user = prm[0];														// ﾕｰｻﾞｰ
			pass = prm[1];														// ﾊﾟｽﾜｰﾄﾞ
		}
		else {
			final String errMsg = "ﾕｰｻﾞｰ:ﾊﾟｽﾜｰﾄﾞ の形式で記述してください。";
			throw new HybsSystemException( errMsg );
		}
	}

	/**
	 * JSON形式の共通要求ｷｰを設定します。
	 * ･company_id   : 企業ID
	 * ･user_id      : ﾕｰｻﾞｰID
	 * ･session_id   : ｾｯｼｮﾝID
	 * ･report_name  : ｱﾌﾟﾘ名
	 * ･method       : 登録条件
	 * 例：{"company_id":"XXXXX","user_id":"admin","session_id":"$session_id$" …}
	 */
	protected void setComJson() {
		// 企業ID
		if( companyId != null ) { mapParam.put( "company_id", companyId ); }
		// ﾕｰｻﾞｰID
		if( !user.isEmpty() ) { mapParam.put( "user_id", user ); }
		// ｾｯｼｮﾝID
		mapParam.put( "session_id", "$session_id$" );
		// ｱﾌﾟﾘ名
		if( appliName != null ) { mapParam.put( "report_name", appliName ); }
	}

	/**
	 * loadFile 指定がある場合は、ﾌｧｲﾙからﾃﾞｰﾀを読取ります。
	 * loadFile 指定がない場合は、URLに対して応答結果を取得します。
	 *
	 * @return	JSON形式の文字列
	 * @og.rtnNotNull
	 */
	protected String outJson() {
		final String str;

		// 読取ﾌｧｲﾙ指定無し
		if( loadFile == null ) {
			if( postData == null || postData.isEmpty() ){
				postData = JSONScan.map2Json( mapParam );
			}
			// URLに対して応答結果を取得します。
			str = retResponse();
		}
		// 読取ﾌｧｲﾙ指定有り
		else {
			final StringBuilder buf = new StringBuilder(BUFFER_MIDDLE);
			try {
				for (final String text : Files.readAllLines( Paths.get(loadFile), StandardCharsets.UTF_8 )) {
					buf.append( text )
						.append( CR );
				}
				str = buf.toString();
			}
			catch( final IOException ex ) {
				final String errMsg = "loadFile 処理中でｴﾗｰが発生しました。"	+ CR
							+ "\t " + ex.getMessage()							+ CR ;
				throw new HybsSystemException( errMsg, ex );
			}
		}
		return str;
	}

	/**
	 * URLに対して応答結果を取得します。
	 *
	 * @return	URL接続先のﾃﾞｰﾀ
	 * @og.rtnNotNull
	 */
	protected String retResponse() {
		HttpConnect conn = null;
		Writer outWriter = null;
		String getData = null;
		try {
			conn = connect();

			// URL接続先のﾃﾞｰﾀを取得します。
			getData = conn.readData();
			// 実行結果のｽﾃｰﾀｽｺｰﾄﾞが'200'(正常)ではないとき、例外を発生させます。
			if( conn.getCode() != 200 ) { throw new Throwable(); }

			if( display ) {
				outWriter = FileUtil.getNonFlushPrintWriter( pageContext.getOut() ) ;	// JspWriter の取得
			}
			else if( saveFile != null ) {
				outWriter = FileUtil.getPrintWriter( new File( saveFile ), "UTF-8" );
			}

			// Unicode文字列から元の文字列に変換します。
			getData = StringUtil.convertToOiginal( getData );

			// 出力先が存在する場合
			if( outWriter != null ) {
				outWriter.write( getData );
			}
		}
		catch( final Throwable th ) {
			final String errMsg = "ﾃﾞｰﾀ処理中にｴﾗｰが発生しました。"	+ CR
						+ " url=[" + urlStr + "]"							+ CR
						+ " message=[" + ( conn == null ? "NO_CONNECTION" : conn.getMessage() ) + "]" + CR
						+ " Exception=[" + th.getMessage() + "]" ;
			throw new HybsSystemException( errMsg, th );
		}
		finally {
			Closer.ioClose( outWriter );
		}
		return getData;
	}

	/**
	 * URLに対して接続を行います。
	 *
	 * @return	接続ｵﾌﾞｼﾞｪｸﾄ
	 * @og.rtnNotNull
	 * @throws	IOException	入出力ｴﾗｰが発生したとき
	 */
	protected HttpConnect connect() throws IOException {
		// HttpConnect は、後付で引数を渡せます。
		final HttpConnect conn = new HttpConnect( urlStr, authUserPass );
		conn.setDebug( isDebug() );
		conn.usePost( true );

		// ﾌﾟﾛｷｼ
		if( proxyHost != null ) {
			conn.setProxy( proxyHost,proxyPort );
		}
		// JSONによるﾌｪｰｽﾞ認証
		if( authUserPass != null && authURL != null ) {
			final String authJson = String.format( AUTH_JSON_FMT, companyId, user, pass ) ;
			conn.setAuthJson( authJson , authURL );
		}
		// 接続ﾀｲﾑｱｳﾄ時間
		if( timeout >= 0 ) {
			conn.setTimeout( timeout );
		}
		// JSONｺｰﾄﾞでﾘｸｴｽﾄするﾊﾟﾗﾒｰﾀを指定
		if( postData != null ) {
			conn.setReqJson( postData );
		}
		return conn;
	}

	/**
	 * IOr の要求結果から、HTTPｽﾃｰﾀｽｺｰﾄﾞ を設定します。
	 *
	 * @param	strJson	Json形式の文字列
	 * @return	ｴﾗｰｺｰﾄﾞ
	 * @og.rtnNotNull
	 */
	protected int getStatus( final String strJson ) {
		int errCode = ErrorMessage.OK;											// ｴﾗｰｺｰﾄﾞ
		final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );			// ﾊﾞｯﾌｧ

		// ---------------------------------------------------------------------
		// HTTPｽﾃｰﾀｽｺｰﾄﾞ (先頭から"data"までの文字列)
		// 例：{"status": 200, "message": "OK", "sessionInfo": "51b16"
		// ---------------------------------------------------------------------
		// ｷｰと値をﾏｯﾋﾟﾝｸﾞします。
		final Map<String,String> mapStts = JSONScan.json2Map( strJson );
		final String stts = mapStts.get( IOR_HTTP_STTS );						// ｽﾃｰﾀｽ

		// ｽﾃｰﾀｽが'200'(正常)である
		if( stts.equals( String.valueOf( 200 ) ) ) {
			errCode = ErrorMessage.OK;											// 正常
		}
		// ｽﾃｰﾀｽが'200'(正常)ではない
		else {
			errCode = ErrorMessage.NG;												// ｴﾗｰｺｰﾄﾞ
			final String msg = mapStts.get( IOR_HTTP_MSG );								// ｴﾗｰﾒｯｾｰｼﾞ

			final ErrorMessage errMessage = new ErrorMessage( "iorQueryTag Error!" );
			errMessage.addMessage( 0, errCode, stts, msg );

			// TaglibUtil.makeHTMLErrorTable ﾒｿｯﾄﾞを利用します。
			final String err = TaglibUtil.makeHTMLErrorTable( errMessage, getResource() );
			if( err != null && err.length() > 0 ) {
				buf.append( err );
				setSessionAttribute( ERR_MSG_ID, errMessage );
			}
			// 以前処理のｴﾗｰﾒｯｾｰｼﾞを削除します。
			else if( CMD_NEW.equals( command ) ) {
				removeSessionAttribute( ERR_MSG_ID );
			}
		}

		final String label = buf.toString();
		// dispErrorで表示をｺﾝﾄﾛｰﾙ
		if( dispError ) { jspPrint( label ); }

		// 検索結果を、"DB.ERR_CODE" ｷｰでﾘｸｴｽﾄにｾｯﾄします。
		setRequestAttribute( "DB.ERR_CODE", String.valueOf( errCode ) );
		// ｴﾗｰﾒｯｾｰｼﾞを、"DB.ERR_MSG" ｷｰでﾘｸｴｽﾄにｾｯﾄします。
		setRequestAttribute( "DB.ERR_MSG", label );

		return errCode;
	}

	/**
	 * IOr の要求結果から、実行件数 を取得します。
	 *
	 * @param	strJson	Json形式の文字列
	 * @return	実行件数
	 * @og.rtnNotNull
	 */
	protected int getCount( final String strJson ) {
		final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );			// ﾊﾞｯﾌｧ

		// ---------------------------------------------------------------------
		// 件数 ("count"からの文字列)
		// 例："count": 10
		// ---------------------------------------------------------------------
		// ｷｰと値をﾏｯﾋﾟﾝｸﾞします。
		final Map<String,String> mapCnt = JSONScan.json2Map( strJson );
		final int count = nval( mapCnt.get( IOR_SQL_CNT ), -1 );				// 実行件数

		// 実行件数の表示 command="NEW" のときのみ、displayMsg を表示させます。
		if( CMD_NEW.equals( command ) ) {
			if( count > 0 && displayMsg != null && displayMsg.length() > 0 ) {
				buf.append( count )
					.append( getResource().getLabel( displayMsg ) )
					.append( BR );
			}
			else if( count == 0 && notfoundMsg != null && notfoundMsg.length() > 0 ) {
					buf.append( getResource().getLabel( notfoundMsg ) )
						.append( BR );
			}
		}

		final String label = buf.toString();
		// dispErrorで表示をｺﾝﾄﾛｰﾙ
		if( dispError ) { jspPrint( label ); }

		// 検索結果の件数を、"DB.COUNT" ｷｰでﾘｸｴｽﾄにｾｯﾄします。
		setRequestAttribute( "DB.COUNT" , String.valueOf( count ) );

		return count;
	}

	/**
	 * IOr の 要求結果から、値を取り出し、DBTableModel を作成します。
	 *
	 * @param	strJson	Json形式の文字列
	 * @return	ﾃｰﾌﾞﾙﾓﾃﾞﾙ
	 * @og.rtnNotNull
	 */
	private DBTableModel makeDBTable( final SplitReqJson strJson ) {
		final DBTableModel table = DBTableModelUtil.newDBTable();

		// ---------------------------------------------------------------------
		// ﾃｰﾌﾞﾙﾓﾃﾞﾙの列 ("headers"から"rows"までの文字列)
		// 例："headers": [{"display_label": "品目番号", "display": "PN"}, … ]
		// ---------------------------------------------------------------------
		final String rtnClm = strJson.getClmJson();

		// 中括弧({})で分割
		final JSONScan scanClm = new JSONScan( rtnClm, '{', '}' );
		final int cntClm = scanClm.countBlock();
		table.init( cntClm );
		int i = 0;

		while( scanClm.hasNext() ) {
			final String clms = scanClm.next();

			// ｷｰと値をﾏｯﾋﾟﾝｸﾞします。
			final Map<String,String> mapClm = JSONScan.json2Map( clms );
			final String clmLbl = mapClm.get( IOR_DISP_LBL );					// ﾗﾍﾞﾙ(例：品目番号)
			final String clmKey = mapClm.get( IOR_DISP_KEY );					// ｷｰ(例：PN)

			// ﾃｰﾌﾞﾙﾓﾃﾞﾙに列を追加します。
			final DBColumn dbColumn = getResource().makeDBColumn( clmKey, clmLbl );
			table.setDBColumn( i++, dbColumn );
		}

		if( executeCount > 0 ){
			// ---------------------------------------------------------------------
			// ﾃｰﾌﾞﾙﾓﾃﾞﾙの行 ("cols"から最後の文字列)
			// 例："rows": [{"cols": [1, "GEN", "20211130", 32.4, "kg"]}, … ]}}
			// ---------------------------------------------------------------------
			final String rtnRow = strJson.getRowJson();

			// 大括弧([])で分割
			final JSONScan scanRow = new JSONScan( rtnRow, '[', ']' );
			while( scanRow.hasNext() ) {
				final String rows = scanRow.next();
				final String[] vals = JSONScan.json2Array( rows );
				// ﾃｰﾌﾞﾙﾓﾃﾞﾙに行の値を追加します。
				table.addColumnValues( vals );
			}
		}
		return table;
	}

	/**
	 * 処理後のﾒｯｾｰｼﾞを作成します。
	 *
	 * @return	ｴﾗｰｺｰﾄﾞ
	 * @og.rtnNotNull
	 */
	protected int makeMessage() {
		int errCode = ErrorMessage.OK;												// ｴﾗｰｺｰﾄﾞ
		final ErrorMessage errMessage = new ErrorMessage( "iorQueryTag Error!" );	// ｴﾗｰﾒｯｾｰｼﾞ
		final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );				// ﾊﾞｯﾌｧ

		// ｢ERR0041:検索処理中に割り込みの検索要求がありました｣ｴﾗｰを、標準のErrorMessageに追加するようにします。
		if( table != null && ! commitTableObject( tableId, table ) ) {
			// ERR0041:検索処理中に割り込みの検索要求がありました。処理されません。
			errCode = ErrorMessage.NG;
			errMessage.addMessage( 0, errCode, "ERR0041" );
		}

		// TaglibUtil.makeHTMLErrorTable ﾒｿｯﾄﾞを利用します。
		final String err = TaglibUtil.makeHTMLErrorTable( errMessage, getResource() );
		if( err != null && err.length() > 0 ) {
			buf.append( err );
			setSessionAttribute( ERR_MSG_ID, errMessage );
		}
		else if( CMD_NEW.equals( command ) ) {
			removeSessionAttribute( ERR_MSG_ID );
		}
		final String label = buf.toString();
		// dispErrorで表示をｺﾝﾄﾛｰﾙ
		if( dispError ) { jspPrint( label ); }

		// 検索結果を、"DB.ERR_CODE" ｷｰでﾘｸｴｽﾄにｾｯﾄします。
		setRequestAttribute( "DB.ERR_CODE", String.valueOf( errCode ) );
		// ｴﾗｰﾒｯｾｰｼﾞを、"DB.ERR_MSG" ｷｰでﾘｸｴｽﾄにｾｯﾄします。
		setRequestAttribute( "DB.ERR_MSG", label );

		return errCode;
	}

	/**
	 * 【TAG】ｱｸｾｽする接続先URLを指定します。
	 *
	 * @og.tag
	 * 接続するURLを指定します。(例：http:// ･･････)
	 *
	 * @param	url	接続先
	 */
	public void setUrl( final String url ) {
		urlStr = nval( getRequestParameter( url ),urlStr );
	}

	/**
	 * 【TAG】ﾌﾟﾛｷｼ経由で接続する場合の、ﾌﾟﾛｷｼﾎｽﾄ名を指定します。
	 *
	 * @og.tag
	 * 接続先が、ﾌﾟﾛｷｼ経由の場合、ﾌﾟﾛｷｼのﾎｽﾄ名を指定します。
	 * 例：proxy.opengion.org
	 *
	 * @param	host	ﾌﾟﾛｷｼﾎｽﾄ名
	 */
	public void setProxyHost( final String host ) {
		proxyHost = nval( getRequestParameter( host ),proxyHost );
	}

	/**
	 * 【TAG】ﾌﾟﾛｷｼ経由で接続する場合の、ﾌﾟﾛｷｼﾎﾟｰﾄ番号を指定します。
	 *
	 * @og.tag
	 * 接続先が、ﾌﾟﾛｷｼ経由の場合、ﾌﾟﾛｷｼのﾎﾟｰﾄ番号を指定します。
	 * 例：8080
	 *
	 * @param	port	ﾌﾟﾛｷｼﾎﾟｰﾄ番号
	 */
	public void setProxyPort( final String port ) {
		proxyPort = nval( getRequestParameter( port ),proxyPort );
	}

	/**
	 * 【TAG】接続ﾀｲﾑｱｳﾄ時間を(秒)で指定します
	 *        (初期値:URL_CONNECT_TIMEOUT[={@og.value SystemData#URL_CONNECT_TIMEOUT}])。
	 *
	 * @og.tag
	 * 実際には、java.net.URLConnection#setConnectTimeout(int) に 1000倍して設定されます。
	 * 0 は、無限のﾀｲﾑｱｳﾄ、ﾏｲﾅｽは、設定しません。(つまりJavaの初期値のまま)
	 * (初期値:ｼｽﾃﾑ定数のURL_CONNECT_TIMEOUT[={@og.value SystemData#URL_CONNECT_TIMEOUT}])。
	 *
	 * @param	tout	ﾀｲﾑｱｳﾄ時間(秒) (ｾﾞﾛは、無制限)
	 * @see		org.opengion.fukurou.util.HttpConnect#setTimeout(int)
	 * @see		java.net.URLConnection#setConnectTimeout(int)
	 */
	public void setTimeout( final String tout ) {
		timeout = nval( getRequestParameter( tout ),timeout );
	}

	/**
	 * 【TAG】JSONｺｰﾄﾞで認証するURLを指定します。
	 *
	 * @og.tag
	 * JSONｺｰﾄﾞで認証するURLを指定します。
	 *
	 * @param	url	JSONｺｰﾄﾞで認証するURL
	 */
	public void setAuthURL( final String url ) {
		authURL = nval( getRequestParameter( url ), authURL );
	}

	/**
	 * 【TAG】Basic認証を使用して接続する場合のﾕｰｻﾞｰ:ﾊﾟｽﾜｰﾄﾞを指定します。
	 *
	 * @og.tag
	 * 接続時のﾕｰｻﾞｰとﾊﾟｽﾜｰﾄﾞを、USER:PASSWD 形式で指定します。
	 *
	 * @param	userPass	ﾕｰｻﾞｰとﾊﾟｽﾜｰﾄﾞ (USER:PASSWD形式)
	 */
	public void setAuthUserPass( final String userPass ) {
		authUserPass = nval( getRequestParameter( userPass ),authUserPass );
	}

	/**
	 * 【TAG】企業IDを指定します。
	 *
	 * @og.tag
	 * 企業IDを指定します。
	 *
	 * @param	compId	企業ID
	 */
	public void setCompanyId( final String compId ) {
		companyId = nval( getRequestParameter( compId ),companyId );
	}

	/**
	 * 【TAG】ｱﾌﾟﾘｹｰｼｮﾝの名前を指定します。
	 *
	 * @og.tag
	 * ｱﾌﾟﾘｹｰｼｮﾝの名前を指定します。
	 *
	 * @param	appName	ﾃﾞｰﾀﾃｰﾌﾞﾙ情報
	 */
	public void setAppliName( final String appName ) {
		appliName = nval( getRequestParameter( appName ),appliName );
	}

	/**
	 * 【TAG】接続の結果を表示するかどうかを指定します(初期値:false)。
	 *
	 * @og.tag
	 * true で、接続結果を表示します。 false では、何も表示しません(初期値:false)
	 * 接続結果を表示する使い方より、admin 画面に接続して、ｷｬｯｼｭｸﾘｱするような
	 * 使い方が多いと考え、初期値は、false になっています。
	 * display="true" と、saveFile を併用することはできません。
	 *
	 * @param	flag	結果表示 [true:する/false:しない]
	 * @see		#setSaveFile( String )
	 */
	public void setDisplay( final String flag ) {
		display = nval( getRequestParameter( flag ),display );

		if( display && saveFile != null ) {
			final String errMsg = "display=\"true\" と、saveFile を併用することはできません。";
			throw new HybsSystemException( errMsg );
		}
	}

	/**
	 * 【TAG】接続の結果をﾌｧｲﾙに保存します。
	 *
	 * @og.tag
	 * 接続先のﾃﾞｰﾀを受け取って、ﾌｧｲﾙに保存します。
	 * display="true" と、saveFile を併用することはできません。
	 * loadFile が指定されていない時のみ処理を行います。
	 *
	 * @param	file	保存先ﾌｧｲﾙ
	 * @see		#setDisplay( String )
	 */
	public void setSaveFile( final String file ) {
		saveFile = nval( getRequestParameter( file ),saveFile );
		if( saveFile != null ) {
			saveFile = HybsSystem.url2dir( StringUtil.urlAppend( fileURL,saveFile ) );
			if( display ) {
				final String errMsg = "display=\"true\" と、saveFile を併用することはできません。";
				throw new HybsSystemException( errMsg );
			}
		}
	}

	/**
	 * 【TAG】ﾌｧｲﾙからURL接続結果に相当するﾃﾞｰﾀを読み取ります。
	 *
	 * @og.tag
	 * 主にﾃﾞﾊﾞｯｸﾞ用として使われます。
	 *
	 * @param	file	検索するﾌｧｲﾙ
	 */
	public void setLoadFile( final String file ) {
		loadFile = nval( getRequestParameter( file ),loadFile );
		if( loadFile != null ) {
			loadFile = HybsSystem.url2dir( StringUtil.urlAppend( fileURL,loadFile ) );
		}
	}

	/**
	 * 【TAG】ｺﾏﾝﾄﾞ (NEW,RENEW)をｾｯﾄします。
	 *
	 * @og.tag
	 * ｺﾏﾝﾄﾞは、HTMLから(get/post)指定されますので、
	 * CMD_xxx で設定されるﾌｨｰﾙﾄﾞ定数値のいづれかを指定できます。
	 *
	 * @param	cmd	ｺﾏﾝﾄﾞ (public static final 宣言されている文字列)
	 * @see		<a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.QueryTag.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】検索結果を画面上に表示するﾒｯｾｰｼﾞﾘｿｰｽIDを指定します
	 *        (初期値:VIEW_DISPLAY_MSG[={@og.value SystemData#VIEW_DISPLAY_MSG}])。
	 *
	 * @og.tag
	 * ここでは、検索結果の件数や登録された件数をまず出力し、
	 * その次に、ここで指定したﾒｯｾｰｼﾞをﾘｿｰｽから取得して表示します。
	 * 件数を表示させる場合は、displayMsg = "MSG0033"[　件検索しました] をｾｯﾄしてください。
	 * 表示させたくない場合は, displayMsg = "" をｾｯﾄしてください。
	 * (初期値:ｼｽﾃﾑ定数のVIEW_DISPLAY_MSG[={@og.value SystemData#VIEW_DISPLAY_MSG}])。
	 *
	 * @param	id	表示ﾒｯｾｰｼﾞID
	 * @see		org.opengion.hayabusa.common.SystemData#VIEW_DISPLAY_MSG
	 */
	public void setDisplayMsg( final String id ) {
		final String ids = getRequestParameter( id );
		if( ids != null ) { displayMsg = ids; }
	}

	/**
	 * 【TAG】検索結果がｾﾞﾛ件の場合に表示するﾒｯｾｰｼﾞﾘｿｰｽIDを指定します(初期値:MSG0077[対象ﾃﾞｰﾀはありませんでした])。
	 *
	 * @og.tag
	 * ここでは、検索結果がｾﾞﾛ件の場合のみ、特別なﾒｯｾｰｼﾞを表示させます。
	 * 従来は、displayMsg と兼用で、『0　件検索しました』という表示でしたが、
	 * displayMsg の初期表示は、OFF になりましたので、ｾﾞﾛ件の場合のみ別に表示させます。
	 * 表示させたくない場合は, notfoundMsg = "" をｾｯﾄしてください。
	 * 初期値は、MSG0077[対象ﾃﾞｰﾀはありませんでした]です。
	 *
	 * @param	id	ｾﾞﾛ件ﾒｯｾｰｼﾞID
	 */
	public void setNotfoundMsg( final String id ) {
		final String ids = getRequestParameter( id );
		if( ids != null ) { notfoundMsg = ids; }
	}

	/**
	 * 【TAG】検索結果が０件のとき処理を停止するかどうか[true/false]を指定します(初期値:false[続行する])。
	 *
	 * @og.tag
	 * 初期値は、false(続行する)です。
	 *
	 * @param	flag	０件時停止可否 [true:処理を中止する/false:続行する]
	 */
	public void setStopZero( final String flag ) {
		stopZero = nval( getRequestParameter( flag ),stopZero );
	}

	/**
	 * 【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】処理ｴﾗｰの時に処理を中止するかどうか[true/false]を設定します(初期値:true)。
	 *
	 * @og.tag
	 * false(中止しない)に設定する場合、後続処理では、{&#064;DB.ERR_CODE}の値により、
	 * IOr の異常/正常終了によって分岐処理は可能となります。
	 * 初期値は、true(中止する)です。
	 *
	 * @param	flag	ｴﾗｰ時処理中止 [true:中止する/false:中止しない]
	 */
	public void setStopError( final String flag ) {
		stopError = nval( getRequestParameter( flag ),stopError );
	}

	/**
	 * 【TAG】PLSQL/SQL処理ｴﾗｰの時にｴﾗｰを画面表示するか[true/false]を設定します(初期値:true)。
	 *
	 * @og.tag
	 * false(表示しない)に設定する場合、後続処理では、{&#064;DB.ERR_MSG}の値により、
	 * 本来表示されるはずだったﾒｯｾｰｼﾞを取得可能です。
	 * stopErrorと併用して、JSON形式でｴﾗｰを返す場合等に利用します。
	 * 初期値は、true(表示する)です。
	 * ※false指定の場合は件数や、overFlowﾒｯｾｰｼﾞ等も表示されなくなります。
	 *
	 * @param	flag	[true:表示する/false:表示しない]
	 */
	public void setDispError( final String flag ) {
		dispError = nval( getRequestParameter( flag ),dispError );
	}

	/**
	 * 【TAG】ﾘｸｴｽﾄ情報の ｼﾝｸﾞﾙｸｫｰﾄ(') 存在ﾁｪｯｸを実施するかどうか[true/false]を設定します
	 *        (初期値:USE_SQL_INJECTION_CHECK[={@og.value SystemData#USE_SQL_INJECTION_CHECK}])。
	 *
	 * @og.tag
	 * SQLｲﾝｼﾞｪｸｼｮﾝ対策の一つとして、暫定的ではありますが、SQLのﾊﾟﾗﾒｰﾀに
	 * 渡す文字列にｼﾝｸﾞﾙｸｫｰﾄ(') を許さない設定にすれば、ある程度は防止できます。
	 * 数字ﾀｲﾌﾟの引数には、 or 5=5 などのｼﾝｸﾞﾙｸｫｰﾄを使用しないｺｰﾄﾞを埋めても、
	 * 数字ﾁｪｯｸで検出可能です。文字ﾀｲﾌﾟの場合は、必ず (')をはずして、
	 * ' or 'A' like 'A のような形式になる為、(')ﾁｪｯｸだけでも有効です。
	 * (') が含まれていたｴﾗｰにする(true)／かﾉｰﾁｪｯｸか(false)を指定します。
	 * 初期値は、SystemData#USE_SQL_INJECTION_CHECK です。
	 *
	 * @param	flag	ｸｫｰﾄﾁｪｯｸ [true:する/それ以外:しない]
	 */
	public void setQuotCheck( final String flag ) {
		quotCheck = nval( getRequestParameter( flag ),quotCheck );
	}

	/**
	 * 【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}])
	 *
	 * @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】(通常は使いません)ﾀｸﾞで処理される処理がﾒｲﾝとなるﾄﾗﾝｻﾞｸｼｮﾝ処理かどうかを指定します(初期値:true)。
	 *
	 * @og.tag
	 * この値は、ﾌｧｲﾙﾀﾞｳﾝﾛｰﾄﾞ処理に影響します。この値がtrueに指定された時にcommitされたDBTableModelが
	 * ﾌｧｲﾙﾀﾞｳﾝﾛｰﾄﾞの対象の表になります。
	 *
	 * このﾊﾟﾗﾒｰﾀｰは、通常、各ﾀｸﾞにより実装され、ﾕｰｻﾞｰが指定する必要はありません。
	 * 但し、1つのJSP内でDBTableModelが複数生成される場合に、前に処理したDBTableModelについてﾌｧｲﾙﾀﾞｳﾝﾛｰﾄﾞをさせたい
	 * 場合は、後ろでDBTableModelを生成するﾀｸﾞで、明示的にこの値をfalseに指定することで、ﾌｧｲﾙﾀﾞｳﾝﾛｰﾄﾞ処理の対象から
	 * 除外することができます。
	 *
	 * @param	flag	ﾒｲﾝﾄﾗﾝｻﾞｸｼｮﾝかどうか [true:ﾒｲﾝ/false:その他]
	 */
	public void setMainTrans( final String flag ) {
		isMainTrans = nval( getRequestParameter( flag ),isMainTrans );
	}

	/**
	 * 【TAG】処理時間(queryTime)などの情報出力[true:有効/false:無効]を指定します(初期値:true)。
	 *
	 * @og.tag
	 * Query で、検索する場合に、処理時間(queryTime)などの情報を出力していますが、
	 * ViewForm で、CustomData などの 非HTML表示ﾋﾞｭｰを使用する場合、ﾃﾞｰﾀとして、
	 * 紛れ込んでしまうため、出力を抑制する必要があります。
	 * true(有効)にすると、これらのHTMLが出力されます。false にすると、出力されません。
	 * 初期値は、true(有効) です。
	 *
	 * @param	useTag	情報出力の有効/無効 [true:有効/false:無効]
	 */
	public void setUseBeforeHtmlTag( final String useTag ) {
		useBeforeHtmlTag = nval( getRequestParameter( useTag ),useBeforeHtmlTag );
	}

	/**
	 * 【TAG】処理時間を表示する TimeView を表示するかどうか[true:する/false:しない]を指定します
	 *        (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])。
	 *
	 * @og.tag
	 * true に設定すると、処理時間を表示するﾊﾞｰｲﾒｰｼﾞが表示されます。
	 * これは、DB検索、APｻｰﾊﾞｰ処理、画面表示の各処理時間をﾊﾞｰｲﾒｰｼﾞで
	 * 表示させる機能です。処理時間の目安になります。
	 * (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])。
	 *
	 * @param	flag	処理時間を表示 [true:する/false:しない]
	 */
	public void setUseTimeView( final String flag ) {
		useTimeView = nval( getRequestParameter( flag ),useTimeView );
	}

	/**
	 * IOr の応答結果を特定のｷｰﾜｰﾄﾞで分割します。(内部ｸﾗｽ)
	 *
	 * ﾌｫｰﾏｯﾄ形式のﾁｪｯｸ と ﾃﾞｰﾀの切り出しを行います。
	 * JSONﾌｫｰﾏｯﾄの例：{"status": … "data": {"headers": [ … ], "rows": [ {cols:[ … ]} ]}}
	 */
	private static final class SplitReqJson {
		private final String	strJson;										// JSON形式の文字列
		private int				endPos;											// 終了位置

		/**
		 * ｺﾝｽﾄﾗｸﾀｰ
		 *
		 * @param	strJson	JSON形式の文字列
		 */
		public SplitReqJson( final String str ) {
			strJson		= str;													// JSON形式の文字列
			endPos		= strJson.indexOf( "\"data\"" );						// 終了位置
		}

		/**
		 * HTTPｽﾃｰﾀｽ(先頭から "data"まで) の文字列を返します。
		 *
		 * @return	JSON形式の文字列
		 */
		public String getSttsJson() {
			if( endPos >= 0 ) {
				return strJson.substring( 0, endPos );
			} else {
				final String errMsg = "data ｷｰが存在しません。";
				throw new HybsSystemException( errMsg );
			}
		}

		/**
		 * 列ﾃﾞｰﾀ("headers"から "rows"まで) の文字列を返します。
		 *
		 * @return	JSON形式の文字列
		 */
		public String getClmJson() {
			final int startPos = strJson.indexOf( "\"headers\"", endPos );		// 開始位置
			endPos = strJson.indexOf( "\"rows\"", startPos );					// 終了位置
			if( startPos >= 0 && endPos >= 0) {
				return strJson.substring( startPos, endPos );
			} else {
				final String errMsg = "headers、rows ｷｰのいずれかが存在しません。";
				throw new HybsSystemException( errMsg );
			}
		}

		/**
		 * 行ﾃﾞｰﾀ("cols"から 最後まで) の文字列を返します。
		 *
		 * @return	JSON形式の文字列
		 */
		public String getRowJson() {
			final int startPos = strJson.indexOf( "\"cols\"", endPos );			// 開始位置
			if( startPos >= 0 ) {
				return strJson.substring( startPos );
			} else {
				final String errMsg = "cols ｷｰが存在しません。";
				throw new HybsSystemException( errMsg );
			}
		}

		/**
		 * 行ﾃﾞｰﾀ(最後から "count") の文字列を返します。
		 *
		 * @return	JSON形式の文字列
		 */
		public String getCntJson() {
			final int startPos = strJson.lastIndexOf( "\"count\"" );			// 開始位置
			if( startPos >= 0 ) {
				return strJson.substring( startPos );
			} else {
				final String errMsg = "count ｷｰが存在しません。";
				throw new HybsSystemException( errMsg );
			}
		}
	}

	/**
	 * このｵﾌﾞｼﾞｪｸﾄの文字列表現を返します。
	 * 基本的にﾃﾞﾊﾞｯｸﾞ目的に使用します。
	 *
	 * @return	このｸﾗｽの文字列表現
	 * @og.rtnNotNull
	 */
	@Override
	public String toString() {
		return ToString.title( this.getClass().getName() )
				.println( "VERSION"			,VERSION		)
				.println( "urlStr"			,urlStr			)
				.println( "timeout"			,timeout		)
				.println( "authURL"			,authURL		)
				.println( "authUserPass"	,authUserPass	)
				.println( "companyId"		,companyId		)
				.println( "appliName"		,appliName		)
				.println( "display"			,display		)
				.println( "postData"		,postData		)
				.println( "saveFile"		,saveFile		)
				.println( "loadFile"		,loadFile		)
				.println( "tableId"			,tableId		)
				.println( "Other..."		,getAttributes().getAttribute() )
				.fixForm().toString() ;
	}
}
