/*
 * 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.servlet;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Enumeration;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.opengion.fukurou.db.ConnectionFactory;
import org.opengion.fukurou.util.Attributes;
import org.opengion.fukurou.util.HybsEntry;
import org.opengion.fukurou.util.StringUtil;
import org.opengion.fukurou.util.Closer ;				// 5.5.2.6 (2012/05/25)
import org.opengion.hayabusa.common.BuildNumber;
import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.SystemManager;
import org.opengion.hayabusa.common.SystemParameter;
import org.opengion.hayabusa.common.UserSummary;

/**
 * サーバー管理情報を取得するAdminサーブレットです。
 *
 * 引数(URL)に応じて、サーバーの状態結果を返します。
 * 一般には、http://サーバー:ポート/システムID/jsp/admin?COMMAND=コマンド の
 * 形式のURL でアクセスします。
 *
 *  ・COMMAND=infomation
 *     【サーバー情報】
 *        ＯＳ情報      = Windows 7 Service Pack 1
 *        サーバー名    = 10374232-0004 ( 172.27.26.192 )
 *        サーブレット  = Apache Tomcat/7.0.42
 *        TOMCAT_HOME   = C:/opengionV6/uap/bin//../../apps/tomcat7.0.42
 *        JDKバージョン = Java HotSpot(TM) Server VM 23.25-b01
 *        JAVA_HOME     = C:/opengionV6/apps/jdk170u25/jre
 *
 *     【実行環境】
 *        REAL_PATH     = C:/opengionV6/uap/webapps/gf/
 *        バージョンNo  = 6.0.0.0 Release6 Builds (2013233)
 *        作成日時      = 2013/08/21 14:57:29
 *
 *     【ログイン情報】
 *        ログイン人数  = 2 名 ( 明細情報 )
 *
 *     【メモリ情報】
 *        空きメモリ    = 15977 [KByte]
 *        合計メモリ    = 32448 [KByte]
 *        使用率        = 50 [％]
 *
 *  ・COMMAND=close
 *       リソース情報のキャッシュを全てクリアします。
 *
 *  ・COMMAND=loginUser
 *       現在のログインユーザーの明細情報を表示します。
 *       SORT=[JNAME,ID,ROLES,IPADDRESS,LOGINTIME] ソートキー
 *       DIREC=[true,false] true:昇順/false:降順
 *
 *  ・COMMAND=plugin
 *       現在のプラグインのバージョン情報を表示します。
 *
 *  ・COMMAND=systemResource
 *       現在のシステムリソースの設定情報を表示します。
 *
 *  ・COMMAND=AccessStop
 *       アクセスストップフィルターの制御(停止、許可)を行います。
 *
 * @og.rev 3.5.3.0 (2003/10/27) Admin JSP を Servlet化して、エンジンと共に供給します。
 * @og.rev 4.0.0.0 (2005/08/31) プラグインのバージョン情報の表示機能を追加
 * @og.group その他機能
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public final class HybsAdmin extends HttpServlet {
	private static final long serialVersionUID = 4000 ;	// 4.0.0 (2005/01/31)

	private static final String CR = HybsSystem.CR ;

	private static final String JSP = HybsSystem.sys( "JSP" );	// jspフォルダの正規パス

	private static final String HEADER =
		"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"												+ CR +
		"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""							+ CR +
		"    \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"							+ CR +
		"<html xmlns=\"http://www.w3.org/1999/xhtml\" >"											+ CR +
		"<head>"																					+ CR +
		"    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />"				+ CR +
		"    <meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />"						+ CR +
		"    <link rel=\"stylesheet\" href=\"" + JSP + "/common/default.css\" type=\"text/css\" />"	+ CR +
		"    <link rel=\"stylesheet\" href=\"" + JSP + "/custom/custom.css\" type=\"text/css\" />"				+ CR +
		"    <title>Hybs Admin</title>"																+ CR +
		"</head>"																					+ CR;

	// 3.5.3.1 (2003/10/31) User情報のテーブルの設定を、システムリソース より行う。
	private static final String TABLE_HEADER = getTableHeaderTag() ;

	private static final String OS_INFO      = HybsSystem.sys( "OS_INFO"      );		// Windows 7 Service Pack 1
	private static final String SERVER_INFO  = HybsSystem.sys( "SERVER_INFO"  );		// 10374232-0004 ( 200.1.50.239 )
	private static final String SERVLET_INFO = HybsSystem.sys( "SERVLET_INFO" );		// Apache Tomcat/7.0.39
	private static final String REAL_PATH    = HybsSystem.sys( "REAL_PATH"    );		// C:/opengion/uap/webapps/gf/
//	private static final String TOMCAT_WORK  = HybsSystem.sys( "TOMCAT_WORK"  );		// 5.6.7.3 (2013/08/23) TOMCAT_HOME に置き換え、廃止
	private static final String TOMCAT_HOME  = HybsSystem.sys( "TOMCAT_HOME"  );		// C:/opengion/apps/tomcat5.5.17
	private static final String JDK_INFO     = HybsSystem.sys( "JDK_INFO"     );		// Java HotSpot(TM) Server VM 23.25-b01
	private static final String JAVA_HOME    = HybsSystem.sys( "JAVA_HOME"    );		// C:/opengion/apps/jdk170u25/jre
	private static final String ENGINE_INFO  = HybsSystem.sys( "ENGINE_INFO"  );		// 5.6.6.0 Release5 Builds (2013182)

	/**
	 * GET メソッドが呼ばれたときに実行します。
	 *
	 * @og.rev 3.5.3.1 (2003/10/31) 機能ごとにメソッドを呼び出すように修正します。
	 * @og.rev 3.5.4.1 (2003/12/01) getAdminLink() メソッドを追加
	 *
	 * @param	req	HttpServletRequestオブジェクト
	 * @param	res	HttpServletResponseオブジェクト
	 *
	 * @throws ServletException サーブレット関係のエラーが発生した場合、throw されます。
	 * @throws IOException 入出力エラーが発生したとき
	 */
	@Override
	public void doGet( final HttpServletRequest req, final HttpServletResponse res)
								throws ServletException, IOException {

		res.setContentType( "text/html; charset=UTF-8" );
		PrintWriter out = res.getWriter();

		String command = req.getParameter( "COMMAND" );

		out.println( HEADER );
		out.println("<body>");

		out.print("<h2>");
		out.print( req.getServerName() );
		out.print( ":" );
		out.print( req.getServerPort() );
		out.print( req.getContextPath() );
		out.println("</h2>");

		if( "infomation".equalsIgnoreCase( command ) ) {
			out.print( getInfomation() );
		}
		else if( "close".equalsIgnoreCase( command ) ) {
			out.print( getCloseMessage( req.getSession() ) );
		}
		else if( "loginUser".equalsIgnoreCase( command ) ) {
			String sort  = req.getParameter( "sort" );
			String direc = req.getParameter( "direc" );
			boolean dir = (direc == null) ? true :  Boolean.valueOf( direc ).booleanValue();
			out.print( getLoginUser(sort,dir) );
		}
		else if( "plugin".equalsIgnoreCase( command ) ) {
			out.print( getPlugInInfo() );
		}
		else if( "taglib".equalsIgnoreCase( command ) ) {
			out.print( getTaglibInfo() );
		}
		else if( "systemResource".equalsIgnoreCase( command ) ) {
			out.print( getSystemResource() );
		}
		else if( "AccessStop".equalsIgnoreCase( command ) ) {
			out.print( getAccessStop() );
		}
		else {
			out.print( getAdminLink() );		// 3.5.4.1 (2003/12/01) 追加
		}

		out.println("</body></html>");
	}

	/**
	 * infomation 情報を作成します。
	 *
	 * @og.rev 3.5.3.1 (2003/10/31) 機能ごとにメソッドを呼び出すように修正します。
	 * @og.rev 5.6.7.3 (2013/08/23) TOMCAT_WORKは、TOMCAT_HOME に置き換えます。
	 *
	 * @return	infomation情報
	 */
	private String getInfomation() {
		// 4.0.0 (2005/01/31) ログイン数の取得方法の変更。
		int loginCount = SystemManager.getRunningCount() ;

		int freeMemory  = (int)( Runtime.getRuntime().freeMemory()/1024 ) ;
		int totalMemory = (int)( Runtime.getRuntime().totalMemory()/1024 );
		int useMemoryRatio = (((totalMemory - freeMemory) * 100 )/totalMemory) ;

		StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE );

		rtn.append( "<table border = \"0px\" >" ).append( CR );
		tableTr1( rtn,"サーバー情報" );
		tableTr( rtn,"ＯＳ情報"		, OS_INFO		);
		tableTr( rtn,"サーバー名"	, SERVER_INFO	);
		tableTr( rtn,"サーブレット"	, SERVLET_INFO	);
