Dev Note/Tomcat2008. 3. 17. 15:45

기본적인 Tomcat의 server.xml이나 context path xml에 DBCP를 설정하는 방법은 대부분 알고 있을 것이다. 그럼 DBCP를 Tomcat에서 설정하는 것이 아니라 Application이나 Servlet을 이용하여 설정하여 사용하고 싶을 때는 어떻게 해야 하나?
그건 DBCP의 Sample 소스를 보면 금방 알 수 있다.
이번에 Servlet을 이용하여 web.xml에 init-param으로 DBCP를 설정하여 web에서 사용하는 간략한 소스를 올려볼까 한다. ^^

-- DBCP를 서비스하기 위한 Servlet
   package com.junducki.blog.dbcp;

  
import java.io.IOException;
   import java.io.UnsupportedEncodingException;
   import java.sql.Connection;
   import java.sql.DriverManager;
   import java.sql.SQLException;
   import javax.servlet.ServletConfig;
   import javax.servlet.ServletException;
   import javax.servlet.http.HttpServlet;
   import javax.servlet.http.HttpServletRequest;
   import javax.servlet.http.HttpServletResponse;
   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.logging.Log;
   import org.apache.commons.logging.LogFactory;
   import org.apache.commons.pool.impl.GenericObjectPool;
   import com.goorm.common.security.SeedCipher;
   import com.goorm.common.util.StringUtil;
   import com.goorm.fw.web.servlet.ServletInitParamException;
   import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;

   /**
      * DBCP를 Default 설정 server.xml or context path xml에 설정하는 것이 아닌 web.xml에 Servlet을
      * 이용하여 설정하여 Servlet을 통해 DB Connection을 가져오기 위한 Servlet
      *
      * @author jinuk jung, junducki@naver.com
      * @version 1.0, 2008. 03. 12
      */

   public class DBCPServlet extends HttpServlet {
     
private static final String DBCP_CONNECT_NAME_PREFIX = "jdbc:apache:commons:dbcp:";

     
// ********** Define Initial Parameter Names
      private final String JNDI_NAME = "name";
      // db connection info parameter names
      private final String DRIVER_CLASS_NAME = "driverClassName";
      private final String URL = "url";
      private final String USERNAME = "username";
      private final String PASSWORD = "password";
      private final String MAX_ACTIVE = "maxActive";
      private final String MAX_IDLE = "maxIdle";
      private final String MAX_WAIT = "maxWait";
      private final String VALIDATION_QUERY = "validationQuery";
      // abandoned setting을 위한 parameter names
      private final String REMOVE_ABANDONED = "removeAbandoned";
      private final String REMOVE_ABANDONED_TIMEOUT = "removeAbandonedTimeout";
      private final String LOG_ABANDONED = "logAbandoned";
      // ********** Define Initial Parameter Names End

      /** logger instance */
      protected Log logger = null;

     
/** DBCP JNDI Name */
      private String jndiName = null;

     
/**
         * Servlet을 초기화한다. <br />
         *
         * @param config ServletConfig Servlet Config
         * @throws ServletException
         */
      public void init(ServletConfig config) throws ServletException {
         super.init(config);

         
// create logger instance
         logger = LogFactory.getLog(this.getClass());

         
try {
            registDBCPToJNDI(config);

           
StringBuilder trace = new StringBuilder("DBCP Regist Success [").append(jndiName).append("]");
            logger.info(trace.toString());
         } catch (ServletInitParamException e) {
            logger.error("DBCP Regist Error :: " + jndiName, e);
         }
      }

     
public void service(HttpServletRequest req, HttpServletResponse res) throws IOException { }

      public void destroy() {
         try {
            super.destroy();

            PoolingDriver poolingDriver = (PoolingDriver) DriverManager.getDriver(DBCP_CONNECT_NAME_PREFIX);
            ((GenericObjectPool) poolingDriver.getConnectionPool(jndiName)).close();

           
StringBuilder trace = new StringBuilder("DBCPServlet Destroy :: DBCP JNDI NAME [")
                  .append( jndiName).append("]");
            logger.info(trace.toString());
         } catch (Exception e) {
            logger.error(e.getMessage(), e);
         }
      }

     
/**
         * 설정정보를 로딩하여 DBCP를 생성하여 등록한다.
         *
         * @param config ServletConfig Servlet Config
         * @throws ServletInitParamException
         */
      private void registDBCPToJNDI(ServletConfig config) throws ServletInitParamException {
         
String initParamValue = null;
     
         
// load dbcp configuration
         jndiName = (initParamValue = config.getInitParameter(JNDI_NAME)) != null ? initParamValue : null;
         if (jndiName == null) {
            throw new ServletInitParamException("DBCP Configuration Error :: name is mandatory.");
         }

         
String driverClassName = (initParamValue = config.getInitParameter(DRIVER_CLASS_NAME)) != null
               ? initParamValue : null;
         if (driverClassName == null) {
            throw new ServletInitParamException("DBCP Configuration Error :: driverClassName is mandatory.");
         }

         
String url = (initParamValue = config.getInitParameter(URL)) != null ? initParamValue : null;
         if (url == null) {
            throw new ServletInitParamException("DBCP Configuration Error :: url is mandatory.");
         }

         
String username = (initParamValue = config.getInitParameter(USERNAME)) != null ? initParamValue : null;
         if (username == null) {
            throw new ServletInitParamException("DBCP Configuration Error :: username is mandatory.");
         }

         
String password = (initParamValue = config.getInitParameter(PASSWORD)) != null ? initParamValue : null;
         if (password == null) {
            throw new ServletInitParamException("DBCP Configuration Error :: password is mandatory.");
         }

         
int maxActive = (initParamValue = config.getInitParameter(MAX_ACTIVE)) != null
               ? Integer.parseInt(initParamValue) : 10;
         int maxIdle = (initParamValue = config.getInitParameter(MAX_IDLE)) != null
               ? Integer.parseInt(initParamValue) : 5;
         int maxWait = (initParamValue = config.getInitParameter(MAX_WAIT)) != null
               ? Integer.parseInt(initParamValue) : 15000; // millisecond
     
         String validationQuery = (initParamValue = config.getInitParameter(VALIDATION_QUERY)) != null
               ? nitParamValue : null;

         
// jdbc driver lodding
         try {
            Class.forName(driverClassName);
         } catch (ClassNotFoundException e) {
            throw new ServletInitParamException(e);
         }

         
// db connection pool로 사용할 GenericObjectPool을 생성하고 설정한다.
         GenericObjectPool connPool = new GenericObjectPool();
         connPool.setMaxActive(maxActive);
         connPool.setMaxIdle(maxIdle);
         connPool.setMaxWait(maxWait);

         
// Object Pool에서 DB Connection을 생성하기 위한 DriverManager Factory를 생성한다.
         ConnectionFactory connFactory = new DriverManagerConnectionFactory(url, username, password);

         
// ConnectionFactory의 래퍼 클래스 생성
         PoolableConnectionFactory poolableConnFactory
               = new PoolableConnectionFactory(connFactory, connPool, null, validationQuery, false, true);

         
// DBCP에서 Abandoned 설정 정보를 사용하려면 주석을 푼다. dbcp-1.2.2에서 Abandoned에 대한 모든
         // 객체가 Deprecated 되었다.
         /*boolean removeAbandoned = (initParamValue = config.getInitParameter(REMOVE_ABANDONED))
               != null ? Boolean.parseBoolean(initParamValue) : false;
         
int removeAbandonedTimeout = (initParamValue
               = config.getInitParameter(REMOVE_ABANDONED_TIMEOUT)) != null
               ? Integer.parseInt(initParamValue) : 300;
         
boolean logAbandoned = (initParamValue = config.getInitParameter(LOG_ABANDONED)) != null
               ? Boolean.parseBoolean(initParamValue) : false;

         
AbandonedConfig abandonedConfig = new AbandonedConfig();
         abandonedConfig.setLogAbandoned(true);
         abandonedConfig.setRemoveAbandoned(true);
         abandonedConfig.setRemoveAbandonedTimeout(120);

         
AbandonedObjectPool abandonedObjectPool
               = new AbandonedObjectPool(poolableConnFactory, abandonedConfig);*/

         
// PoolingDriver를 로딩하여 DB Connection Pool을 등록한다.
         try {
            Class.forName("org.apache.commons.dbcp.PoolingDriver");
            PoolingDriver poolingDriver
                  = (PoolingDriver) DriverManager.getDriver(DBCP_CONNECT_NAME_PREFIX);
            poolingDriver.registerPool(jndiName, connPool);
         } catch (ClassNotFoundException e) {
            throw new ServletInitParamException(e);
         } catch (SQLException e) {
            throw new ServletInitParamException(e);
         }
      }

     
/**
         * DBCP에 있는 DB Connection을 가져와 리턴한다.
         *
         * @param poolName String DBCP Pool Name
         * @return Connection DataBase Connection
         * @throws SQLException
         */
      public static Connection getDBCPConnection(String poolName) throws SQLException {
         
return DriverManager.getConnection(DBCP_CONNECT_NAME_PREFIX + "oraDBCP");
      }
   }

