/* JFox, the OpenSource J2EE Application Server
 *
 * Distributable under GNU LGPL license by gun.org
 * more details please visit http://www.huihoo.org/jfox
 */

package org.jfox.jdbc.datasource;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
import javax.sql.DataSource;

import org.jfox.system.AbstractComponent;

/**
 * @author <a href="mailto:kelvin_wym@hotmail.com">Kelvin Wu</a>
 */
public class PoolDataSource extends AbstractComponent implements DataSource, Referenceable {
    protected ConnectionPool pool = null; // The connection pool used the get connections.
    private String dbDriver; // database driver class name.
    private String dbURL; // database url
    private String user; // database user
    private String password; //database password
    private int initNum = 2;
    private int maxRest = 10;

    private String dsName;


    /**
     * Constructor specify database connection parameters to generate a valid and usable datasource.
     *
     * @param dbDriver database class name according your dabase
     * @param dbURL    database url used to access database
     * @param user     valid database user
     * @param password // corresponding database password
     * @throws Exception any exception who cares?
     */
    public PoolDataSource(String dsName, String dbDriver, String dbURL, String user, String password) throws Exception {
        this.dsName = dsName;
        this.dbDriver = dbDriver;
        this.dbURL = dbURL;
        this.user = user;
        this.password = password;
    }

    /**
     * Get usable connection from datasource
     *
     * @return Connection the valid database connection can used by user
     * @throws SQLException
     */
    public Connection getConnection() throws SQLException {
        // since the pool.getConnection() throws out exception, so I have to catch it.
        // Please Young consider about the excpetion handler meshiasm.
        try {
            return pool.getConnection();
        }
        catch(SQLException sqle) {
            throw sqle;
        }
        catch(Exception e) {
            e.printStackTrace();
            throw new SQLException(e.getMessage());
        }
    }

    /**
     * Get connection by specific user name and password, the connection is not pooled by
     * Connection Pool
     *
     * @param username
     * @param password
     * @return
     * @throws SQLException
     */
    public Connection getConnection(String username, String password)
            throws SQLException {
        return DriverManager.getConnection(dbURL, username, password);

    }

    /**
     * Get logger writer
     *
     * @return
     * @throws SQLException
     */
    public PrintWriter getLogWriter() throws SQLException {
        return DriverManager.getLogWriter();
    }

    /**
     * @param out
     * @throws SQLException
     */
    public void setLogWriter(PrintWriter out) throws SQLException {
        DriverManager.setLogWriter(out);
    }

    /**
     * @param seconds
     * @throws SQLException
     */
    public void setLoginTimeout(int seconds) throws SQLException {
        DriverManager.setLoginTimeout(seconds);
    }

    /**
     * @return
     * @throws SQLException
     */
    public int getLoginTimeout() throws SQLException {
        return DriverManager.getLoginTimeout();
    }

    /**
     * Method that inherited from Referenceable.
     *
     * @return
     * @throws javax.naming.NamingException
     */
    public Reference getReference() throws NamingException {
        Reference ref = new Reference(getClass().getName(), DataSourceObjectFactory.class.getName(), null);
        ref.add(new StringRefAddr("dsName", dsName));
        ref.add(new StringRefAddr("dbDriver", dbDriver));
        ref.add(new StringRefAddr("dbURL", dbURL));
        ref.add(new StringRefAddr("user", user));
        ref.add(new StringRefAddr("password", password));
        ref.add(new StringRefAddr("initNum", "" + initNum));
        ref.add(new StringRefAddr("maxRest", "" + maxRest));
        return ref;
    }

    public String getDbDriver() {
        return dbDriver;
    }

    public String getDbURL() {
        return dbURL;
    }

    public String getUser() {
        return user;
    }

    public String getPassword() {
        return password;
    }

    public int getMaxRest() {
        return maxRest;
    }

    public int getInitNum() {
        return initNum;
    }

    public void setInitNum(int initNum) {
        this.initNum = initNum;
    }

    public void setMaxRest(int maxRest) {
        this.maxRest = maxRest;
    }

    protected void doInit() throws Exception {
        pool = new ConnectionPool(dbDriver, dbURL, user, password);
        pool.setInitNum(initNum);
        pool.setMaxRest(maxRest);
        pool.init();
    }

    public String getDsName() {
        return dsName;
    }

    protected void doDestroy() throws Exception {
        pool.destroy();
        DataSourceObjectFactory.removeDataSource(dsName);
    }
}
