/*
このファイルの中身は、NTT オープンソースライセンス　バージョン 1.0（「本
契約」という）の適用を受けます。
本契約を遵守しない限り、このファイルを使用してはなりません。
本契約のコピーは、次のＵＲＬから入手できます。
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

本契約に基づき頒布されるソフトウェアは、現状のまま、明示又は黙示のあらゆ
る種類の保証なしで、頒布されます。本契約に基づく権利及び制限を律する特定
の文言については、本契約を参照してください。

「オリジナルコード」は、 NTT Cyber Space Laboratories Code です。 
「オリジナルコード」の「初期開発者」は、日本電信電話株式会社です。  
日本電信電話株式会社により創作された部分は、Copyright (C) 2004 
日本電信電話株式会社 です。
全ての権利が留保されます。 
「コントリビュータ」：_____________________________________ 


The contents of this file are subject to the NTT Opensource License
Version 1.0 (the License); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

Software distributed under the License is distributed on an AS IS
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.

The Original Code is NTT Cyber Space Laboratories Code .

The Initial Developer of the Original Code is NIPPON TELEGRAPH AND 
TELEPHONE CORPORATION.
Portions created by the NIPPON TELEGRAPH AND TELEPHONE CORPORATION 
are Copyright (C) 2004 NIPPON TELEGRAPH AND TELEPHONE CORPORATION. 
All Rights Reserved.

Contributor(s) ______________________________________.
*/

//
// 業務振分定義ＸＭＬ対応クラス
//
//
//	変更履歴
//	2004/01/08 新規作成	T.Nishiki
//
package jp.co.ntt.lms.xms.framework;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import jp.co.ntt.lms.xmo.util.DebugLog;
import jp.co.ntt.lms.xms.common.util.StringUtil;
import jp.co.ntt.lms.xms.common.util.XmlUtil;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
 * 業務振分定義ＸＭＬ対応クラス。<br>
 * @author T.Nishiki
 */
public class XmsBusinessXMLPerser {

	/**
	 * 業務XML定義情報Document。
	 */
	private static Document DOCUMENT;

	/**
	 * 画面XML定義共通プロパティ・マップ。
	 */
	private static Map COMMON_PROPERTIES;

	/**
	 *  <common><property>ノードのパス。
	 */
	private static final String PATH_NODE_COMMON_PROPERTY
		= "root/common/property";

	/**
	 *  <common><property>ノードのname属性。
	 */
	private static final String NODE_COMMON_PROPERTY_ATTR_NAME = "name";

	/**
	 *  <common><property>ノードのvalue属性。
	 */
	private static final String NODE_COMMON_PROPERTY_ATTR_VALUE = "value";

	/**
	 *  プロパティ名称：共通デフォルト・エンコード。
	 */
	private static final String NODE_COMMON_PROPERTY_ENCODING = "encoding";

	/**
	 * 業務XML定義ファイルのパス。
	 */
	private static final String BUSINESS_XMLFILE_PATH
		= "/conf/xms/XmsBusinessDefine.xml";

	/**
	 *  <action>ノードのパス。
	 */
	private static final String PATH_NODE_ACTION
		= "root/action";

	/**
	 *  <action>ノードのname属性。
	 */
	private static final String NODE_ACTION_ATTR_NAME = "name";

	/**
	 *  <action>ノードのclass属性。
	 */
	private static final String NODE_ACTION_ATTR_CLASS = "class";

	/**
	 *  <action>ノードのencoding属性。
	 */
	private static final String NODE_ACTION_ATTR_ENCODING = "encoding";

	/**
	 *  <permision>ノード。
	 */
	private static final String NODE_PERMISSON = "permission/text()";

	/**
	 * 共通デフォルト・エンコード。
	 */
	private static String DEFAULT_ENCODING;

	/**
	 * 更新業務用アクションクラス名を取得する。<br>
	 * 更新業務振分定義ファイルから、指定したアクションIDに対応する
	 * アクションクラス名を取得し、戻す。<br>
	 * @param actionId アクションID。
	 * @return 指定したアクションIDに対応するクラス名。
	 *
	 * @throws XmsException 処理中に例外が発生した場合。
	 */
	static String getBusinessActionName(String actionId) throws XmsException {
		String actionName = null;
		Node actionNode = null;
		try {
			// <action>ノード取得。
			actionNode = getActionNode(actionId);
			// <action>ノードから、class属性を取得
			actionName =
				XmlUtil.getAttributeValue(actionNode, NODE_ACTION_ATTR_CLASS);
		}
		catch (XmsException e) {
			throw e;
		}
		catch (Exception e) {
			throw new XmsSystemException(e);
		}
		return actionName;
	}

