/*
 * Copyright (c) 2003, Morpho Project.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *	  this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *	  this list of conditions and the following disclaimer in the documentation
 *	  and/or other materials provided with the distribution.
 * 3. Neither the name of the Morpho Project nor the names of its contributors
 *	  may be used to endorse or promote products derived from this software
 *	  without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package jp.morpho.webapp.action.impl;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * <P>
 * このクラスは、要求を受け取るサーブレットのパスのエントリを表します。
 * サーブレットが要求を受け取った際に、任意のアクションマッピングが選択されるようにするために、アクションマッピングマネージャにこのエントリを追加します。
 * </P>
 * <P>
 * サーブレットが要求を受け取った際に、任意のアクションマッピングが選択されるようにするために、2 つのメソッド  addActionHandlerEntry(ActionHandlerEntry) 、addActionViewEntry(ActionViewEntry) を使用してエントリを追加する必要があります。
 * 前者は要求を処理するアクションハンドラのエントリを追加し、後者は要求を処理した後に表示する画面を表すアクションビューのエントリを追加します。
 * </P>
 * <P>
 * setServletPath(String) メソッドで指定するサーブレットの URL は、web.xml において配置したサーブレットの URL  です。
 * </P>
 * @author Kumiko Hiroi
 */
public class ActionServletPath
	implements Serializable
{
	/** null のアクションマッピングが対応する URL */
	private static final String NULL_SERVLETPATH = "";

	/** null のステータスの値 */
	private static final String NULL_STATUS = "";

	/** null のアクションの値 */
	private static final String NULL_ACTION = "";

	/** アクションマッピングが対応する URL */
	private String servletPath = null;

	/** アクションハンドラエントリのマップ */
	private Map actionHandlerEntries = new HashMap();

	/** アクションビューエントリのマップ */
	private Map actionViewEntries = new HashMap();

	/**
	 * <P>
	 * ActionServletPath を作成します。
	 * </P>
	 */
	public ActionServletPath()
	{
		super();
	}

	/**
	 * <P>
	 * アクションマッピングが対応するサーブレットの URL を取得します。
	 * </P>
	 * @return アクションマッピングが対応するサーブレットの URL
	 */
	public synchronized String getServletPath()
	{
		return (servletPath != null) ? servletPath : NULL_SERVLETPATH;
	}

	/**
	 * <P>
	 * アクションマッピングが対応するサーブレットの URL を設定します。
	 * </P>
	 * @param servletPath アクションマッピングが対応するサーブレットの URL
	 */
	public synchronized void setServletPath(String servletPath)
	{
		this.servletPath = servletPath;
	}

	/**
	 * <P>
	 * すでに同じキーのアクションハンドラエントリが追加されているかどうかを判定します。
	 * アクションハンドラエントリのマップが指定のキーのマッピングを保持する場合、例外 IllegalArgumentException をスローします。
	 * </P>
	 * @param key マップにあるかどうかが判定されるキー
	 * @exception IllegalArgumentException アクションハンドラエントリのマップが指定のキーのマッピングを保持している場合
	 */
	private synchronized void checkActionHandlerMapping(String key)
	{
		if (actionHandlerEntries.containsKey(key))
		{
			throw new IllegalArgumentException("ActionHandlerEntry Mapping Key already exists: " + key);
		}
	}

	/**
	 * <P>
	 * すでに同じキーのアクションビューエントリが追加されているかどうかを判定します。
	 * アクションビューエントリのマップが指定のキーのマッピングを保持する場合、例外 IllegalArgumentException をスローします。
	 * </P>
	 * @param key マップにあるかどうかが判定されるキー
	 * @exception IllegalArgumentException アクションビューエントリのマップが指定のキーのマッピングを保持している場合
	 */
	private synchronized void checkActionViewMapping(String key)
	{
		if (this.actionViewEntries.containsKey(key))
		{
			throw new IllegalArgumentException("ActionViewEntry Mapping Key already exists: " + key);
		}
	}

	/**
	 * <P>
	 * 指定されたアクションハンドラエントリを追加します。
	 * </P>
	 * @param entry 追加するアクションハンドラエントリ
	 */
	public synchronized void addActionHandlerEntry(
		ActionHandlerEntry entry)
	{
		String key = generateActionHandlerMappingKey(entry.getStatus(), entry.getAction());
		checkActionHandlerMapping(key);
		actionHandlerEntries.put(key, entry);
	}

	/**
	 * <P>
	 * アクションハンドラエントリを取得します。
	 * </P>
	 * @param status 要求を処理するステータスの値
	 * @param action 要求を処理するアクションの値
	 * @return アクションハンドラエントリ。それがない場合は null
	 */
	public synchronized ActionHandlerEntry getActionHandlerEntry(
		String status, String action)
	{
		return (ActionHandlerEntry)actionHandlerEntries.get(generateActionHandlerMappingKey(status, action));
	}

	/**
	 * <P>
	 * 指定されたアクションビューエントリを追加します。
	 * </P>
	 * @param entry 追加するアクションビューエントリ
	 */
	public synchronized void addActionViewEntry(
		ActionViewEntry entry)
	{
		String key = generateActionViewMappingKey(entry.getStatus());
		checkActionViewMapping(key);
		actionViewEntries.put(key, entry);
	}

	/**
	 * <P>
	 * アクションビューエントリを取得します。
	 * </P>
	 * @param status 要求を処理するステータスの値
	 * @return アクションビューエントリ。それがない場合は null
	 */
	public synchronized ActionViewEntry getActionViewEntry(String status)
	{
		return (ActionViewEntry)actionViewEntries.get(generateActionViewMappingKey(status));
	}

	/**
	 * <P>
	 * アクションハンドラエントリをマップオブジェクトに関連付けるためのキーを作成します。
	 * </P>
	 * <P>
	 * これは次のようなキーを作成します。
	 * <CODE>
	 * ActionHandlerEntry[status=<I>ステータスの値</I>,action=<I>アクションの値</I>]
	 * </CODE>
	 * </P>
	 * @param status 要求を処理するステータスの値
	 * @param action 要求を処理するアクションの値
	 * @return アクションハンドラエントリのキー
	 */
	public synchronized String generateActionHandlerMappingKey(String status, String action)
	{
		StringBuffer buf = new StringBuffer();
		buf.append("ActionHandlerEntry[");
		buf.append("status=").append((status != null) ? status : NULL_STATUS);
		buf.append(",");
		buf.append("action=").append((action != null) ? action : NULL_ACTION);
		buf.append("]");

		return buf.toString();
	}

	/**
	 * <P>
	 * アクションビューエントリをマップオブジェクトに関連付けるためのキーを作成します。
	 * </P>
	 * <P>
	 * これは次のようなキーを作成します。
	 * <CODE>
	 * ActionViewEntry[status=<I>ステータスの値</I>]
	 * </CODE>
	 * </P>
	 * @param status 要求を処理するステータスの値
	 * @return アクションビューエントリのキー
	 */
	public synchronized String generateActionViewMappingKey(String status)
	{
		StringBuffer buf = new StringBuffer();
		buf.append("ActionViewEntry[");
		buf.append("status=").append((status != null) ? status : NULL_STATUS);
		buf.append("]");

		return buf.toString();
	}

}
