package org.maachang.session.engine ;

import java.io.IOException;

import org.maachang.dbm.MDbmIO;
import org.maachang.dbm.MDbmOp;

/**
 * 永続化セッション管理オブジェクト.
 * 
 * @version 2008/05/25
 * @author masahito suzuki
 * @since PersistenceSession 1.00
 */
class PersistenceEngineImpl implements PersistenceEngine {
    
    /**
     * 生成待機カウント.
     */
    private static final int WAIT_LOOP = 25 ;
    
    /**
     * 生成待機時間.
     */
    private static final int WAIT_TIME = 100 ;
    
    /**
     * セッションキャッシュ管理情報.
     */
    private SessionCache sessionCache = null ;
    
    /**
     * セッションID生成管理情報.
     */
    private CreateSession createSession = null ;
    
    /**
     * コンストラクタ.
     */
    private PersistenceEngineImpl() {
        
    }
    
    /**
     * コンストラクタ.
     * @param mdbm セッション管理用MDBMを設定します.
     * @param cacheTimeout キャッシュタイムアウト値を設定します.
     * @param sessionTimeout セッションタイムアウト値を設定します.
     * @exception Exception 例外.
     */
    public PersistenceEngineImpl( MDbmOp mdbm,int cacheTimeout,int sessionTimeout )
        throws Exception {
        if( mdbm == null || mdbm.isUse() == false ||
            ( mdbm.maachangDbm() instanceof MDbmIO ) == false ) {
            if( mdbm == null || mdbm.isUse() == false ) {
                throw new IllegalArgumentException( "指定されたMDbmは不正です" ) ;
            }
            throw new IllegalArgumentException( "MDbmはRemote及びTransactionでは扱えません" ) ;
        }
        SessionCache sessionCache = new SessionCache( mdbm,cacheTimeout,sessionTimeout ) ;
        if( sessionCache.isUse() == false ) {
            boolean flg = false ;
            for( int i = 0 ; i < WAIT_LOOP ; i ++ ) {
                if( sessionCache.isUse() == true ) {
                    flg = true ;
                    break ;
                }
                try { Thread.sleep( WAIT_TIME ) ; } catch( Exception e ) {}
            }
            if( flg == false ) {
                throw new IOException( "生成に失敗しました" ) ;
            }
        }
        CreateSession createSession = new CreateSession( sessionCache ) ;
        this.sessionCache = sessionCache ;
        this.createSession = createSession ;
    }
    
    /**
     * デストラクタ.
     */
    protected void finalize() throws Exception {
        destroy() ;
    }
    
    /**
     * オブジェクトを破棄します.
     */
    public void destroy() {
        if( createSession != null ) {
            createSession.destroy() ;
        }
        createSession = null ;
        if( sessionCache != null ) {
            sessionCache.destroy() ;
        }
        sessionCache = null ;
    }
    
    /**
     * 新しいセッションキーを生成.
     * @return String 新しいSessionKeyが返されます.
     * @exception Exception 例外.
     */
    public String createSessionId()
        throws Exception {
        if( isUse() == false ) {
            throw new IOException( "オブジェクトは無効な状態です" ) ;
        }
        return createSession.createSessionKey() ;
    }
    
    /**
     * セッションに１つの要素を設定.
     * @param sessionId 対象のセッションIDを設定します.
     * @param key 対象のKeyを設定します.
     * @param value 対象の要素を設定します.
     * @exception Exception 例外.
     */
    public void put( String sessionId,String key,byte[] value )
        throws Exception {
        if( isUse() == false ) {
            throw new IOException( "オブジェクトは無効な状態です" ) ;
        }
        sessionCache.put( sessionId,key,value ) ;
    }
    
    /**
     * セッションを削除.
     * @param sessionId 対象のセッションIDを設定します.
     * @exception Exception 例外.
     */
    public void remove( String sessionId ) throws Exception {
        if( isUse() == false ) {
            throw new IOException( "オブジェクトは無効な状態です" ) ;
        }
        sessionCache.remove( sessionId ) ;
    }
    
    /**
     * セッションから１つの要素を削除.
     * @param sessionId 対象のセッションIDを設定します.
     * @param key 対象のKeyを設定します.
     * @exception Exception 例外.
     */
    public void remove( String sessionId,String key )
        throws Exception {
        if( isUse() == false ) {
            throw new IOException( "オブジェクトは無効な状態です" ) ;
        }
        sessionCache.remove( sessionId,key ) ;
    }
    
    /**
     * セッションから１つの要素を取得.
     * @param sessionId 対象のセッションIDを設定します.
     * @param key 対象のKeyを設定します.
     * @return byte[] １つの要素が返されます.
     * @exception Exception 例外.
     */
    public byte[] get( String sessionId,String key )
        throws Exception {
        if( isUse() == false ) {
            throw new IOException( "オブジェクトは無効な状態です" ) ;
        }
        return sessionCache.get( sessionId,key ) ;
    }
    
    /**
     * 指定セッション更新時間を取得.
     * @param sessionId 対象のセッションIDを設定します.
     * @return long 対象の更新時間が返されます.
     * @exception Exception 例外.
     */
    public long getLastUpdateTime( String sessionId ) throws Exception {
        if( isUse() == false ) {
            throw new IOException( "オブジェクトは無効な状態です" ) ;
        }
        return sessionCache.getLastUpdateTime( sessionId ) ;
    }
    
    /**
     * 指定セッション情報が存在するかチェック.
     * @param sessionId 対象のセッションIDを設定します.
     * @return boolean [true]の場合、セッションIDは存在します.
     */
    public boolean containsKey( String sessionId ) {
        if( isUse() == false ) {
            return false ;
        }
        boolean ret = false ;
        if( ( ret = sessionCache.containsKey( sessionId ) ) == false ) {
            return createSession.containsKey( sessionId ) ;
        }
        return ret ;
    }
    
    /**
     * MDBMオブジェクトを取得.
     * @return MDbmOp MDBMオブジェクトが返されます.
     */
    public MDbmOp getMDbm() {
        return ( isUse() ) ? sessionCache.getMDbm() : null ;
    }
    
    /**
     * セッション削除時間を取得.
     * @return long セッション削除時間が返されます.
     */
    public long getDeleteSessionTime() {
        if( isUse() == false ) {
            return -1L ;
        }
        return sessionCache.getDeleteSessionTime() ;
    }
    
    /**
     * このオブジェクトが有効かチェック.
     * @return boolean [true]が返された場合、オブジェクトは有効です.
     */
    public boolean isUse() {
        return ( sessionCache == null || createSession == null || createSession.isUse() == false ) ?
            false : true ;
    }
}

