Home » commons-dbcp-1.2.2-src » org.apache.commons » dbcp » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   package org.apache.commons.dbcp;
   19   
   20   import java.sql.Connection;
   21   import java.sql.PreparedStatement;
   22   import java.sql.SQLException;
   23   
   24   import java.util.NoSuchElementException;
   25   
   26   import org.apache.commons.pool.KeyedObjectPool;
   27   import org.apache.commons.pool.KeyedPoolableObjectFactory;
   28   
   29   /**
   30    * A {@link DelegatingConnection} that pools {@link PreparedStatement}s.
   31    * <p>
   32    * My {@link #prepareStatement} methods, rather than creating a new {@link PreparedStatement}
   33    * each time, may actually pull the {@link PreparedStatement} from a pool of unused statements.
   34    * The {@link PreparedStatement#close} method of the returned {@link PreparedStatement} doesn't
   35    * actually close the statement, but rather returns it to my pool. (See {@link PoolablePreparedStatement}.)
   36    *
   37    * @see PoolablePreparedStatement
   38    * @author Rodney Waldhoff
   39    * @author Dirk Verbeeck
   40    * @version $Revision: 498524 $ $Date: 2007-01-21 21:44:45 -0700 (Sun, 21 Jan 2007) $
   41    */
   42   public class PoolingConnection extends DelegatingConnection implements Connection, KeyedPoolableObjectFactory {
   43       /** My pool of {@link PreparedStatement}s. */
   44       protected KeyedObjectPool _pstmtPool = null;
   45   
   46       /**
   47        * Constructor.
   48        * @param c the underlying {@link Connection}.
   49        */
   50       public PoolingConnection(Connection c) {
   51           super(c);
   52       }
   53   
   54       /**
   55        * Constructor.
   56        * @param c the underlying {@link Connection}.
   57        * @param pool {@link KeyedObjectPool} of {@link PreparedStatement}s
   58        */
   59       public PoolingConnection(Connection c, KeyedObjectPool pool) {
   60           super(c);
   61           _pstmtPool = pool;
   62       }
   63   
   64   
   65       /**
   66        * Close and free all {@link PreparedStatement}s from my pool, and
   67        * close my underlying connection.
   68        */
   69       public synchronized void close() throws SQLException {
   70           if(null != _pstmtPool) {
   71               KeyedObjectPool oldpool = _pstmtPool;            
   72               _pstmtPool = null;
   73               try {
   74                   oldpool.close();
   75               } catch(RuntimeException e) {
   76                   throw e;
   77               } catch(SQLException e) {
   78                   throw e;
   79               } catch(Exception e) {
   80                   throw new SQLNestedException("Cannot close connection", e);
   81               }
   82           }
   83           getInnermostDelegate().close();
   84       }
   85   
   86       /**
   87        * Create or obtain a {@link PreparedStatement} from my pool.
   88        * @return a {@link PoolablePreparedStatement}
   89        */
   90       public PreparedStatement prepareStatement(String sql) throws SQLException {
   91           try {
   92               return(PreparedStatement)(_pstmtPool.borrowObject(createKey(sql)));
   93           } catch(NoSuchElementException e) {
   94               throw new SQLNestedException("MaxOpenPreparedStatements limit reached", e); 
   95           } catch(RuntimeException e) {
   96               throw e;
   97           } catch(Exception e) {
   98               throw new SQLNestedException("Borrow prepareStatement from pool failed", e);
   99           }
  100       }
  101   
  102       /**
  103        * Create or obtain a {@link PreparedStatement} from my pool.
  104        * @return a {@link PoolablePreparedStatement}
  105        */
  106       public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
  107           try {
  108               return(PreparedStatement)(_pstmtPool.borrowObject(createKey(sql,resultSetType,resultSetConcurrency)));
  109           } catch(NoSuchElementException e) {
  110               throw new SQLNestedException("MaxOpenPreparedStatements limit reached", e); 
  111           } catch(RuntimeException e) {
  112               throw e;
  113           } catch(Exception e) {
  114               throw new SQLNestedException("Borrow prepareStatement from pool failed", e);
  115           }
  116       }
  117   
  118       // ------------------- JDBC 3.0 -----------------------------------------
  119       // Will be commented by the build process on a JDBC 2.0 system
  120   
  121   /* JDBC_3_ANT_KEY_BEGIN */
  122   
  123   //    TODO: possible enhancement, cache these preparedStatements as well
  124   
  125   //    public PreparedStatement prepareStatement(String sql, int resultSetType,
  126   //                                              int resultSetConcurrency,
  127   //                                              int resultSetHoldability)
  128   //        throws SQLException {
  129   //        return super.prepareStatement(
  130   //            sql, resultSetType, resultSetConcurrency, resultSetHoldability);
  131   //    }
  132   //
  133   //    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
  134   //        throws SQLException {
  135   //        return super.prepareStatement(sql, autoGeneratedKeys);
  136   //    }
  137   //
  138   //    public PreparedStatement prepareStatement(String sql, int columnIndexes[])
  139   //        throws SQLException {
  140   //        return super.prepareStatement(sql, columnIndexes);
  141   //    }
  142   //
  143   //    public PreparedStatement prepareStatement(String sql, String columnNames[])
  144   //        throws SQLException {
  145   //        return super.prepareStatement(sql, columnNames);
  146   //    }
  147   
  148   /* JDBC_3_ANT_KEY_END */
  149   
  150   
  151       /**
  152        * Create a PStmtKey for the given arguments.
  153        */
  154       protected Object createKey(String sql, int resultSetType, int resultSetConcurrency) {
  155           String catalog = null;
  156           try {
  157               catalog = getCatalog();
  158           } catch (Exception e) {}
  159           return new PStmtKey(normalizeSQL(sql), catalog, resultSetType, resultSetConcurrency);
  160       }
  161   
  162       /**
  163        * Create a PStmtKey for the given arguments.
  164        */
  165       protected Object createKey(String sql) {
  166           String catalog = null;
  167           try {
  168               catalog = getCatalog();
  169           } catch (Exception e) {}
  170           return new PStmtKey(normalizeSQL(sql), catalog);
  171       }
  172   
  173       /**
  174        * Normalize the given SQL statement, producing a
  175        * cannonical form that is semantically equivalent to the original.
  176        */
  177       protected String normalizeSQL(String sql) {
  178           return sql.trim();
  179       }
  180   
  181       /**
  182        * My {@link KeyedPoolableObjectFactory} method for creating
  183        * {@link PreparedStatement}s.
  184        * @param obj the key for the {@link PreparedStatement} to be created
  185        */
  186       public Object makeObject(Object obj) throws Exception {
  187           if(null == obj || !(obj instanceof PStmtKey)) {
  188               throw new IllegalArgumentException();
  189           } else {
  190               // _openPstmts++;
  191               PStmtKey key = (PStmtKey)obj;
  192               if(null == key._resultSetType && null == key._resultSetConcurrency) {
  193                   return new PoolablePreparedStatement(getDelegate().prepareStatement(key._sql),key,_pstmtPool,this);
  194               } else {
  195                   return new PoolablePreparedStatement(getDelegate().prepareStatement(key._sql,key._resultSetType.intValue(),key._resultSetConcurrency.intValue()),key,_pstmtPool,this);
  196               }
  197           }
  198       }
  199   
  200       /**
  201        * My {@link KeyedPoolableObjectFactory} method for destroying
  202        * {@link PreparedStatement}s.
  203        * @param key ignored
  204        * @param obj the {@link PreparedStatement} to be destroyed.
  205        */
  206       public void destroyObject(Object key, Object obj) throws Exception {
  207           //_openPstmts--;
  208           if(obj instanceof DelegatingPreparedStatement) {
  209               ((DelegatingPreparedStatement)obj).getInnermostDelegate().close();
  210           } else {
  211               ((PreparedStatement)obj).close();
  212           }
  213       }
  214   
  215       /**
  216        * My {@link KeyedPoolableObjectFactory} method for validating
  217        * {@link PreparedStatement}s.
  218        * @param key ignored
  219        * @param obj ignored
  220        * @return <tt>true</tt>
  221        */
  222       public boolean validateObject(Object key, Object obj) {
  223           return true;
  224       }
  225   
  226       /**
  227        * My {@link KeyedPoolableObjectFactory} method for activating
  228        * {@link PreparedStatement}s. (Currently a no-op.)
  229        * @param key ignored
  230        * @param obj ignored
  231        */
  232       public void activateObject(Object key, Object obj) throws Exception {
  233           ((DelegatingPreparedStatement)obj).activate();
  234       }
  235   
  236       /**
  237        * My {@link KeyedPoolableObjectFactory} method for passivating
  238        * {@link PreparedStatement}s.  Currently invokes {@link PreparedStatement#clearParameters}.
  239        * @param key ignored
  240        * @param obj a {@link PreparedStatement}
  241        */
  242       public void passivateObject(Object key, Object obj) throws Exception {
  243           ((PreparedStatement)obj).clearParameters();
  244           ((DelegatingPreparedStatement)obj).passivate();
  245       }
  246   
  247       public String toString() {
  248           return "PoolingConnection: " + _pstmtPool.toString();
  249       }
  250   
  251       /**
  252        * A key uniquely identifiying {@link PreparedStatement}s.
  253        */
  254       class PStmtKey {
  255           protected String _sql = null;
  256           protected Integer _resultSetType = null;
  257           protected Integer _resultSetConcurrency = null;
  258           protected String _catalog = null;
  259           
  260           PStmtKey(String sql) {
  261               _sql = sql;
  262           }
  263   
  264           PStmtKey(String sql, String catalog) {
  265               _sql = sql;
  266               _catalog = catalog;
  267           }
  268   
  269           PStmtKey(String sql, int resultSetType, int resultSetConcurrency) {
  270               _sql = sql;
  271               _resultSetType = new Integer(resultSetType);
  272               _resultSetConcurrency = new Integer(resultSetConcurrency);
  273           }
  274   
  275           PStmtKey(String sql, String catalog, int resultSetType, int resultSetConcurrency) {
  276               _sql = sql;
  277               _catalog = catalog;
  278               _resultSetType = new Integer(resultSetType);
  279               _resultSetConcurrency = new Integer(resultSetConcurrency);
  280           }
  281   
  282           public boolean equals(Object that) {
  283               try {
  284                   PStmtKey key = (PStmtKey)that;
  285                   return( ((null == _sql && null == key._sql) || _sql.equals(key._sql)) &&
  286                           ((null == _catalog && null == key._catalog) || _catalog.equals(key._catalog)) &&
  287                           ((null == _resultSetType && null == key._resultSetType) || _resultSetType.equals(key._resultSetType)) &&
  288                           ((null == _resultSetConcurrency && null == key._resultSetConcurrency) || _resultSetConcurrency.equals(key._resultSetConcurrency))
  289                         );
  290               } catch(ClassCastException e) {
  291                   return false;
  292               } catch(NullPointerException e) {
  293                   return false;
  294               }
  295           }
  296   
  297           public int hashCode() {
  298               if (_catalog==null)
  299                   return(null == _sql ? 0 : _sql.hashCode());
  300               else
  301                   return(null == _sql ? _catalog.hashCode() : (_catalog + _sql).hashCode());
  302           }
  303   
  304           public String toString() {
  305               StringBuffer buf = new StringBuffer();
  306               buf.append("PStmtKey: sql=");
  307               buf.append(_sql);
  308               buf.append(", catalog=");
  309               buf.append(_catalog);
  310               buf.append(", resultSetType=");
  311               buf.append(_resultSetType);
  312               buf.append(", resultSetConcurrency=");
  313               buf.append(_resultSetConcurrency);
  314               return buf.toString();
  315           }
  316       }
  317   }

Save This Page
Home » commons-dbcp-1.2.2-src » org.apache.commons » dbcp » [javadoc | source]