//		tableTr( rtn,"TOMCAT_WORK"	, TOMCAT_WORK	);		// 5.6.7.3 (2013/08/23) TOMCAT_HOME に置き換え、廃止
		tableTr( rtn,"TOMCAT_HOME"	, TOMCAT_HOME	);		// 5.6.7.3 (2013/08/23)
		tableTr( rtn,"JDKバージョン", JDK_INFO		);
		tableTr( rtn,"JAVA_HOME"	, JAVA_HOME		);

		tableTr1( rtn,"実行環境" );
		tableTr( rtn,"REAL_PATH"	, REAL_PATH		);
		tableTr( rtn,"バージョンNo"	, ENGINE_INFO	);
		tableTr( rtn,"作成日時"		, BuildNumber.TIMESTAMP	);

		tableTr1( rtn,"ログイン情報" );
		tableTr( rtn,"ログイン人数"	, String.valueOf( loginCount )," 名 ","( <a href=\"admin?COMMAND=loginUser\">明細情報</a> )" );

		tableTr1( rtn,"メモリ情報" );
		tableTr( rtn,"空きメモリ"	, String.valueOf( freeMemory )		, " [KByte]" );
		tableTr( rtn,"合計メモリ"	, String.valueOf( totalMemory )		, " [KByte]" );
		tableTr( rtn,"使用率"		, String.valueOf( useMemoryRatio )	, " [％]"    );

		rtn.append( "</table>" ).append( CR );
		rtn.append( CR );

