/**
 * LOGICAL-PARADOX.ORG
 * Copyright (C)2004 satoshi akabane(akabane@logical-paradox.org)
 *
 */
package org.logical_paradox.common.session;

import org.logical_paradox.common.util.AttributeChangeListener;
import org.logical_paradox.common.util.DateTime;
import org.logical_paradox.common.util.ObservableAttribute;

/**
 * セッションオブジェクト
 * @author satoshi akabane@logical-paradox.org
 * @version $Revision: 1.2 $
 */
public class Session implements ObservableAttribute {
	/** セッションオブジェクトのデフォルト生存期間(20分) */
	public static final long DEFAULT_SESSION_LIFETIME = 1000*20;

	/** セッションの生成と破棄のタイミングで呼び出されます */
	private SessionBindingListener listener;
	/** このセッションの有効期限 */
	private long expireDateTime;
	/** セッションの生存期間(msec) デフォルト20分 */
	private long lifetime = DEFAULT_SESSION_LIFETIME;
	/** セッションID */
	private final String sessionId;
	/** このセッションに固有のコンテキスト */
	private SessionContext context = new SessionContext();

	/** 現在日時管理ユーティリティ */
	private DateTime datetime = DateTime.getInstance();
	
	/** セッションの状態 */
	private boolean available = true;

	/**
	 * コンストラクタ
	 * @param sid セッションID
	 */
	Session(String sid) throws IllegalSessionStateException {
		sessionId = sid;
		touch();
	}
	/**
	 * コンストラクタ
	 * @param sid セッションID
	 * @param itv セッションの有効期限(msec)
	 */
	Session(String sid, long itv) throws IllegalSessionStateException {
		this(sid);
		lifetime = itv;
		touch();
	}
	/**
	 * このセッションのセッションIDを返す
	 * @return セッションID
	 */
	public String getSessionId() {
		return sessionId;
	}
	/**
	 * セッション追加/破棄時のリスナーを登録する
	 * @param lsnr リスナー
	 */
	public void setSessionBindingListener(SessionBindingListener lsnr) throws IllegalSessionStateException {
		checkSessionState();
		listener = lsnr;
	}
	/**
	 * セッション追加/破棄時のリスナーを登録する
	 */
	public void removeSessionBindingListener() throws IllegalSessionStateException {
		checkSessionState();
		listener = null;
	}
	/**
	 * セッションがセッションマネージャーからアンバウンドされた際に呼び出されます
	 */
	void unbound() {
		if(listener != null) {
			listener.onUnBound();
		}
		// このセッションの状態を無効にする
		available = false;
	}
	/**
	 * セッションの状態が有効かどうかを検査する
	 * @throws IllegalSessionStateException セッションが有効でなくなった
	 */
	private void checkSessionState() throws IllegalSessionStateException {
		if(available == false) {
			throw new IllegalSessionStateException("セッションは既に有効でなくなりました");
		}
	}
	/**
	 * セッションの有効期限がきれていないかどうかを返す
	 * @return true: 期限内 / false:期限切れ
	 */
	public boolean isActive() {
		return datetime.currentTimeInMillis() <= expireDateTime;
	}
	/**
	 * このセッションの有効期限を延長する
	 * 通常、セッションコンテキストに対するアクセサから呼ばれる
	 */
	void touch() throws IllegalSessionStateException {
		checkSessionState();
		expireDateTime = datetime.currentTimeInMillis() + lifetime;
	}
	/**
	 * 当該セッションが有効かどうかを設定する
	 * @param state true:有効 / false:無効
	 */
	void setSessionState(boolean state) throws IllegalSessionStateException {
		checkSessionState();
		available = state;
	}
	/**
	 * 当該セッションが有効かどうかを返す
	 * @return true:有効 / false:無効
	 */
	public boolean getSessionState() throws IllegalSessionStateException {
		checkSessionState();
		return available;
	}
	/**
	 * このセッションのコンテキストに対して属性変更リスナーを登録する
	 * @param key 属性
	 * @param lsnr 属性変更リスナー
	 */
	public void setAttributeChangeListener(String key, AttributeChangeListener lsnr) {
		context.setAttribute(key, lsnr);
	}
	/**
	 * このセッションのコンテキストから属性変更リスナーを削除する
	 * @param key 属性
	 */
	public void removeAttributeChangeListener(String key) {
		context.removeAttributeChangeListener(key);
	}
	/**
	 * このセッションのコンテキストから属性値を取得する
	 * @param key 属性
	 * @return 属性値
	 */
	public Object getAttribute(String key) throws IllegalSessionStateException {
		touch();
		return context.getAttribute(key);
	}
	/**
	 * このセッションのコンテキストに対して属性値を設定する
	 * @param key 属性
	 * @param o 属性値
	 */
	public void setAttribute(String key, Object o) throws IllegalSessionStateException {
		touch();
		context.setAttribute(key, o);
	}
	/**
	 * このセッションのコンテキストから属性値を取り除く
	 * @param  key 属性
	 */
	public void removeAttribute(String key) throws IllegalSessionStateException {
		touch();
		context.removeAttribute(key);
	}
}
