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

package org.jfox.jdbc.datasource;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.huihoo.jfox.pool.AbstractObjectPool;
import org.huihoo.jfox.pool.ObjectFactory;
import org.huihoo.jfox.pool.ObjectPool;
import org.huihoo.jfox.pool.PoolableObject;
import org.huihoo.jfox.pool.SimpleObjectPool;
import org.huihoo.jfox.system.ComponentSupport;

/**
 * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
 */

public class ConnectionPool extends ComponentSupport implements ObjectPool {

  private AbstractObjectPool pool = null;
  private ConnectionFactory factory = null;

  private int initNum = 2;
  private int maxRest = 10;

  // Connection <=> 使用开始时间
  private Map workings = new HashMap();

  private long timeout = 60 * 60 * 1000L; // one hour

  public ConnectionPool(String dbDriver, String dbURL, String user, String password) throws Exception {
    factory = new ConnectionFactory(PoolableConnection.class,dbDriver,dbURL,user,password);
  }

  public Connection getConnection() throws Exception {
    PoolableConnection pconn = (PoolableConnection)retrieveObject();
    return pconn;
  }

  public int getInitNum() {
    return initNum;
  }

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

  public void clear() {
    try {
      for(Iterator it = workings.keySet().iterator(); it.hasNext();){
        ((PoolableConnection)it.next()).getConnection().close();
      }
    }
    catch(SQLException e){
      e.printStackTrace();
    }
  }

  public int getMaxRest() {
    return maxRest;
  }

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

  public ObjectFactory getObjectFactory() {
    return factory;
  }

  public boolean removeObject(PoolableObject obj) {
    workings.remove(obj);
    try {
      factory.destroyObject(obj);
      return true;
    }
    catch(Exception e){
      e.printStackTrace();
      return false;
    }
  }

  public int getWorking() {
    return workings.size();
  }

  public String getObjectClass() {
    return factory.getObjectClass().getName();
  }

  public int getRest() {
    return pool.getRest();
  }

  public PoolableObject retrieveObject() throws Exception {
    PoolableConnection pobj = (PoolableConnection)pool.retrieveObject();
    pobj.setPool(this);
    workings.put(pobj,new Long(System.currentTimeMillis()));
    return pobj;
  }

  public boolean restoreObject(PoolableObject obj) {
    workings.remove(obj);
    return pool.restoreObject(obj);
  }

  protected void doInit() throws Exception {
    pool = new SimpleObjectPool(factory,initNum,maxRest);
    pool.init();
    new LifecyleThread().start();
  }

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

  /**
   * 检查连接的超时
   */
  private class LifecyleThread extends Thread {
    public LifecyleThread() {
      this.setPriority(Thread.MIN_PRIORITY);
      this.setDaemon(true);
    }

    public void run() {
      while(true){
        try {
          Thread.sleep(timeout/10);
        }
        catch(Exception e){ }
        for(Iterator it = workings.entrySet().iterator(); it.hasNext();){
          Map.Entry entry = (Map.Entry)it.next();
          long time = ((Long)entry.getValue()).longValue();
          if(System.currentTimeMillis() - time > timeout){
            try {
              factory.destroyObject((PoolableObject)entry.getKey());
            }
            catch(Exception e){
              e.printStackTrace();
            }
          }
        }
      }
    }
  }

  public static void main(String[] args) {

  }
}