/*
 * 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 static org.opengion.fukurou.util.StringUtil.nval;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
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 javax.servlet.jsp.PageContext;

import org.opengion.fukurou.util.StringUtil;
import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.db.DBTableModel;
import org.opengion.hayabusa.db.Query;
import org.opengion.hayabusa.db.QueryFactory;

/**
 * JSP上からキー、値を設定することにより、リクエスト情報として、値を
 * 取出し可能にするタグです。
 *
 * 通常のリクエスト情報と同じ扱いができます（優先順位は、Valueタグが上位）。
 *
 * 設定した値は、{&#064;XXXX} 形式で 取り出すことができます。
 * また、command ="GET" で 直接画面に値を書き出すことも可能です。
 *
 * @og.formSample
 * ●形式：&lt;og:value command="SET" key="ABC" value="123" /&gt;
 * ●body：あり
 *
 * ●使用例
 *     ・ &lt;og:value command="SET" key="ABC" value="123" /&gt;
 *     ・ &lt;og:value command="SQL"&gt;&lt;jsp:text&gt;SELECT 1 TEST FROM DUAL&lt;/jsp:text&gt;&lt;/og:value&gt;
 *     ・ &lt;og:value command="SET" key="DEF" value="{&#064;NOCOMMAND}" defaultValue="0000" /&gt;
 *     ・ &lt;og:value command="GET" key="NOKEY" defaultValue="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;
 *
 * @og.group その他部品
 *
 * @version  4.0
 * @author   M.Endou
 * @since    JDK5.0,
 */
public class ValueTag extends CommonTagSupport {
	//* このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "4.0.0 (2005/08/31)" ;

	private static final long serialVersionUID = 4000 ;	// 4.0.0 (2005/01/31)

	/** 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 引数に渡す事の出来る コマンド リスト  */
	private static final String[] COMMAND_LIST = new String[] {
			CMD_SET , CMD_GET , CMD_REMOVE , CMD_SQL , CMD_SETTBL , CMD_GETTBL ,
			CMD_KEYTBL , CMD_CLEAR , CMD_SETMEM };

	/** 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 引数に渡す事の出来る アクション  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 引数に渡す事の出来る アクション リスト  */
	private static final String[] ACTION_LIST = new String[] {
//		ACT_UPPER , ACT_LOWER , ACT_MESSAGE , ACT_APPEND , ACT_ALL_APPEND , ACT_DAY_WEEK , ACT_MERGE , ACT_FIRST };
		ACT_UPPER , ACT_LOWER , ACT_MESSAGE , ACT_APPEND , ACT_ALL_APPEND , ACT_LIST, ACT_ALL_LIST , ACT_DAY_WEEK , ACT_MERGE , ACT_FIRST , ACT_ROW_APPEND };

	private String			tableId		= HybsSystem.TBL_MDL_KEY;
	private String			command		= CMD_SET;
	private String			key			= null;
	private String			inValue		= null;		// 3.5.4.0 (2003/11/25)
	private String			value		= null;
	private String			defaultVal	= null;
	private String			action		= null;
	private boolean			isNullSet	= true;			// NULL のときにセットし直すかどうか。
	private transient DBTableModel	table		= null;
	// 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
//	private String			dbid		= "DEFAULT";
	private String			dbid		= null;
	private String			scope		= "request";	// "request","session"
	private String			separator	= ",";   // 項目区切り文字
	private String			parameter	= null;
	// 3.2.4.0 (2003/06/12) マルチデータ（複数件検索）を使用するかしないか。
	private boolean		useMultiRows	= false;	// 初期値 使用せず