//		rtn.append( "	<tr><td colspan = \"4\">サーバー情報</td></tr>" ).append( CR );
//		rtn.append( "	<tr><td></td><td>ＯＳ情報</td><td>=</td><td>" ).append( OS_INFO ).append( "</td></tr>" ).append( CR );
//		rtn.append( "	<tr><td></td><td>サーバー名</td><td>=</td><td>" ).append( SERVER_INFO ).append( "</td></tr>" ).append( CR );
//		rtn.append( "	<tr><td></td><td>サーブレット</td><td>=</td><td>" ).append( SERVLET_INFO ).append( "</td></tr>" ).append( CR );
//		rtn.append( "	<tr><td></td><td>REAL_PATH</td><td>=</td><td>" ).append( REAL_PATH ).append( "</td></tr>" ).append( CR );
//		rtn.append( "	<tr><td></td><td>TOMCAT_WORK</td><td>=</td><td>" ).append( TOMCAT_WORK ).append( "</td></tr>" ).append( CR );
//		rtn.append( "	<tr><td></td><td>JDKバージョン</td><td>=</td><td>" ).append( JDK_INFO ).append( "</td></tr>" ).append( CR );
//		rtn.append( "	<tr><td></td><td>JAVA_HOME</td><td>=</td><td>" ).append( JAVA_HOME ).append( "</td></tr>" ).append( CR );
//		rtn.append( "	<th><td></td><td colspan = \"2\"></td></th>" ).append( CR );
//		rtn.append( "	<tr><td colspan = \"4\">エンジンバージョン</td></tr>" ).append( CR );
//		rtn.append( "	<tr><td></td><td>バージョンNo</td><td>=</td><td>" ).append( ENGINE_INFO ).append( "</td></tr>" ).append( CR );
//		rtn.append( "	<tr><td></td><td>作成日時</td><td>=</td><td>" ).append( BuildNumber.TIMESTAMP ).append( "</td></tr>" ).append( CR );
//		rtn.append( "	<th><td></td><td colspan = \"2\"></td></th>" ).append( CR );
//		rtn.append( "	<tr><td colspan = \"4\">ログインユーザー</td></tr>" ).append( CR );
//		rtn.append( "	<tr><td></td><td>ログイン人数    </td><td>=</td><td>" ).append( loginCount ).append( " 名 " );
//		rtn.append( "( <a href=\"admin?COMMAND=loginUser\">明細情報</a> )</td></tr>" ).append( CR );
//		rtn.append( "	<tr><td colspan = \"4\">メモリ情報</td></tr>" ).append( CR );
//		rtn.append( "	<tr><td></td><td>空きメモリ</td><td>=</td><td>" ).append( freeMemory ).append( " [KByte]</td></tr>" ).append( CR );
//		rtn.append( "	<tr><td></td><td>合計メモリ</td><td>=</td><td>" ).append( totalMemory ).append( " [KByte]</td></tr>" ).append( CR );
//		rtn.append( "	<tr><td></td><td>使用率</td><td>=</td><td>" ).append( useMemoryRatio ).append( " [％]</td></tr>" ).append( CR );
//		rtn.append( "</table>" ).append( CR );
//		rtn.append( CR );

		rtn.append( "<table width=\"50%\" frame=\"box\" border = \"1px\" cellspacing=\"0px\" cellpadding=\"0px\" >" ).append( CR );
