package org.maachang.dbm.service ;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.maachang.conf.Config;
import org.maachang.conf.ReadIni;
import org.maachang.dbm.MDbmManager;
import org.maachang.dbm.engine.MDbmDefine;
import org.maachang.shutdown.ShutdownCallback;
import org.maachang.shutdown.ShutdownHook;
import org.maachang.shutdown.WaitShutdown;

/**
 * MDbmServer起動用オブジェクト.
 * <BR><BR>
 * MaachangDBMをサーバモードで起動させるためには、次の点を設定する必要があります.<BR>
 * <BR>
 * &nbsp;&nbsp;
 * 1.環境変数[JAVA_HOME]を設定する.<BR>
 * &nbsp;&nbsp;
 * 2.環境変数[MAACHANG_DBM]を設定する.<BR>
 * &nbsp;&nbsp;
 * 3.環境変数[PATH]に、${MAACHANG_DBM]/shを設定する.<BR>
 * &nbsp;&nbsp;
 * 4.MaachangDBMコンフィグを設定する.<BR>
 * <BR>
 * 最初に環境変数[JAVA_HOME]を設定します.<BR>
 * <BR>
 * <div style="border:1px solid gray; padding:5px;">
 * <pre>
 * 例：javaインストールディレクトリ名 = /var/java/jdk1.6.0_03
 * JAVA_HOME=/var/java/jdk1.6.0_03
 * export JAVA_HOME
 * 
 * </pre>
 * </div>
 * <BR>
 * 次に環境変数[MAACHANG_DBM]を設定します.<BR>
 * その前に、MaachangDBM-x.xx.zipを解凍し、解凍先のディレクトリ/binに環境変数を適応させます.<BR>
 * <BR>
 * <div style="border:1px solid gray; padding:5px;">
 * <pre>
 * 例：MaachangDBM解凍先ディレクトリ名 = /var/MaachangDBM-x.xx
 * MAACHANG_DBM=/var/MaachangDBM-x.xx/bin
 * export MAACHANG_DBM
 * 
 * </pre>
 * </div>
 * <BR>
 * 次に環境変数[PATH]に${MAACHANG_DBM]/shを設定します.<BR>
 * <BR>
 * <div style="border:1px solid gray; padding:5px;">
 * <pre>
 * PATH=${PATH}:${MAACHANG_DBM}/sh
 * export PATH
 * 
 * </pre>
 * </div>
 * <BR>
 * 最後に、MaachangDBMのコンフィグ内容を設定します.
 * この内容は、解凍したディレクトリ名[MaachangDBM-x.xx/bin/conf]以下に存在するので、
 * そのファイルを[任意のディレクトリ/conf]にコピーします.<BR>
 * そして、任意のディレクトリに移動して、コマンド[mdbm]を実行することで、MaachangDBMをサーバモードで
 * 起動できます.<BR>
 * <BR>
 * <div style="border:1px solid gray; padding:5px;">
 * <pre>
 * mkdir 任意のディレクトリ
 * mkdir 任意のディレクトリ/conf
 * cp ${MAACHANG_DBM]/conf/mdbm.conf 任意のディレクトリ/conf
 * cd 任意のディレクトリ
 * mdbm
 * 
 * </pre>
 * </div>
 * <BR>
 * また、MaachangDBMをサーバモードで起動させた場合は、
 * org.maachang.dbm.MDbmManagerでMDbmオブジェクトを取得するのではなく、
 * org.maachang.dbm.service.client.MDbmDriverManagerで、MDbmを取得して利用します。
 * 
 * @version 2008/01/20
 * @author masahito suzuki
 * @since MaachangDBM 1.03
 */
public class MDbmServerProcess {
    
    /**
     * LOG.
     */
    private static final Log LOG = LogFactory.getLog( MDbmServerProcess.class ) ;
    
    /**
     * コンフィグファイル名.
     */
    private static final String CONFIG = "conf/mdbm.conf" ;
    
    /**
     * コンストラクタ.
     */
    private MDbmServerProcess() {
        
    }
    
    /**
     * メイン処理.
     * <BR>
     * @param args java引数が設定されます.
     */
    public static final void main( String[] args ) {
        LOG.info( "*** start maachang DBM(version:" +MDbmDefine.VERSION+")." ) ;
        try {
            new MDbmServerProcess().execution( args ) ;
        } catch( Exception e ) {
            e.printStackTrace() ;
        }
        LOG.info( "*** exit maachang DBM." ) ;
    }
    
    /**
     * サーバプロセス実行処理.
     */
    private void execution( String[] args ) throws Exception {
        Config conf = readConfig() ;
        MDbmServerService server = createServer( conf ) ;
        ShutdownHook.registHook( new MDbmShutdown( server ) ) ;
        WaitShutdown waitDown = new WaitShutdown( getShutdownPort( conf ) ) ;
        conf = null ;
        for( ;; ) {
            if( waitDown.isShutdown() ) {
                waitDown.exitShutdown() ;
                break ;
            }
        }
    }
    
    /**
     * コンフィグ内容を取得.
     */
    private static final Config readConfig() throws Exception {
        Config ret = null ;
        BufferedReader r = null ;
        try {
            r = new BufferedReader(
            new InputStreamReader( new FileInputStream( CONFIG ),"UTF8" ) ) ;
            ret = new Config() ;
            ReadIni.analisys( ret,r ) ;
            r.close() ;
            r = null ;
        } finally {
            if( r != null ) {
                try {
                    r.close() ;
                } catch( Exception e ) {
                }
            }
            r = null ;
        }
        return ret ;
    }
    
    /**
     * MDbmServerを生成.
     */
    private static final MDbmServerService createServer( Config conf ) throws Exception {
        String dir = conf.get( "mdbm","directory",0 ) ;
        InetAddress addr = conf.getInetAddress( "mdbm","bind-addr",0 ) ;
        int port = conf.getInt( "mdbm","bind-port",0 ) ;
        int max = conf.getInt( "mdbm","max",0 ) ;
        int pool = conf.getInt( "mdbm","pool",0 ) ;
        if( dir == null || ( dir = dir.trim() ).length() <= 0 ) {
            throw new IOException( "MDBMデータ保存用ディレクトリは不正です" ) ;
        }
        MDbmManager.getInstance().open( dir ) ;
        MDbmServerService ret = new MDbmServerService( addr,port,max,pool ) ;
        return ret ;
    }
    
    /**
     * シャットダウンポートを取得.
     */
    protected static final int getShutdownPort( Config conf ) throws Exception {
        if( conf == null ) {
            conf = readConfig() ;
        }
        return conf.getInt( "mdbm","shutdown-port",0 ) ;
    }
}

/**
 * シャットダウン用コールバック.
 */
class MDbmShutdown extends ShutdownCallback {
    private static final Log LOG = LogFactory.getLog( MDbmShutdown.class ) ;
    private MDbmServerService server = null ;
    public MDbmShutdown( MDbmServerService server ) {
        this.server = server ;
    }
    public void execution() {
        LOG.info( "*** start shutdown .... maachang DBM." ) ;
        if( this.server != null ) {
            this.server.destroy() ;
        }
        LOG.info( "*** exit shutdown .... maachang DBM." ) ;
        MDbmManager.getInstance().close() ;
    }
}

