/* ====================================================================================*
 * 																					   *
 * 说明：管理类DBConnMgr支持对一个或多个由属性文件定义的数据库连接池的访问.            *
 *       客户程序可以调用getInstance()方法访问本类的唯一实例.                          *
 * 功能：     																		   *
 *       1、装载与注册JDBC驱动程序                             						   *                   
 *       2、根据属性文件的描述创建连接池对象										   *
 *       3、实现连接池名字与实例之间的映射											   *
 *	     4、根据客户程序对连接池的引用，保证在最后一个客户程序结束后再安全地关闭所有连 *
 *			接池的连接。															   *
 *						 															   *
 *=====================================================================================*/ 
 
package  com.Quincy.common.pools;

import java.io.InputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection; 
import java.sql.Driver; 
import java.sql.DriverManager; 
import java.sql.SQLException; 
import java.util.Hashtable; 
import java.util.Properties;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.Date; 

import com.Quincy.common.Global;

public class dbConnMgr implements dbPoolConstants
{
	static private dbConnMgr instance; 		 		   //唯一实例 
	static private int       clients; 			 	   //引用本对象的客户数
	private Vector 			 JdbC_Drivers = new Vector();   //JdbC驱动程序向量
	
	private Hashtable pools = new Hashtable(); 
	private Global CHS=new Global();
	private dbLogging dbLogFile=new dbLogging();
	
	/*=============================================================================
		作用：返回唯一实例.如果是第一次调用此方法,则创建实例. 
		参数：无
		返回：dbConnMgr 唯一实例. 
	=============================================================================*/ 
	static synchronized public dbConnMgr getInstance() 
	{ 
  		if (instance == null) 
  		{ 
    		instance = new dbConnMgr(); 
  		} 
  			clients++; 
  		return instance; 
  	} 

	/* 构造函数：私有，以防止其它对象创建本类实例. */ 
	private dbConnMgr() 
	{ 
  		init(); 	
	} 


	/*=============================================================================
	 * 作用：将连接对象返回给由名字指定的连接池. 
	 * 参数：name 在属性文件中定义的连接池名字; con 连接对象. 
	 * 返回：无
	 =============================================================================*/ 
 
	public void freeConnection(String name, Connection con) 
	{ 
  		dbConnPool pool = (dbConnPool) pools.get(name); 
  		if (pool != null) 
  		{  
  			pool.freeConnection(con); 
  		} 
	} 

   /*=============================================================================
 	* 作用：获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数
 		    限制,则创建并返回新连接 
 	* 参数： name 在属性文件中定义的连接池名字 
 	* 返回： Connection 可用连接或null 
 	=============================================================================*/ 
 	
	public Connection getConnection(String name) 
	{ 
  		dbConnPool pool = (dbConnPool) pools.get(name); 
		if (pool != null) {  return pool.getConnection(); } 
		return null; 
	} 

   /*=============================================================================
 	* 作用：获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制, 
 	        则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接. 
 	* 参数： name 连接池名字,time 以毫秒计的等待时间 
 	* 返回：Connection 可用连接或null 
 	=============================================================================*/ 
	public Connection getConnection(String name, long time) 
	{ 
  		dbConnPool pool = (dbConnPool) pools.get(name); 
		if (pool != null) {  return pool.getConnection(time); } 
		return null; 
	} 

	/* =============================================================================
	* 作用：关闭所有连接,撤销驱动程序的注册 
	* 参数：无
	* 返回：无
	=============================================================================*/ 
	public synchronized void release() 
	{ 
  		//等待直到最后一个客户程序结束对对象的使用
  		if (--clients != 0) { return; } 
  		Enumeration allPools = pools.elements(); 
  		while (allPools.hasMoreElements()) 
  		{ 
    		dbConnPool pool = (dbConnPool) allPools.nextElement(); 
    		pool.release(); 
  		} 
  		Enumeration allDrivers = JdbC_Drivers.elements(); 
  		while (allDrivers.hasMoreElements()) 
  		{ 
    		Driver driver = (Driver) allDrivers.nextElement(); 
    		try 
    		{ 
      			DriverManager.deregisterDriver(driver); 
      			dbLogFile.Logging("撤销JdbC驱动程序 " + driver.getClass().getName()+"的注册"); 
    		} 
    		catch (SQLException e) 
    		{ 
      			dbLogFile.Logging(e, "无法撤销下列JdbC驱动程序的注册: " + driver.getClass().getName()); 
    		} 
  		} 
	} 