//		rtn.append( "	<tr><td width=\"" ).append( useMemoryRatio ).append( "%\" bgcolor=\"red\" >" ).append( CR );
//		rtn.append( "		<img width=\"100%\" height=\"10px\" src=\"" ).append( JSP ).append( "/image/space.gif\" alt=\"" ).append( useMemoryRatio ).append( "%\"></td>" ).append( CR );
//		rtn.append( "		<td></td>" ).append( CR );
//		rtn.append( "	</tr>" ).append( CR );
		rtn.append( "	<tr><td align=\"center\" width=\"" ).append( useMemoryRatio ).append( "%\" bgcolor=\"red\" >" ).append( CR );
		rtn.append( useMemoryRatio ).append( "%</td>" ).append( CR );
		rtn.append( "		<td align=\"center\">" ).append( 100-useMemoryRatio ).append( "%</td>" ).append( CR );
		rtn.append( "	</tr>" ).append( CR );
		rtn.append( "</table>" ).append( CR );

		rtn.append( "<hr />" ).append( CR );
		rtn.append( "<pre>" ).append( CR );
		rtn.append( ConnectionFactory.information() ).append( CR );
		rtn.append( "</pre>" ).append( CR );

		return rtn.toString();
	}

	/**
	 * infomation 情報を作成します。
	 *
	 * @og.rev 5.6.6.0 (2013/07/05) &lt;/td&gt;&lt;/tr&gt;漏れ追加
	 * @og.rev 5.6.7.3 (2013/08/23) 前後に、【】を付けます。
	 *
	 * @param	buf	情報登録用のStringBuilder(出力と同じオブジェクト)
	 * @param	key	キー
	 *
	 * @return	infomation情報
	 */
	private StringBuilder tableTr1( final StringBuilder buf, final String key ) {
//		buf.append( "<tr><td colspan = \"4\">" ).append( key ).append( CR );
//		buf.append( "<tr><td colspan=\"4\"><b>" ).append( key ).append( "</b></td></tr>" ).append( CR );		// td,tr 漏れ追加
		buf.append( "<tr><td colspan=\"4\"><b>【" ).append( key ).append( "】</b></td></tr>" ).append( CR );	// 【】追加
		return buf ;
	}

	/**
	 * infomation 情報を作成します。
	 *
	 * @og.rev 5.6.6.0 (2013/07/05) 最初の td に、全角スペース２個 追加
	 *
	 * @param	buf	情報登録用のStringBuilder(出力と同じオブジェクト)
	 * @param	key	キー
	 * @param	val	値の可変長引数
	 *
	 * @return	infomation情報
	 */
	private StringBuilder tableTr( final StringBuilder buf, final String key, final String... val ) {
//		buf.append( "\t<tr><td></td><td>" ).append( key ).append( "</td><td>=</td><td>" );
		buf.append( "<tr><td width=\"20px\">　</td><td>" ).append( key ).append( "</td><td> = </td><td>" );			// 段を作成する為に、width指定 追加
		for( int i=0; i<val.length; i++ ) {
			buf.append( val[i] );
		}
		buf.append( "</td></tr>" ).append( CR );
		return buf ;
	}

	/**
	 * close 情報を作成します。
	 *
	 * @og.rev 3.5.3.1 (2003/10/31) 機能ごとにメソッドを呼び出すように修正します。
	 * @og.rev 3.6.0.0 (2004/09/17) CalendarFactory.clear() を追加します。
	 * @og.rev 4.0.0.0 (2005/01/31) Cleanable インターフェースによる初期化処理
	 * @og.rev 4.1.0.2 (2008/01/29) UserInfoをsessionから消去する(超暫定対応)
	 * @og.rev 5.6.6.0 (2013/07/05) UserSummary の削除処理は、SystemManager から行う。
	 *
	 * @param	session	HttpSessionオブジェクト
	 *
	 * @return	close情報
	 */
	private String getCloseMessage( final HttpSession session ) {

		// 4.0.0 (2005/01/31) Cleanable インターフェースによる初期化処理
		SystemManager.allClear( false ) ;

		ServletContext context = session.getServletContext();
		Map<String,String> param = SystemParameter.makeSystemParameter( context );
		HybsSystem.setInitialData( param );			// 4.0.0 (2005/01/31)

		// 5.6.6.0 (2013/07/05) UserSummary の削除処理は、SystemManager から行う。
		SystemManager.removeSession( session ) ;

//		UserSummary userInfo = (UserSummary)session.getAttribute( HybsSystem.USERINFO_KEY );
////		if( userInfo != null ) { userInfo.clear(); }
//		if( userInfo != null ) { // 4.1.0.2 (2008/01/29)
//			userInfo.clear();
//			session.removeAttribute( HybsSystem.USERINFO_KEY );
//		}

		String rtn = "<pre>"
					+ "キャッシュ情報をクリアーしました。"
					+ CR
					+ "ユーザー情報の初期化に関しては、ブラウザを閉じて、再ログインが必要です。"
					+ CR
					+ ConnectionFactory.information()
					+ "</pre>" ;
		return rtn ;
	}

	// 5.6.6.0 (2013/07/05) getLoginUser( String,boolean ) で、指定するキーを配列で持っておきます。
	// キーは、SystemManager.getRunningUserSummary 処理内で大文字化されるため、この配列は、表示用と兼用します。
	private static final String[] USER_KEYS = new String[] { "ID","Jname","Roles","IPAddress","LoginTime","LastAccess","LastGamenNm" };

	/**
	 * loginUser 情報を作成します。
	 *
	 * @og.rev 3.5.3.1 (2003/10/31) 機能ごとにメソッドを呼び出すように修正します。
	 * @og.rev 3.8.5.3 (2006/08/07) ユーザー情報をソートするためのキー情報を追加
	 * @og.rev 3.8.7.0 (2006/12/15) USER.LASTACCESS情報を追加します。
	 * @og.rev 4.0.0.0 (2005/01/31) DBColumn の 属性(CLS_NM)から、DBTYPEに変更
	 * @og.rev 4.4.0.1 (2009/08/08) 最終ログイン画面名称を追加
	 * @og.rev 5.6.6.0 (2013/07/05) table作成処理を、変更します。
	 *
	 * @param	sort 	ソートするキー項目を指定
	 * @param	direc	ソートする方向 [true:昇順/false:降順]
	 *
	 * @return	loginUser情報
	 */
	private String getLoginUser( final String sort,final boolean direc ) {
		// 4.0.0 (2005/01/31) ログイン数の取得方法の変更。
		int loginCount = SystemManager.getRunningCount() ;

		// 4.0.0 (2005/01/31)
		UserSummary[] userInfos = SystemManager.getRunningUserSummary( sort,direc );

		StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE );

		rtn.append( "現在 " ).append( loginCount ).append( " 名の方がログイン中です。" );
		rtn.append( CR );

		rtn.append( "<table " ).append( TABLE_HEADER ).append( " >" ).append( CR );
		rtn.append( " <thead><tr><th>No</th>" );

		// 5.6.6.0 (2013/07/05) table作成処理を、変更します。
		for( String sortKey : USER_KEYS ) {
			rtn.append( "  <th><a href=\"?COMMAND=loginUser&sort=" ).append( sortKey )
				.append( "&direc=" ).append( !direc )
				.append( "\">" ).append( sortKey ).append( "</a></th>" );
		}

