/* JFox, the OpenSource J2EE Application Server
 *
 * Copyright (C) 2002 huihoo.org
 * Distributable under GNU LGPL license
 * See the GNU Lesser General Public License for more details.
 */

package org.huihoo.jfox.datasource;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.DriverManager;
import java.io.PrintWriter;
import java.util.Hashtable;

import javax.sql.DataSource;
import javax.naming.spi.ObjectFactory;
import javax.naming.Referenceable;
import javax.naming.Reference;
import javax.naming.NamingException;
import javax.naming.StringRefAddr;
import javax.naming.Name;
import javax.naming.Context;

import org.huihoo.jfox.pool.connection.SimpleConnectionPool;
import org.huihoo.jfox.service.ComponentSupport;
/**
 *
 * @author <a href="mailto:kelvin_wym@hotmail.com">Kelvin Wu</a>
 */
public class PoolDataSource extends ComponentSupport implements DataSource, Referenceable, ObjectFactory,PoolDataSourceMBean {
  protected SimpleConnectionPool 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

  /**
   * Default constructor used by JNDI to get a new Instance without any parameters.
   */
  public PoolDataSource() {
//    System.out.println("constructing PoolDataSource...");
  }

  /**
   * 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 dbDriver, String dbURL, String user, String password) throws Exception {
    this.dbDriver = dbDriver;
    this.dbURL = dbURL;
    this.user = user;
    this.password = password;
    pool = new SimpleConnectionPool(dbDriver, dbURL, user, 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 new SQLException(sqle.getLocalizedMessage(), sqle.getSQLState());
    } catch(Exception e) {
      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(), getClass().getName(), null);
    ref.add(new StringRefAddr("dbDriver", dbDriver));
    ref.add(new StringRefAddr("dbURL", dbURL));
    ref.add(new StringRefAddr("user", user));
    ref.add(new StringRefAddr("password", password));
    return ref;
  }

  /**
   * Method that inherited from ObjectFactory.
   * @param obj
   * @param name
   * @param nameCtx
   * @param environment
   * @return
   * @throws Exception
   */
  public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {
    Object result = null;
    Reference ref = (Reference) obj;
    if (ref.getClassName().equals(getClass().getName())) {
      String _dbDriver = (String) ref.get("dbDriver").getContent();
      String _dbURL = (String) ref.get("dbURL").getContent();
      String _user = (String) ref.get("user").getContent();
      String _password = (String) ref.get("password").getContent();
      PoolDataSource pds = new PoolDataSource(_dbDriver, _dbURL, _user, _password);
      result = pds;
    }
    return result;
  }

  public String getDbDriver() {
    return dbDriver;
  }

  public void setDbDriver(String dbDriver) {
    this.dbDriver = dbDriver;
    pool.setDbDriver(dbDriver);
  }

  public String getDbURL() {
    return dbURL;
  }

  public void setDbURL(String dbURL) {
    this.dbURL = dbURL;
    pool.setDbURL(dbURL);
  }

  public String getUser() {
    return user;
  }

  public void setUser(String user) {
    this.user = user;
    pool.setUser(user);
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
    pool.setPassword(password);
  }

  protected void doInit() throws Exception {
    pool.init();
  }

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