package net.java_school.db.dbpool; 

import java.util.*; 
import java.sql.*; 
import java.util.Date; 
import net.java_school.util.Log;

// Connection PoolÀ» °ü¸®ÇÏ´Â Å¬·¡½º 
class DBConnectionPool {
  
  // ÇöÀç »ç¿ë ÁßÀÎ Connection °³¼ö
  private int checkedOut;
  
  // Free Connection List JDK 1.5 ÀÌÈÄ¹öÀüÀÏ °æ¿ì
  private Vector<Connection> freeConnections = new Vector<Connection>();

  // Free Connection List JDK 1.5 ÀÌÀü¹öÀüÀÏ °æ¿ì
  // private Vector freeConnections = new Vector();

  // Connection ÃÖ´ë °³¼ö
  private int maxConn;
  
  // Connection ÃÊ±â °³¼ö
  private int initConn;
  
  // Waiting time (pool¿¡ connectionÀÌ ¾øÀ»¶§ ±â´Ù¸®´Â ÃÖ´ë½Ã°£)
  private int maxWait;
  
  // Connection Pool Name
  private String name;
  
  // DB Password
  private String password;
  
  // DB URL
  private String URL;
  
  // DB UserID
  private String user;
  
  // Constructor
  public DBConnectionPool( String name, String URL, String user, String password, 
    int maxConn, int initConn, int waitTime ) {
    this.name = name;
    this.URL = URL;
    this.user = user;
    this.password = password;
    this.maxConn = maxConn;
    this.maxWait = waitTime;
    
    for ( int i = 0; i < initConn; i++ ) {
      freeConnections.addElement( newConnection() );
    }
  }

  // Connection ¹Ý³³
  // @param con : ¹Ý³³ÇÒ Connection
  public synchronized void freeConnection( Connection con ) {
    freeConnections.addElement( con );
    checkedOut--;
    // ConnectionÀ» ¾ò±â À§ÇØ ´ë±âÇÏ°í ÀÖ´Â thread¿¡ ¾Ë¸²
    notifyAll();
  }

  // Connection À» ¾òÀ½
  public synchronized Connection getConnection() {
    Connection con = null;
    // ConnectionÀÌ Free List¿¡ ÀÖÀ¸¸é ListÀÇ Ã³À½ °ÍÀ» ¾òÀ½
    if ( freeConnections.size() > 0 ) {
      con = (Connection) freeConnections.firstElement();
      freeConnections.removeElementAt(0);
      try {
        // DBMS¿¡ ÀÇÇØ ConnectionÀÌ close µÇ¾úÀ¸¸é ´Ù½Ã ¿ä±¸
        if ( con.isClosed() ) {
          Log.err( "Removed bad connection from " + name );
          con = getConnection();
        }
      } // ¿ä»óÇÑ Connection ¹ß»ýÇÏ¸é ´Ù½Ã ¿ä±¸
      catch ( SQLException e ) {
        Log.err( e, "Removed bad connection from " + name );
        con = getConnection();
      }
    } // ConnectionÀÌ Free List¿¡ ¾øÀ¸¸é »õ·Î »ý¼º
    else if ( maxConn == 0 || checkedOut < maxConn ) {
      con = newConnection();
    }
    
    if ( con != null ) {
      checkedOut++;
    }
    return con;
  }

  // ConnectionÀ» ¾òÀ½
  // @param timeout : ConnectionÀ» ¾ò±â À§ÇÑ ÃÖ´ë ±â´Ù¸² ½Ã°£
  public synchronized Connection getConnection( long timeout ) {
    long startTime = new Date().getTime();
    Connection con;
    while ( (con = getConnection()) == null ) {
      try {
        wait( timeout * maxWait );
      } catch ( InterruptedException e ) {}
      if ( (new Date().getTime() - startTime) >= timeout ) {
        // ±â´Ù¸² ½Ã°£ ÃÊ°ú
        return null;
      }
    }
    return con;
  }

  // Connection »ý¼º
  private Connection newConnection() {
    Connection con = null;
    try {
      if ( user == null ) {
        con = DriverManager.getConnection( URL );
      } else {
        con = DriverManager.getConnection( URL, user, password );
      }
      Log.out( "Created a new connection in pool " + name );
    } catch ( SQLException e ) {
      Log.err(e, "Can't create a new connection for " + URL + " user : " +
        user + " passwd : " + password);
      return null;
    }
    return con;
  }
}