//		rtn.append( "  <th><a href=\"?COMMAND=loginUser&sort=ID&direc="			).append( !direc );
//		rtn.append(				"\">UserID</a></th>" );
//		rtn.append( "  <th><a href=\"?COMMAND=loginUser&sort=JNAME&direc="		).append( !direc );
//		rtn.append(				"\">Jname</a></th>" );
//		rtn.append( "  <th><a href=\"?COMMAND=loginUser&sort=ROLES&direc="		).append( !direc );
//		rtn.append(				"\">Roles</th>" );
//		rtn.append( "  <th><a href=\"?COMMAND=loginUser&sort=IPADDRESS&direc="	).append( !direc );
//		rtn.append(				"\">IPAddress</a></th>" );
//		rtn.append( "  <th><a href=\"?COMMAND=loginUser&sort=LOGINTIME&direc="	).append( !direc );
//		rtn.append(				"\">LoginTime</a></th>" );
//		rtn.append( "  <th><a href=\"?COMMAND=loginUser&sort=LASTACCESS&direc="	).append( !direc );
//		rtn.append(				"\">LastAccess</a></th>" );
//		rtn.append( "  <th><a href=\"?COMMAND=loginUser&sort=LASTGAMENNM&direc=").append( !direc ); // 4.4.0.1 (2009/08/08)
//		rtn.append(				"\">LastGamenName</a></th>" );
		rtn.append( " </tr></thead>" ).append( CR );
		rtn.append( " <colgroup class=\"S9\" />" ).append( CR );
		rtn.append( " <colgroup class=\"X\" span=\"6\" />" ).append( CR );
		rtn.append( CR );

		for( int i=0; i<userInfos.length; i++ ) {
			UserSummary userInfo = userInfos[i] ;
			rtn.append( " <tr class=\"row_" ).append( i%2 ).append( "\" >" ).append( CR );
			rtn.append( "  <td>" ).append( String.valueOf( i+1 )   ).append( "</td>" ).append( CR );
			rtn.append( "  <td>" ).append( userInfo.getUserID()    ).append( "</td>" ).append( CR );
			rtn.append( "  <td>" ).append( userInfo.getJname()     ).append( "</td>" ).append( CR );
			rtn.append( "  <td>" ).append( userInfo.getRoles()     ).append( "</td>" ).append( CR );
			rtn.append( "  <td>" ).append( userInfo.getIPAddress() ).append( "</td>" ).append( CR );
			rtn.append( "  <td>" ).append( HybsSystem.getDate( userInfo.getLoginTime() ) ).append( "</td>" ).append( CR );
			rtn.append( "  <td>" ).append( userInfo.getAttribute( "LASTACCESS") ).append( "</td>" ).append( CR );
			rtn.append( "  <td>" ).append( StringUtil.nval( userInfo.getAttribute( "LASTGAMENNM"), "" ) ).append( "</td>" ).append( CR );  // 4.4.0.1 (2009/08/08)
			rtn.append( " </tr>" ).append( CR );
		}
		rtn.append( "</table>" ).append( CR );

		return rtn.toString() ;
	}

	/**
	 * PlugIn 情報を作成します。
	 *
	 * @og.rev 4.0.0.0 (2005/08/31) 新規作成
	 * @og.rev 5.6.6.0 (2013/07/05) "DBConstValue","Daemon","JspCreate" を、追加します。
	 *
	 * @return	PlugIn情報
	 */
	private String getPlugInInfo() {

		String[] pluginType = new String[] {
								"Query","Renderer","Editor","DBType","ViewForm",
								"TableReader","TableWriter","TableFilter","ChartWriter","CalendarQuery",
								"DBConstValue","Daemon","JspCreate"					// 5.6.6.0 (2013/07/05) 追加
							} ;

		ClassInfo info = new ClassInfo();

		for( int j=0; j<pluginType.length; j++ ) {
			String type = pluginType[j] ;
			HybsEntry[] names = HybsSystem.sysEntry( type + "_" );
			for( int i=0; i<names.length; i++ ) {
				String key		= names[i].getKey().substring( type.length()+1 );
				String clsName	= names[i].getValue();
				info.addLine( type,key,clsName );
			}
		}
		return info.getClassInfoData() ;
	}

	/**
	 * Taglib 情報を作成します。
	 *
	 * @og.rev 4.0.0.0 (2006/01/31) 新規作成
	 * @og.rev 5.3.6.0 (2011/06/01) Taglib クラス名の求め方を変更します。(jar版のみ)
	 * @og.rev 5.5.2.6 (2012/05/25) JarFile を、Closer#zipClose( ZipFile ) メソッドを利用して、close します。
	 *
	 * @return	Taglib情報
	 */
	private String getTaglibInfo() {
		ClassInfo info = new ClassInfo();

		// 5.5.2.6 (2012/05/25) findbugs対応
		JarFile jarFile = null;
		try {
			ClassLoader loader = Thread.currentThread().getContextClassLoader();
			Enumeration<URL> enume = loader.getResources( "org/opengion/hayabusa/taglib/" );		// 4.3.3.6 (2008/11/15) Generics警告対応
			while( enume.hasMoreElements() ) {
				URL url = enume.nextElement();		// 4.3.3.6 (2008/11/15) Generics警告対応
				// jar:file:/実ディレクトリ または、file:/実ディレクトリ
				String dir = url.getFile();
				if( "jar".equals( url.getProtocol() ) ) {
					// dir = file:/G:/webapps/gf/WEB-INF/lib/hayabusa4.0.0.jar!/org/opengion/hayabusa/taglib 形式です。
					String jar = dir.substring(dir.indexOf( ':' )+1,dir.lastIndexOf( '!' ));
					// jar = /G:/webapps/gf/WEB-INF/lib/hayabusa4.0.0.jar 形式に切り出します。
//					JarFile jarFile = new JarFile( jar );
					jarFile = new JarFile( jar );
					Enumeration<JarEntry> en = jarFile.entries() ;		// 4.3.3.6 (2008/11/15) Generics警告対応
					while( en.hasMoreElements() ) {
						JarEntry ent = en.nextElement();		// 4.3.3.6 (2008/11/15) Generics警告対応
						String file = ent.getName();
						if( ! ent.isDirectory() && file.endsWith( "Tag.class" ) ) {
							String type		= "Taglib";
							// 5.3.6.0 (2011/06/01) Taglib クラス名の求め方を変更します。(jar版のみ)
//							String key		= file.substring( 0,file.length()-6 );
							String key		= file.substring( file.lastIndexOf( '/' )+1,file.length()-6 );	// -6 は、.class 分
//							String clsName	= "org.opengion.hayabusa.taglib." + key ;
							String clsName	= file.replace( '/','.' ).substring( 0,file.length()-6 );
							info.addLine( type,key,clsName );
						}
					}
					Closer.zipClose( jarFile );		// 5.5.2.6 (2012/05/25) findbugs対応
					jarFile = null;					// 正常終了時に、close() が２回呼ばれるのを防ぐため。
				}
				else {
					// dir = /G:/webapps/gf/WEB-INF/classes/org/opengion/hayabusa/taglib/ 形式です。
					File fileObj = new File( dir );
					File[] list = fileObj.listFiles();
					for( int i=0; i<list.length; i++ ) {
						String file = list[i].getName() ;
						if( list[i].isFile() && file.endsWith( "Tag.class" ) ) {
							String type		= "Taglib";
							String key		= file.substring( 0,file.length()-6 );
							String clsName	= "org.opengion.hayabusa.taglib." + key ;
							info.addLine( type,key,clsName );
						}
					}
				}
			}
		}
		catch( IOException ex ) {
			String errMsg = "taglibファイル読み取りストリームを失敗しました。"
					+ CR + ex.getMessage();
			throw new RuntimeException( errMsg,ex );
		}
		finally {
			Closer.zipClose( jarFile );		// 5.5.2.6 (2012/05/25) findbugs対応
		}

		return info.getClassInfoData() ;
	}

	/**
	 * クラス情報を表示するためのデータを管理します。
	 * ここでは、引数に渡された、分類(Classify)、名称(Key Name)、クラス名(Class Name)、
	 * バージョン(Version)情報をテーブル形式で表示します。
	 * バージョン情報は、クラス名から、インスタンスを作成して、private static final String VERSION
	 *  フィールドの値を読み取ります。
	 *
	 * @og.rev 4.0.0.0 (2006/01/31) 新規作成
	 */
	private static final class ClassInfo {
		private final StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
		private int cnt = 0;

		/**
		 * コンストラクター
		 *
		 * @og.rev 4.0.0.0 (2006/01/31) 新規作成
		 */
		public ClassInfo() {
			rtn.append( "<table " ).append( TABLE_HEADER ).append( " >" ).append( CR );
			rtn.append( "	<thead><tr><th>No</th><th>Classify</th><th>Key Name</th><th>Class Name</th><th>Version</th></tr></thead>" ).append( CR );
			rtn.append( "	<colgroup class=\"S9\" />" ).append( CR );
			rtn.append( "	<colgroup class=\"X\" />"  ).append( CR );
			rtn.append( "	<colgroup class=\"X\" />"  ).append( CR );
			rtn.append( "	<colgroup class=\"X\" />"  ).append( CR );
			rtn.append( "	<colgroup class=\"X\" />"  ).append( CR );
			rtn.append( "	<colgroup class=\"X\" />"  ).append( CR );
			rtn.append( CR );
		}

		/**
		 * テーブル表示用のデータを追加します。
		 *
		 * @og.rev 4.0.0.0 (2006/01/31) 新規作成
		 *
		 * @param	type	タイプ属性
		 * @param	key 	キー属性
		 * @param	clsName	クラス名(このクラス名からインスタンス化します。)
		 */
		public void addLine( final String type, final String key, final String clsName ) {
			String version	= getFieldValue( clsName );

			boolean isCustom = ( version.compareTo( BuildNumber.VERSION_NO ) > 0 ) ||
								version.indexOf( "Pache"   ) >= 0 ||
								version.indexOf( "Nightly" ) >= 0 ;

			String trType = ( isCustom ) ? "warning" : String.valueOf( cnt%2 );

			rtn.append( "	<tr class=\"row_" ).append( trType ).append( "\" >" ).append( CR );
			rtn.append( "		<td>" ).append( cnt++    ).append( "</td>" ).append( CR );
			rtn.append( "		<td>" ).append( type     ).append( "</td>" ).append( CR );
			rtn.append( "		<td>" ).append( key      ).append( "</td>" ).append( CR );
			rtn.append( "		<td>" ).append( clsName  ).append( "</td>" ).append( CR );
			rtn.append( "		<td>" ).append( version  ).append( "</td>" ).append( CR );
			rtn.append( "	</tr>" ).append( CR );
		}

		/**
		 * すべての内部のデータを文字列化して返します。
		 *
		 * @og.rev 4.0.0.0 (2006/01/31) 新規作成
		 *
		 * @return	作成されたテーブルデータ
		 */
		public String getClassInfoData() {
			rtn.append( "</table>" ).append( CR );
			return rtn.toString() ;
		}

		/**
		 * 指定のオブジェクトの  VERSION staticフィールドの値を取得します。
		 *
		 * @og.rev 4.0.0.0 (2005/08/31) 新規作成
		 *
		 * @param	clsName	指定のクラスを表す名称
		 * @return	VERSION staticフィールドの値(エラー時は、そのメッセージ)
		 */
		private String getFieldValue( final String clsName ) {
			String rtn ;
			try {
				Object obj = HybsSystem.newInstance( clsName );
				Field fld = obj.getClass().getDeclaredField( "VERSION" ) ;
				// privateフィールドの取得には、accessibleフラグを trueにする必要があります。
				fld.setAccessible( true );

				rtn = (String)fld.get( null );
			}
			catch( Throwable ex ) {
				rtn = ex.getMessage();
			}
			return rtn ;
		}
	}

	/**
	 * systemResource 情報を作成します。
	 *
	 * @og.rev 3.5.3.1 (2003/10/31) 機能ごとにメソッドを呼び出すように修正します。
	 * @og.rev 4.0.0.0 (2005/01/31) DBColumn の 属性(CLS_NM)から、DBTYPEに変更
	 *
	 * @return	systemResource情報
	 */
	private String getSystemResource() {
		StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE );

		rtn.append( "<table " ).append( TABLE_HEADER ).append( " >" ).append( CR );
		rtn.append( "	<thead><tr><th>No</th><th>Key</th><th>Value</th></tr></thead>" ).append( CR );
		rtn.append( "	<colgroup class=\"S9\" />" ).append( CR );
		rtn.append( "	<colgroup class=\"X\" span=\"2\" />" ).append( CR );
		rtn.append( CR );

		String[][] str = HybsSystem.getSystemResourceData();
		for( int i=0; i<str[0].length; i++ ) {
			rtn.append( "	<tr class=\"row_" ).append( i%2 ).append( "\" >" ).append( CR );
			rtn.append( "		<td>" ).append( String.valueOf( i+1 ) ).append( "</td>" ).append( CR );
			rtn.append( "		<td>" ).append( str[0][i] ).append( "</td>" ).append( CR );
			rtn.append( "		<td>" ).append( str[1][i] ).append( "</td>" ).append( CR );
			rtn.append( "	</tr>" ).append( CR );
		}
		rtn.append( "</table>" ).append( CR );

		return rtn.toString();
	}

	/**
	 * AccessStop 情報を作成します。
	 *
	 * @og.rev 3.5.3.1 (2003/10/31) 機能ごとにメソッドを呼び出すように修正します。
	 * @og.rev 4.0.0.0 (2007/11/29) AccessStopFilter#getStopFilter() ⇒ isStopFilter() に変更
	 *
	 * @return	AccessStop情報
	 */
	private String getAccessStop() {

//		boolean flag = org.opengion.hayabusa.filter.AccessStopFilter.getStopFilter();
		boolean flag = org.opengion.hayabusa.filter.AccessStopFilter.isStopFilter();
		flag = !flag ;

		final String rtn ;
		if( flag ) {
			rtn = "Webアプリケーションのサービスを停止します。";
		}
		else {
			rtn = "Webアプリケーションのサービスを開始します。";
		}
		org.opengion.hayabusa.filter.AccessStopFilter.setStopFilter( flag );

		return rtn ;
	}

	/**
	 * admin リンク情報を作成します。
	 * 簡易メソッドなので、国際化対応していません。
	 *
	 * @og.rev 3.5.4.1 (2003/12/01) 新規作成
	 * @og.rev 5.1.1.2 (2009/12/10) 画面IDを変更
	 * @og.rev 5.6.3.4 (2013/04/26) ｸｲｯｸﾘﾌｧﾚﾝｽ 画面を追加
	 *
	 * @return	アドミンリンク情報
	 */
	private String getAdminLink() {
		StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE );

		rtn.append( "<table><tr>" ).append( CR );
		rtn.append( "<td width=\"10px\"/>" ).append( CR );
		rtn.append( "<td>[<a href=\"admin?COMMAND=infomation\" target=\"RESULT\" >状況表示</a>]</td>" ).append( CR );
		rtn.append( "<td width=\"10px\"/>" ).append( CR );
		rtn.append( "<td>[<a href=\"admin?COMMAND=close\" target=\"RESULT\" >ﾌﾟｰﾙ削除</a>]</td>" ).append( CR );
		rtn.append( "<td width=\"10px\"/><td>" ).append( CR );
		rtn.append( "[<a href=\"admin?COMMAND=loginUser\" target=\"RESULT\" >ﾛｸﾞｲﾝﾕｰｻﾞｰ</a>]</td>" ).append( CR );
		rtn.append( "<td width=\"10px\"/><td>" ).append( CR );
		rtn.append( "[<a href=\"admin?COMMAND=plugin\" target=\"RESULT\" >ﾌﾟﾗｸﾞｲﾝ情報</a>]</td>" ).append( CR );
		rtn.append( "<td width=\"10px\"/><td>" ).append( CR );
		rtn.append( "[<a href=\"admin?COMMAND=taglib\" target=\"RESULT\" >ﾀｸﾞﾘﾌﾞ情報</a>]</td>" ).append( CR );
		rtn.append( "<td width=\"10px\"/><td>" ).append( CR );
		rtn.append( "[<a href=\"common/quickReference.html\" target=\"RESULT\" >ｸｲｯｸﾘﾌｧﾚﾝｽ</a>]</td>" ).append( CR );	// 5.6.3.4 (2013/04/26)
		rtn.append( "<td width=\"10px\"/><td>" ).append( CR );
		rtn.append( "[<a href=\"admin?COMMAND=systemResource\" target=\"RESULT\" >ｼｽﾃﾑﾘｿｰｽ</a>]</td>" ).append( CR );
		rtn.append( "<td width=\"10px\"/><td>" ).append( CR );