	/**
	 * 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 に移動。
	 *
	 * @return  int
	 */
	@Override
	public int doStartTag() {
		super.setScope( scope );

		if( isNullSet ) {
			setUseValue( false );
		}

		if( CMD_SQL.equals( command ) || CMD_SET.equals( command ) ) {
			return ( EVAL_BODY_BUFFERED );		// Body を評価する
		}
		else {
			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 (2005/01/31) lang ⇒ ResourceManager へ変更
	 *
	 * @return  int
	 */
	@Override
	public int doAfterBody() {
		if( value == null || value.length() <= 0 ) {
			value = getBodyString();

			if( CMD_SQL.equals( command ) ) {
				Query query = QueryFactory.newInstance();		// 4.0.0 (2005/01/31)
				try {
					value = value.trim();
					query.setConnectionID( dbid );
					query.setResourceManager( getResource() );	// 4.0.0 (2005/01/31)

					query.setStatement( value );
					query.setApplicationInfo( getApplicationInfo() );	// 3.8.7.0 (2006/12/15)
					query.execute();

					table = query.getDBTableModel();
				}
				finally {
					if( query != null ) { query.close(); }
					QueryFactory.close( query );
				}
			}
		}

		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 が存在するときのみ実行するロジックになっていたバグ対応。
	 *
	 * @return  int
	 */
	@Override
	public int doEndTag() {
		debugPrint();		// 4.0.0 (2005/02/28)
		if( check( command, COMMAND_LIST ) ) {
			if( CMD_SETTBL.equals( command ) ||
				CMD_GETTBL.equals( command ) ||
				CMD_KEYTBL.equals( command ) ) {
					table = (DBTableModel)getSessionAttribute( tableId );
			}
		}

		commandExec( command );

		if( CMD_GET.equals( command ) || CMD_GETTBL.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 に変更
	 *
	 */
	@Override
	protected void release2() {
		super.release2();
		tableId		= HybsSystem.TBL_MDL_KEY;
		command		= CMD_SET;
		key			= null;
		value		= null;
		defaultVal	= null;
		action		= null;
		isNullSet	= true;			// NULL のときにセットし直すかどうか。
		table		= null;
//		dbid		= "DEFAULT";
		dbid		= null;
		scope       = "request";	// "request","session"
		separator	= ",";
		parameter	= null;
		useMultiRows = false;
		inValue		= null;			// 3.5.4.0 (2003/11/25)
	}

	/**
	 * コマンドを実行します。
	 *
	 * コマンドは,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 を追加。
	 *
	 * @param   command String コマンド（public static final 宣言されている文字列)
	 * @see		<a href="{@docRoot}/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_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 )
	 *
	 * @param command String コマンド（public static final 宣言されている文字列)
	 * @param value String
	 * @return value String
	 */
	private String actionExec( final String action,final String value ) {
		String rtn = value;

		if( action == 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().getMessage( value );
			rtn = getResource().getLabel( value );
		}
		else if( ACT_DAY_WEEK.equals( action ) ) {
			// 日付型文字列(YYYYMMDD) の入力データを、開始日を月曜日にセットします。
			// SUNDAY=1 , MONDAY=2 になります。月曜日との差だけ、前に戻します。
			// 指定日が日曜日の場合は、次の日(月曜日)に進めます。
			Calendar ymd = HybsSystem.getCalendar( value );
			int shu = ymd.get( Calendar.DAY_OF_WEEK ) - Calendar.MONDAY ;

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

			DateFormat formatter = new SimpleDateFormat( "yyyyMMdd",Locale.JAPAN );
			rtn = formatter.format( ymd.getTime() );
		}
		// 3.7.1.1 (2005/05/23)
		else if( ACT_MERGE.equals( action ) ) {
			// 引数をカンマで文字列配列に分解します。
			String[] str = StringUtil.csv2Array( value );
			Set<String> set = new LinkedHashSet<String>();
			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(),"," );
		}

		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時のセパレータを外部指定の変数を使用
	 *
	 * @param key String
	 * @param value String
	 * @param action String
	 */
	private void setAttribute( final String key,final String value,final String action ) {
		if( key == null || key.length() == 0 ) {
			String errMsg = "key がセットされていません。" ;
			throw new HybsSystemException( errMsg );
		}

		if( isNullSet || ( !isNullSet && ( value != null && value.length() > 0 ) ) ) {
			if( ACT_APPEND.equals( action ) ) {
				String[] array = getRequestParameterValues( inValue );
				setObject( key, StringUtil.array2line( array,separator ) );
			}
			else {
				setObject( key, actionExec( action,value ) );
			}
		}
	}

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

		String rtn = defaultVal;
		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 String
	 */
	private void removeAttribute( final String key ) {
		if( key == null || key.length() == 0 ) {
			String errMsg = "key がセットされていません。" ;
			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 String
	 */
	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() ) {
//			String ekey = String.valueOf( ekeys.nextElement() ).toLowerCase(Locale.JAPAN);
			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() ) {
			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 アクションの追加
	 *
	 * @param table DBTableModel
	 */
	private void setSQLAttribute( final DBTableModel table ) {
		if( table == null ) {		// 3.8.6.0 (2006/08/07)
			return;
		}

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

		if( ACT_ROW_APPEND.equals( action ) ) {
			for( int clm = 0; clm < clmCnt; clm++ ) {
				StringBuilder buf = new StringBuilder();
				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_ALL_LIST.equals( action ) || ACT_LIST.equals( action ) ) {
			for( int clm = 0; clm < clmCnt; clm++ ) {
				ArrayList<String> list = new ArrayList<String>();
				for( int row=0; row<rowCnt; row++ ) {
					sqlval = table.getValue( row, clm );
					list.add( sqlval );
				}
				sqlkey = table.getColumnName( clm );
				setObject( sqlkey , list );
			}
		}
		else {
			if( isNullSet && 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; }
				}
			}
		}
	}

	/**
	 * 指定のスコープの内部キャッシュ情報に、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 アクションの追加
	 *
	 * @param table DBTableModel
	 * @param key String
	 * @param action String
	 */
	private void setTableAttribute( final DBTableModel table,final String key,final String action ) {
		if( table == null || table.getRowCount() == 0 || table.getColumnCount() == 0 ) { return ; }

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

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

		// 3.6.1.0 (2005/01/05) ACT_ALL_APPEND アクションの追加
		if( ACT_APPEND.equals( action ) ) {
			for( int i=0; i<keys.length; i++ ) {
				int clm = table.getColumnNo( keys[i] );
				StringBuilder val = new StringBuilder();
				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() );
			}
		}
		else if( ACT_ALL_APPEND.equals( action ) ) {
			int size = table.getRowCount();
			for( int i=0; i<keys.length; i++ ) {
				int clm = table.getColumnNo( keys[i] );
				StringBuilder val = new StringBuilder();
				val.append( table.getValue( 0,clm ) );
				for( int row=1; row<size; row++ ) {
					val.append( separator );
					val.append( table.getValue( row,clm ) );
				}
				setObject( keys[i],val.toString() );
			}
		}
	 	// 4.3.7.5 (2009/07/13) ACT_LIST アクションの追加
		else if( ACT_LIST.equals( action ) ) {
			for( int i=0; i<keys.length; i++ ) {
				int clm = table.getColumnNo( keys[i] );
				ArrayList<String> list = new ArrayList<String>();
				for( int j=0; j<rowNo.length; j++ ) {
					list.add( table.getValue( rowNo[j],clm ) );
				}
				setObject( keys[i],list );
			}
		}
	 	// 4.3.7.5 (2009/07/13) ACT_ALL_LIST アクションの追加
		else if( ACT_ALL_LIST.equals( action ) ) {
			int size = table.getRowCount();
			for( int i=0; i<keys.length; i++ ) {
				int clm = table.getColumnNo( keys[i] );
				ArrayList<String> list = new ArrayList<String>();
				for( int row=0; row<size; row++ ) {
					list.add( table.getValue( row,clm ) );
				}
				setObject( keys[i],list );
			}
		}
		else {
			for( int i=0; i<keys.length; i++ ) {
				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 アクションの追加
	 *
	 * @param table DBTableModel
	 * @param key String
	 * @param action String
	 * @return value String
	 */
	private String getTableAttribute( final DBTableModel table,final String key,final String action ) {
		if( table == null ) {
			String errMsg = "table がセットされていません。" ;
			throw new HybsSystemException( errMsg );
		}

		if( key == null || key.length() == 0 ) {
			String errMsg = "key がセットされていません。" ;
			throw new HybsSystemException( errMsg );
		}

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

		// 3.6.1.0 (2005/01/05) ACT_ALL_APPEND アクションの追加
		int clm = table.getColumnNo( key );
		if( ACT_APPEND.equals( action ) ) {
			StringBuilder val = new StringBuilder();
			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 if( ACT_ALL_APPEND.equals( action ) ) {
			StringBuilder val = new StringBuilder();
			val.append( table.getValue( 0,clm ) );
			int size = table.getRowCount();
			for( int row=1; row<size; row++ ) {
				val.append( separator );
				val.append( table.getValue( row,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 String
	 * @param value String
	 * @param action String
	 */
	private void setKeyTableAttribute( final DBTableModel table,final String key,final String value,final String action ) {
		if( table == null ) { return ; }

		if( key == null || key.length() == 0 ) {
			String errMsg = "key がセットされていません。" ;
			throw new HybsSystemException( errMsg );
		}

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

		final int[] valClm ;
		if( value == null || value.length() == 0 ) {
			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) ロジック変更
		for( int j=0; j<rowNo.length; j++ ) {
			String rowKey = key + j ;
			if( ACT_APPEND.equals( action ) ) {
				StringBuilder val = new StringBuilder();
				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 を元に、選ばれた 行を
	 * 処理の対象とします。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) 新規作成
	 * @og.rev 4.0.0 (2005/01/31) メイン処理を、super class で対応
	 * @og.rev 3.8.0.4 (2005/08/08) action="FIRST" 機能の追加
	 *
	 * @return rowNo int[]
	 */
	protected int[] getParameterRows() {
		// 3.8.0.4 (2005/08/08) action="FIRST" 機能の追加
		if( ACT_FIRST.equals( action ) ) {
			return new int[] { 0 };
		}
		else {
			return super.getParameterRows() ;
		}
	}

	/**
	 * 【TAG】sessionから取得する DBTableModel オブジェクトの ID。
	 *
	 * @og.tag
	 * 初期値は、HybsSystem.TBL_MDL_KEY です。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) DBTableModelの値をSET/GETできる command , action を追加。
	 *
	 * @param	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>
	 * <th><td>command	</td><td>名称			</td><td>機能</td></th>
	 * <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>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を使用します。
	 *
	 * @param	cmd コマンド（public static final 宣言されている文字列)
	 * @see		<a href="{@docRoot}/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 ) ) {
			StringBuilder errMsg = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
			errMsg.append( "指定のコマンドは実行できません。コマンドエラー" );
			errMsg.append( HybsSystem.CR );
			errMsg.append( "command=[" ).append( command ).append( "] " );
			errMsg.append( HybsSystem.CR );
			for( int i=0; i<COMMAND_LIST.length; i++ ) {
				errMsg.append( " | " );
				errMsg.append( COMMAND_LIST[i] );
			}
			errMsg.append( " | " );
			throw new HybsSystemException( errMsg.toString() );
		}
	}

	/**
	 * 【TAG】アクション(UPPER,LOWER,MESSAGE,APPEND,ALL_APPEND,LIST,ALL_LIST,DAY_WEEK,MERGE,FIRST,ROW_APPEND)をセットします。
	 *
	 * @og.tag
	 * アクションは,HTMLから（get/post)指定されますので,ACT_xxx で設定される
	 * フィールド定数値のいづれかを、指定できます。
	 * 無指定の場合は、なにもしません。
	 *
	 * <table>
	 * <th><td>action		</td><td>名称				</td><td>機能</td></th>
	 * <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>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>重複を除く、ユニークな値に、マージします。</td></tr>
	 * <tr><td>FIRST		</td><td>１件目取得		 	</td><td>最初の１件目を強制的に選択状態にして、処理を行います。</td></tr>
	 * <tr><td>ROW_APPEND	</td><td>検索結果の連結		</td><td>検索結果の行方向のデータを連結します。</td></tr>
	 * </table>
	 *
	 * @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のみ修正）
	 *
	 * @param	act アクション（public static final 宣言されている文字列)
	 * @see		<a href="{@docRoot}/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 ) ) {
			StringBuilder errMsg = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
			errMsg.append( "指定のアクションは実行できません。アクションエラー" );
			errMsg.append( HybsSystem.CR );
			errMsg.append( "action=[" ).append( action ).append( "] " );
			errMsg.append( HybsSystem.CR );
			for( int i=0; i<ACTION_LIST.length; i++ ) {
				errMsg.append( " | " );
				errMsg.append( ACTION_LIST[i] );
			}
			errMsg.append( " | " );
			throw new HybsSystemException( errMsg.toString() );
		}
	}

	/**
	 * 【TAG】リクエスト情報 に登録するキーをセットします。
	 *
	 * @og.tag リクエスト情報 に登録するキーをセットします。
	 *
	 * @og.rev 3.0.1.3 (2003/03/11) キーを toUpperCase している箇所を削除
	 *
	 * @param	key1 リクエスト情報に登録するキー
	 */
	public void setKey( final String key1 ) {
		key = nval( getRequestParameter( key1 ),key ) ;
		if( key == null ) {
			String errMsg = "key is not null." ;
			throw new HybsSystemException( errMsg );
		}
	}

	/**
	 * 【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 に移動。
	 *
	 * @param val String リクエスト情報に登録する値
	 */
	public void setValue( final String val ) {
		inValue = val;		// 3.5.4.0 (2003/11/25) 入力変数も、キープしておく。
		value = getRequestParameter( inValue );
	}

	/**
	 * 【TAG】value値がNULLの場合に、この初期値を設定します。
	 *
	 * @og.tag
	 * value値がNULLの場合に、この初期値をセットします。
	 *
	 * @param	val 初期値
	 */
	public void setDefaultVal( final String val ) {
		defaultVal = getRequestParameter( val );
	}

	/**
	 * 【TAG】value が NULL の時に、設定するかどうか(true/false)を指定します(初期値:true)。
	 *
	 * @og.tag
	 * true の場合は, null のときでもセットします。
	 * false の場合は, null のときは、既存の値を置き換えません。
	 * 初期値は、null のときでもセットするです。 ("true")
	 *
	 * @param   flag NULL の時に、設定する ("true")／設定しない(それ以外)
	 */
	public void setNullSet( final String flag ) {
		isNullSet = nval( getRequestParameter( flag ),isNullSet );
	}

	/**
	 * 【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 String スコープ
	 */
	public void setScope( final String scp ) {
		scope = nval( getRequestParameter( scp ),scope );
	}

	/**
	 * 【TAG】(未使用)アクションの処理パラメータを設定します。
	 *
	 * @og.tag アクションの処理パラメータを設定します。
	 *
	 * @og.rev 3.1.0.1 (2003/03/26) パラメーター属性の追加。
	 *
	 * @param	param パラメータ
	 */
	public void setParameter( final String param ) {
		parameter = nval( getRequestParameter( param ),parameter );
	}

	/**
	 * 【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】APPEND アクション時の文字列を連結する項目区切り文字をセットします。
	 *
	 * @og.tag 初期値は、"," に設定されています。
	 *
	 * @og.rev 3.5.6.5 (2004/08/09) 新規追加
	 *
	 * @param   sepa 項目区切り文字
	 */
	public void setSeparator( final String sepa ) {
		separator = nval( getRequestParameter( sepa ),separator );
	}

	/**
	 * シリアライズ用のカスタムシリアライズ書き込みメソッド
	 *
	 * @og.rev 4.0.0 (2006/09/31) 新規追加
	 * @serialData
	 *
	 * @param strm ObjectOutputStream
	 */
	private void writeObject( final ObjectOutputStream strm ) throws IOException {
		strm.defaultWriteObject();
	}

	/**
	 * シリアライズ用のカスタムシリアライズ読み込みメソッド
	 *
	 * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。
	 *
	 * @og.rev 4.0.0 (2006/09/31) 新規追加
	 * @serialData
	 *
	 * @param strm ObjectInputStream
	 * @see #release2()
	 */
	private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException {
		strm.defaultReadObject();
	}

	/**
	 * このオブジェクトの文字列表現を返します。
	 * 基本的にデバッグ目的に使用します。
	 * 
	 * @og.rev 4.3.4.0 (2008/12/01) PageContextのスコープをクラス変数としてアクセス
	 *
	 * @return このクラスの文字列表現
	 */
	public String toString() {
		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( "isNullSet"		,isNullSet		)
				.println( "dbid"			,dbid			)
				.println( "scope"			,scope			)
				.println( "separator"		,separator		)
				.println( "parameter"		,parameter		)
				.println( "useMultiRows"	,useMultiRows	)
				.println( "COMMAND_LIST"	,COMMAND_LIST	)
				.println( "ACTION_LIST"		,ACTION_LIST	)
				.println( "Other..."	,getAttributes().getAttribute() )
				.fixForm().toString() ;

		StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
		rtn.append( HybsSystem.CR ).append( "====================================" ).append( HybsSystem.CR );

		rtn.append( "APPLICATION_SCOPE:" ).append( HybsSystem.CR );

		Enumeration<String> ekeys = pageContext.getAttributeNamesInScope( PageContext.APPLICATION_SCOPE );	// 4.3.3.6 (2008/11/15) Generics警告対応
		while ( ekeys.hasMoreElements() ) {
//			String ekey = String.valueOf( ekeys.nextElement() );
			String ekey = ekeys.nextElement();		// 4.3.3.6 (2008/11/15) Generics警告対応
			rtn.append( "  key=[" ).append( ekey ).append( "] " );
			rtn.append( "value=[" ).append( pageContext.getAttribute( ekey,PageContext.APPLICATION_SCOPE ) ).append( "]" );
			rtn.append( HybsSystem.CR );
		}

		rtn.append( "SESSION_SCOPE:" ).append( HybsSystem.CR );
		ekeys = pageContext.getAttributeNamesInScope( PageContext.SESSION_SCOPE );
		while ( ekeys.hasMoreElements() ) {
			String ekey = String.valueOf( ekeys.nextElement() );
			rtn.append( "  key=[" ).append( ekey ).append( "] " );
			rtn.append( "value=[" ).append( pageContext.getAttribute( ekey,PageContext.SESSION_SCOPE ) ).append( "]" );
			rtn.append( HybsSystem.CR );
		}

		rtn.append( "REQUEST_SCOPE:" ).append( HybsSystem.CR );
		ekeys = pageContext.getAttributeNamesInScope( PageContext.REQUEST_SCOPE );
		while ( ekeys.hasMoreElements() ) {
			String ekey = String.valueOf( ekeys.nextElement() );
			rtn.append( "  key=[" ).append( ekey ).append( "] " );
			rtn.append( "value=[" ).append( pageContext.getAttribute( ekey,PageContext.REQUEST_SCOPE ) ).append( "]" );
			rtn.append( HybsSystem.CR );
		}

		rtn.append( "PAGE_SCOPE:" ).append( HybsSystem.CR );
		ekeys = pageContext.getAttributeNamesInScope( PageContext.PAGE_SCOPE );
		while ( ekeys.hasMoreElements() ) {
			String ekey = String.valueOf( ekeys.nextElement() );
			rtn.append( "  key=[" ).append( ekey ).append( "] " );
			rtn.append( "value=[" ).append( pageContext.getAttribute( ekey,PageContext.PAGE_SCOPE ) ).append( "]" );
			rtn.append( HybsSystem.CR );
		}
		rtn.append( "====================================" ).append( HybsSystem.CR );

		return rtnStr + rtn.toString();
	}
}