	/**
	 * 指定したアクションIDに対応する許可リストを戻す。<br>
	 * 更新業務振分定義ファイルから、指定したアクションIDに対応する
	 * &lt;action&gt;ノードを取得する。
	 * その子要素の&lt;permission&gt;ノードのテキスト部分をリスト化して戻す。
	 * その子要素の&lt;permission&gt;がない場合、空リストを戻す。
	 * @param actionId 許可設定を確認するアクションID。
	 * @return アクションIDに対応する許可リスト。
	 * @throws XmsException 処理中に例外が発生した場合。
	 */
	static List getPermittedList(String actionId) throws XmsException {
		List permittedList = null;
		Node actionNode = null;
		Node[] permissionNodes = null;
		Node permissionNode = null;
		String permissionText = null;
		try {
			// <action>ノード取得。
			actionNode = getActionNode(actionId);
			// <permision>ノードを取得
			permissionNodes = XmlUtil.selectNodes(actionNode, NODE_PERMISSON);
			permittedList = new ArrayList();
			// 取得したTEXTノードから１つ１つテキスト部分を取得。
			for (int i = 0; i < permissionNodes.length; i++) {
				permissionNode = permissionNodes[i];
				permissionText = permissionNode.getNodeValue();
				if (StringUtil.isNullString(permissionText) == false) {
					permittedList.add(permissionText);
				}

			}

		}
		catch (XmsException e) {
			throw e;
		}
		catch (Exception e) {
			throw new XmsSystemException(e);
		}
		return permittedList;
	}

	/**
	 * 指定したアクションIDに対応するアクションのエンコードを取得する。<br>
	 * 指定したIDと一致する&lt;action&gt;を取得し、encoding属性を取得する。
	 * encoding属性を取得できない場合は、共通属性として
	 * &lt;var name=&quot;encoding&quot; /&gt;要素のvalue属性で
	 * 指定した値を戻す。<br>
	 * 共通属性も指定がない場合は、nullを戻す。<br>
	 *
	 * @param actionId アクションID。
	 * @return 指定したアクションIDに対応するエンコード。
	 *
	 * @throws XmsException 処理中に例外が発生した場合。
	 */
	static String getActionEncoding(String actionId) throws XmsException {

		String encoding = null;
		try {
			Node actionNode = getActionNode(actionId);
			if (actionNode != null) {
				encoding = XmlUtil.getAttributeValue(
								actionNode, NODE_ACTION_ATTR_ENCODING);
			}
			if (StringUtil.isNullString(encoding) == true) {
				encoding = DEFAULT_ENCODING;
			}
		}
		catch (XmsException e) {
			throw e;
		}
		catch (Exception e) {
			throw new XmsSystemException(e);
		}
		return encoding;
	}

	/**
	 * 指定したアクションIDに合致する&lt;action&gt;ノードを戻す。<br>
	 * @param actionId 検索キーとなるアクションID。
	 * @return 指定したアクションIDに合致する&lt;action&gt;ノードがあれば、
	 *          そのノード、なければnullを戻す。
	 * @throws XmsException 処理中に例外が発生した場合。
	 */
	private static Node getActionNode(String actionId) throws XmsException {
		// <action>ノードの集合
		Node[] actionNodes = null;
		// このメソッドの戻り値。
		Node returnNode = null;
		try {
			// <action>ノードを取得
			actionNodes = XmlUtil.selectNodes(getDocument(), PATH_NODE_ACTION);
			// NAME属性値が指定したアクションIDと一致するノードを選択
			returnNode =
				XmlUtil.searchNodeByAttribute(
					actionNodes,
					NODE_ACTION_ATTR_NAME,
					actionId);
		}
		catch (XmsException e) {
			throw e;
		}
		catch (Exception e) {
			throw new XmsSystemException(e);
		}
		return returnNode;
	}