//		rtn.append( "[<a href=\"common/gamen/01_ADMIN/parameter.jsp?GAMENID=ADMIN\" target=\"RESULT\" >Parameter</a>]</td>" ).append( CR );
		rtn.append( "[<a href=\"common/gamen/01_ADMIN/parameter.jsp?GAMENID=01_ADMIN\" target=\"RESULT\" >Parameter</a>]</td>" ).append( CR );
		rtn.append( "</tr></table>" ).append( CR );

		return rtn.toString();
	}

	/**
	 * DBTableModel から テーブルのタグ文字列を作成して返します。
	 *
	 * @og.rev 3.5.3.1 (2003/10/31) User情報のテーブルの設定を、システムリソース より行う。
	 * @og.rev 5.2.2.0 (2010/11/01) SystemData 見直し漏れの対応。
	 *
	 * @return	テーブルのタグ文字列
	 */
	private static String getTableHeaderTag() {
		Attributes attri = new Attributes();
		attri.set( "id" ,"viewTable" );		// 3.6.0.5 (2004/10/18)
		attri.set( "summary"	 ,"layout"	  );			// サマリー

//		// 4.0.0 (2005/08/31) テーブル表示の CSSファイル利用の有無
//		boolean useCSSfile = HybsSystem.sysBool( "USE_HTML_TABLE_CSS" ) ;
//
//		if( ! useCSSfile ) {
//			attri.set( "summary"	 ,"layout"	  );			// サマリー
//			attri.set( "border" 	 ,HybsSystem.sys( "HTML_BORDER" ) ) ;     // 外枠の太さ
//			attri.set( "width"		 ,HybsSystem.sys( "HTML_WIDTH" )  ) ;     // 表の大きさ(幅)ピクセルまたは,％
//			attri.set( "frame"		 ,HybsSystem.sys( "HTML_FRAME" )  ) ;     // 外枠の表示形式  void,above,below,lhs,rhs,hsides,vsides,box,border
//			attri.set( "rules"		 ,HybsSystem.sys( "HTML_RULES" )  ) ;     // セルを区切る線の形式 none,rows,cols,groups,all
//			attri.set( "cellspacing" ,HybsSystem.sys( "HTML_CELLSPACING" ) );  // セルの間隔
//			attri.set( "cellpadding" ,HybsSystem.sys( "HTML_CELLPADDING" ) );  // セル内のマージン
//		}

		return attri.getAttribute();
	}
}