위 소스는 DBCP를 web.xml을 이용하여 DBCPServlet을 이용하여 Servlet을 등록하여 사용하는 방식이다. DBCP DataBase Connection을 가져올때는 DBCPServlet.getDBCPConnection(jndiName)을 이용하면 된다.
그럼 DBCPServlet을 web.xml에 어떻게 등록하여 사용하는가?

-- web.xml에 DBCPServlet 등록
   <!-- oraDB DBCP Servlet -->
   <servlet>
      <servlet-name>oraDbcpServlet</servlet-name>
      <servlet-class>com.junducki.blog.dbcp.GoormDBCPServlet</servlet-class>
      <init-param>
         <param-name>name</param-name>
         <param-value>oraDBCP</param-value>
      </init-param>
      <init-param>
         <param-name>driverClassName</param-name>
         <param-value>oracle.jdbc.driver.OracleDriver</param-value>
      </init-param>
      <init-param>
         <param-name>url</param-name>
         <param-value>jdbc:oracle:thin:@xxx.xxx.xxx.xxx:1521:ora</param-value>
      </init-param>
      <init-param>
         <param-name>username</param-name>
         <param-value>scott</param-value>
      </init-param>
      <init-param>
         <param-name>password</param-name>
         <param-value>tiger</param-value>
      </init-param>
      <init-param>
         <param-name>maxActive</param-name>
         <param-value>10</param-value>
      </init-param>
      <init-param>
         <param-name>maxIdle</param-name>
         <param-value>3</param-value>
      </init-param>
      <init-param>
         <param-name>maxWait</param-name>
         <param-value>20000</param-value>
      </init-param>
      <init-param>
         <param-name>validationQuery</param-name>
         <param-value>SELECT 1 FROM DUAL</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
   </servlet>

-- JSP Sample
   <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
   <%@ page import="javax.naming.*, javax.sql.*, java.sql.*, com.junducki.blog.dbcp.*" %>
   <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

   <html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <title>Blog Welcome Page</title>
   </head>
  
<body>
   <%
      Connection conn = null;
      Statement stmt = null;
      ResultSet rs = null;

      try {
         conn = DBCPServlet.getDBCPConnection("oraDBCP");
         stmt = conn.createStatement();
         rs = stmt.executeQuery("SELECT TO_CHAR(SYSDATE, 'YYYY/MM/DD HH24:MI:SS') FROM DUAL");
         while(rs.next()) {
            out.println("DataBase Date :: " + rs.getString(1));
         }
      } catch (Exception e) {
         e.printStackTrace();
      } finally {
         try {
            rs.close();
            stmt.close();
            conn.close();
         } catch(SQLException e) {}
      }
   %>
   </body>
   </html>

Posted by as.wind.914