	/**
	 * ＤＯＭデータの初期化。<br>
	 * @throws XmsException 処理中に例外が発生した場合。
	 */
	private static synchronized void initializeDocument()
			throws XmsException {
		DebugLog.write(
			XmsBusinessXMLPerser.class,
			"HEAD initializeDocument()",
			DebugLog.ROW);
		// 変換用ビルダ・ファクトリ
		DocumentBuilderFactory dbf = null;
		// 変換用ビルダ
		DocumentBuilder db = null;
		// 定義ファイルの入力ストリーム
		InputStream in = null;
		// 例外発生フラグ（tryブロック内）
		boolean exceptionFlag = true;

		try {
			dbf = DocumentBuilderFactory.newInstance();
			// XMLファイル内の空白を排除します
			dbf.setIgnoringElementContentWhitespace(true);
			// XMLファイル内のコメントを無視します
			dbf.setIgnoringComments(true);

			db = dbf.newDocumentBuilder();
			in = (XmsBusinessXMLPerser.class).getResourceAsStream(
					BUSINESS_XMLFILE_PATH);
			// ファイルからDOMに変換
			DOCUMENT = db.parse(in);
			DebugLog.write(XmsBusinessXMLPerser.class,
					"DOCUMENT==null:" + (DOCUMENT == null), DebugLog.HIGHT);

			// tryブロック内で例外が発生していない
			exceptionFlag = false;
		}
		catch (Exception e) {
			DebugLog.write(XmsBusinessXMLPerser.class, e, DebugLog.HIGHT);
			throw new XmsSystemException(e);
		}
		finally {
			// InputStreamのクローズ
			try {
				if ( in != null ) {
					in.close();
				}
			}
			catch (Exception e) {
				DebugLog.write(XmsBusinessXMLPerser.class, e, DebugLog.HIGHT);
				// tryブロック内で例外が発生していない場合、スロー
				if ( exceptionFlag == false ) {
					throw new XmsSystemException( e );
				}
			}
			finally {
				in = null;

				DebugLog.write(
					XmsBusinessXMLPerser.class,
					"TAIL initializeDocument()",
					DebugLog.ROW);
			}
		}
	}

	/**
	 * 共通プロパティを定義ファイルより取得する。<br>
	 * @throws XmsException 処理中に例外が発生した場合。
	 */
	private static synchronized void initializeCommons()
			throws XmsException {
		DebugLog.write( XmsBusinessXMLPerser.class,
			"HEAD initializeCommons()", DebugLog.ROW);
		try {
			////////////////////////////////////////////////////////////////////
			// プロパティ取得
			// -----------------------------------------------------------------
			// <var>ノードを取得
			Node[] varNodes = null;
			String varName = null;
			String varValue = null;
			COMMON_PROPERTIES = new HashMap();
			varNodes =
				XmlUtil.selectNodes(getDocument(), PATH_NODE_COMMON_PROPERTY);
			for (int i = 0; i < varNodes.length; i++) {
				varName =
					XmlUtil.getAttributeValue(
						varNodes[i],
						NODE_COMMON_PROPERTY_ATTR_NAME);
				varValue =
					XmlUtil.getAttributeValue(
						varNodes[i],
						NODE_COMMON_PROPERTY_ATTR_VALUE);
				DebugLog.write( XmsBusinessXMLPerser.class,
					"varName=[" + varName + "]", DebugLog.ROW);
				DebugLog.write( XmsBusinessXMLPerser.class,
					"varValue=[" + varValue + "]", DebugLog.ROW);

				if ((varName != null) && (varValue != null)) {
					COMMON_PROPERTIES.put(varName, varValue);
				}
			}

			// デフォルト・エンコード
			DEFAULT_ENCODING =
				(String)COMMON_PROPERTIES.get(NODE_COMMON_PROPERTY_ENCODING);
		}
		catch (XmsException e) {
			DebugLog.write(XmsBusinessXMLPerser.class, e, DebugLog.HIGHT);
			throw e;
		}
		catch (Exception e) {
			DebugLog.write(XmsBusinessXMLPerser.class, e, DebugLog.HIGHT);
			throw new XmsSystemException(e);
		}
		finally {
			DebugLog.write( XmsBusinessXMLPerser.class,
				"TAIL initializeCommons()", DebugLog.ROW);
		}
	}

	/**
	 * 画面振分定義ＸＭＬ−ＤＯＭを返却する。<br>
	 * @return Document 画面振分定義ＸＭＬ。
	 * @throws XmsException 処理中に例外が発生した場合。
	 */
	private static synchronized Document getDocument()
			throws XmsException {
		if (DOCUMENT == null) {
			initializeDocument();
			initializeCommons();
		}
		return DOCUMENT;
	}
}
