/*
 * Copyright (c) 2005 by NOAATS Technology, Inc.
 * 
 * 5F, Dong Sung Bldg.17-8, Yeouido-Dong Yeongdeungpo-Gu, Seoul 150-874, Korea
 * All rights reserved.
 */
package net.kldp.logviewer.db.common.pool;

import java.sql.DriverManager;
import java.sql.SQLException;

import net.kldp.logviewer.common.config.CommonConfig;
import net.kldp.logviewer.common.log.LogViews;

import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDriver;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.log4j.Logger;


/**
 * <PRE>
 * 
 * Title : 컨넥션 풀링을 한다.
 * 				처음 한번만 생성되어야한다.
 * Comment :
 * 
 * History : 
 * 
 * </PRE>
 * 
 * @version 0.1, 2005. 9. 15.
 * @author henry
 */
public class ConnectionInitialize {
	/**
	 * Logger for this class
	 */
	private static final Logger logger = LogViews.getLogger(ConnectionInitialize.class);

	/**
	 * 객체를 초기화 한다.
	 */
	public void init(String poolName) throws Exception {
		String driverClassName 		= CommonConfig.getWentProp(poolName + ".DriverName");
		String url 					= CommonConfig.getWentProp(poolName + ".DataSource");
		String databaseName			= CommonConfig.getWentProp(poolName + ".DataBaseName");
		String username 			= CommonConfig.getWentProp(poolName + ".User");
		String password 			= CommonConfig.getWentProp(poolName + ".Pass");
		boolean defaultAutoCommit 	= CommonConfig.getWentPropBool(poolName + ".AutoCommit");
		boolean defaultReadOnly 	= CommonConfig.getWentPropBool(poolName + ".DefaultReadOnly");
		int maxActive 				= CommonConfig.getWentPropInt(poolName + ".MaxActive");
		int maxIdle 				= CommonConfig.getWentPropInt(poolName + ".MaxIdle");
		long maxWait 				= CommonConfig.getWentPropInt(poolName + ".MaxWait");

		try {
			setupDriver(
				poolName,
				driverClassName,
				url,
				databaseName,
				username,
				password,
				defaultAutoCommit,
				defaultReadOnly,
				maxActive,
				maxIdle,
				maxWait
			);

			logger.debug("Creation the Connection Pooling Object");
		} catch (Exception e) {
			logger.debug("Fail the Connection initialize!!!");
			e.printStackTrace();
			
			throw e;
		}
	}

	/**
	 * Driver를 로드한다.
	 * 
	 * @param driverClassName
	 * @param url
	 * @param databaseName
	 * @param username
	 * @param password
	 * @param defaultAutoCommit
	 * @param defaultReadOnly
	 * @param maxActive
	 * @param maxIdle
	 * @param maxWait
	 * @throws Exception
	 */
	public void setupDriver(
			String poolName			, String driverClassName, 
			String url				, String databaseName	,
			String username			, String password	   	, 
			boolean defaultAutoCommit,	boolean defaultReadOnly	, 
			int maxActive			, int maxIdle			, 
			long maxWait)	throws ClassNotFoundException, SQLException {

		try {
			Class.forName(driverClassName);
		} catch (ClassNotFoundException cnfe) {
			logger.error(driverClassName + " is not found", cnfe);
			
			throw cnfe;
		}

		// 커넥션 풀로 사용할 commons-collections의 genericOjbectPool을 생성합니다.
		GenericObjectPool connectionPool = new GenericObjectPool(null);
		
		connectionPool.setMaxActive(maxActive);
		
		connectionPool.setMaxIdle(maxIdle);
		
		connectionPool.setMaxWait(maxWait);

		// 비활성화 커넥션을 추출할 때 커넥션이 유효한지의 여부를 검사해서 유효하지 않은 커넥션은 풀에서 제거한다.
		connectionPool.setTestWhileIdle(true);
		
		// 커넥션 풀에서 커넥션을 가져올수 없을 경우 커넥션을 일시적으로 커넥션을 구해 사용한다.
		connectionPool.setWhenExhaustedAction((byte)2);
		
		// 사용되지 않은 커넥션을 추출하는 쓰레드의 실행 주기를 지정한다
		connectionPool.setTimeBetweenEvictionRunsMillis(600000); 

		// 풀이 커넥션을 생성하는데 사용하는 DriverManagerConnectionFactory를 생성합니다.
		ConnectionFactory connectionFactory = 
				new DriverManagerConnectionFactory(url, username, password);

		// ConnectionFactory의 래퍼 클래스인 PoolableConnectionFactory를 생성한다
		PoolableConnectionFactory poolableConnectionFactory = 
			new PoolableConnectionFactory(connectionFactory, connectionPool, null, null, defaultReadOnly, defaultAutoCommit);

		try {
			// 마지막으로 PoolingDriver 자신을 로딩한다
			Class.forName("org.apache.commons.dbcp.PoolingDriver");
		} catch(ClassNotFoundException cnfe) {
			logger.error("org.apache.commons.dbcp.PoolingDriver is not found", cnfe);
			
			throw cnfe;
		}
			
		try {
			PoolingDriver driver = (PoolingDriver)DriverManager.getDriver("jdbc:apache:commons:dbcp:");
			
			//풀에 이름을 등록한다.
			driver.registerPool(poolName, connectionPool);
		} catch(SQLException sqle) {
			logger.error(poolName + "를 Connection Pool을 등록하는 중에 에러가 발생했습니다.", sqle);
			
			throw sqle;
		}
	}
}