	/*=============================================================================
 	 * 作用：根据指定属性创建连接池实例. 
 	 * 参数：props 连接池属性 
 	 * 返回：无
 	=============================================================================*/ 
	private void createPools(Properties props) 
	{ 
  		Enumeration propNames = props.propertyNames(); 
  		while (propNames.hasMoreElements()) 
  		{ 
    		String name = (String) propNames.nextElement(); 
    		if (name.endsWith(".url")) 
    		{ 
      			String poolName = name.substring(0, name.lastIndexOf(".")); 
      			String url = props.getProperty(poolName + ".url"); 
      			if (url == null) 
      			{ 
        			dbLogFile.Logging("没有为连接池" + poolName + "指定URL");
        			continue; 
      			} 
      			String user = props.getProperty(poolName + ".user"); 
      			String password = props.getProperty(poolName + ".password"); 
      			String maxconn = props.getProperty(poolName + ".maxconn", "0"); 
      			int max; 
      			try 
      			{ 
        			max = Integer.valueOf(maxconn).intValue(); 
      			} catch (NumberFormatException e) 
      			{ 
        			dbLogFile.Logging("错误的最大连接数限制: " + maxconn + " .连接池: " + poolName); 
        			max = 0; 
      			} 
      			dbConnPool pool = new dbConnPool(poolName, url, user, password, max); 
      			pools.put(poolName, pool); 
      			dbLogFile.Logging("成功创建连接池" + poolName); 
    		} 
  		} 
	} 

	/* =============================================================================
    * 作用：读取属性完成初始化  
    * 参数：无
    * 返回：无
	=============================================================================*/ 
	private void init() 
	{ 
		dbLogFile.setLogFilePath(DB_PROPERTIES_FILE);
  		InputStream is = getClass().getResourceAsStream(DB_PROPERTIES_FILE); 
  		Properties dbProps = new Properties(); 
  		try 
  		{ 
    		dbProps.load(is); 
  		} 
  		catch (Exception e) 
  		{ 
    		dbLogFile.Logging("不能读取属性文件."); 
    		return; 
  		} 
  		
  		//String logFile = dbProps.getProperty("logfile", DB_POOL_LOGFILE); 
  		/*try 
  		{ 
    		log = new PrintWriter(new FileWriter(logFile, true), true); 
  		} 
  		catch (IOException e) 
  		{ 
    		//System.err.println("无法打开日志文件: " + logFile); 
    		System.err.println("unable to open the log file:"+logFile);
    		log = new PrintWriter(System.err); 
  		} */
  		loadDrivers(dbProps); 
  		createPools(dbProps); 
	} 

	/*============================================================================= 
	* 作用：装载和注册所有JdbC驱动程序 
	* 参数：props 属性 
	* 返回：无
	=============================================================================*/ 
	private void loadDrivers(Properties props) 
	{ 
  		String driverClasses = props.getProperty("drivers"); 
  		StringTokenizer st = new StringTokenizer(driverClasses); 
		while (st.hasMoreElements()) 
		{ 
    		String driverClassName = st.nextToken().trim(); 
    		try 
    		{ 
      			Driver driver = (Driver) Class.forName(driverClassName).newInstance(); 
      			DriverManager.registerDriver(driver); 
      			JdbC_Drivers.addElement(driver); 
      			dbLogFile.Logging("成功注册JdbC驱动程序" + driverClassName); 
    		} 
    		catch (Exception e) 
    		{ 
      			dbLogFile.Logging("无法注册JdbC驱动程序: " + driverClassName + ", 错误: " + e); 
    		} 
  		} 
	} 

}
