KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opensubsystems > core > persist > db > connectionpool > DBCPDatabaseConnectionFactoryImpl


1 /*
2  * Copyright (c) 2003 - 2007 OpenSubsystems s.r.o. Slovak Republic. All rights reserved.
3  *
4  * Project: OpenSubsystems
5  *
6  * $Id: DBCPDatabaseConnectionFactoryImpl.java,v 1.7 2007/01/07 06:14:58 bastafidli Exp $
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; version 2 of the License.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21
22 package org.opensubsystems.core.persist.db.connectionpool;
23
24 import java.sql.Connection JavaDoc;
25 import java.sql.DriverManager JavaDoc;
26 import java.sql.SQLException JavaDoc;
27
28 import org.apache.commons.dbcp.ConnectionFactory;
29 import org.apache.commons.dbcp.DriverManagerConnectionFactory;
30 import org.apache.commons.dbcp.PoolableConnectionFactory;
31 import org.apache.commons.pool.KeyedObjectPoolFactory;
32 import org.apache.commons.pool.ObjectPool;
33 import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
34 import org.apache.commons.pool.impl.GenericObjectPool;
35 import org.opensubsystems.core.error.OSSConfigException;
36 import org.opensubsystems.core.error.OSSDatabaseAccessException;
37 import org.opensubsystems.core.error.OSSException;
38 import org.opensubsystems.core.persist.db.DatabaseImpl;
39 import org.opensubsystems.core.persist.db.DatabaseTransactionFactoryImpl;
40 import org.opensubsystems.core.util.GlobalConstants;
41
42 /**
43  * Implementation of connection pool using Jakarta Commons DBCP package.
44  *
45  * @version $Id: DBCPDatabaseConnectionFactoryImpl.java,v 1.7 2007/01/07 06:14:58 bastafidli Exp $
46  * @author Miro Halas
47  * @code.reviewer Miro Halas
48  * @code.reviewed 1.3 2005/09/24 00:23:57 jlegeny
49  */

50 public class DBCPDatabaseConnectionFactoryImpl extends PooledDatabaseConnectionFactoryImpl
51 {
52    // Constructors /////////////////////////////////////////////////////////////
53

54    /**
55     * Constructor for new instance using default database properties.
56     *
57     * @throws OSSConfigException - if there was an error accessing default database
58     * properties
59     * @throws OSSDatabaseAccessException - problem accessing the database
60     */

61    public DBCPDatabaseConnectionFactoryImpl(
62    ) throws OSSConfigException,
63             OSSDatabaseAccessException
64    {
65       super();
66       
67       // Use the default database properties
68
loadDefaultDatabaseProperties();
69
70       // Do not start it now because when we are creating pool we need to know
71
// what database we are running on and it would create circular dependency
72
// with DatabaseImpl
73
// start();
74
}
75    
76
77    /**
78     * Constructor for new instance using default database properties.
79     *
80     * @param transactionFactory - transaction factory to use for this
81     * connection factory, can be null
82     * @throws OSSConfigException - if there was an error accessing default database
83     * properties
84     * @throws OSSDatabaseAccessException - problem accessing the database
85     */

86    public DBCPDatabaseConnectionFactoryImpl(
87       DatabaseTransactionFactoryImpl transactionFactory
88    ) throws OSSConfigException,
89             OSSDatabaseAccessException
90    {
91       super(transactionFactory);
92
93       // Use the default database properties
94
loadDefaultDatabaseProperties();
95
96       // Do not start it know because when we are creating pool we need to know
97
// what database we are running on and it would create circular dependency
98
// with DatabaseImpl
99
// start();
100
}
101    
102    /**
103     * Constructor for new instance using explicitely specified properties.
104     *
105     * @param strDriver - JDBC driver to connect to the database
106     * @param strURL - URL of database to connect to
107     * @param strUser - user name to connect to the database
108     * @param strPassword - password to the database
109     * @param transactionFactory - transaction factory to use for this
110     * connection factory, can be null
111     * @throws OSSConfigException - problem accessing or locating the config file.
112     * @throws OSSDatabaseAccessException - problem accessing the database
113     */

114    public DBCPDatabaseConnectionFactoryImpl(
115       String JavaDoc strDriver,
116       String JavaDoc strURL,
117       String JavaDoc strUser,
118       String JavaDoc strPassword,
119       DatabaseTransactionFactoryImpl transactionFactory
120    ) throws OSSConfigException,
121             OSSDatabaseAccessException
122    {
123       super(strDriver, strURL, strUser, strPassword, transactionFactory);
124       
125       // Do not start it now because when we are creating pool we need to know
126
// what database we are running on and it would create circular dependency
127
// with DatabaseImpl
128
// start();
129
}
130
131    // Helper methods ///////////////////////////////////////////////////////////
132

133    /**
134     * {@inheritDoc}
135     */

136    protected Connection JavaDoc getPooledConnection(
137       ConnectionPoolDefinition connectionpool
138    ) throws OSSDatabaseAccessException
139    {
140       Connection JavaDoc conReturn;
141       
142       try
143       {
144          conReturn = (Connection JavaDoc)((ObjectPool)connectionpool.getConnectionPool()).borrowObject();
145       }
146       catch (Exception JavaDoc eExc)
147       {
148          // ObjectPool throws Exception so convert it to something more meaningful here
149
throw new OSSDatabaseAccessException("Cannot get database connection from pool.",
150                                                  eExc);
151       }
152       
153       return conReturn;
154    }
155
156    /**
157     * {@inheritDoc}
158     */

159    protected Connection JavaDoc getPooledConnection(
160       ConnectionPoolDefinition connectionpool,
161       String JavaDoc strUser,
162       String JavaDoc strPassword
163    ) throws OSSDatabaseAccessException
164    {
165       Connection JavaDoc cntDBConnection;
166       
167       // DBCP doesn't provide any way how to get it so ask for nonpooled connection
168
try
169       {
170          cntDBConnection = DriverManager.getConnection(connectionpool.getUrl(),
171                                                        strUser,
172                                                        strPassword);
173          if (cntDBConnection != null)
174          {
175             m_mpNotPooledConnections.put(cntDBConnection, cntDBConnection);
176          }
177       }
178       catch (SQLException JavaDoc sqleExc)
179       {
180          throw new OSSDatabaseAccessException("Cannot get database connection" +
181                                                  " for explicitely specified user.",
182                                                  sqleExc);
183       }
184       
185       return cntDBConnection;
186    }
187
188    /**
189     * {@inheritDoc}
190     */

191    protected Object JavaDoc createConnectionPool(
192       String JavaDoc strConnectionPoolName,
193       String JavaDoc strDriverName,
194       String JavaDoc strUrl,
195       String JavaDoc strUser,
196       String JavaDoc strPassword
197    ) throws OSSException
198    {
199       // I am using here the PoolingDriver instead of PoolingDataSource because
200
// in DBCP version 1.1 the PoolingDriver has clear way how to shutdown
201
// the pool and PoolingDataSource doesn't.
202
// This code was inspired by method setupDriver from
203
// ManualPoolingDriverExample.java in commons-dbcp package v 1.6
204
ObjectPool connectionPool;
205       ConnectionFactory connectionFactory;
206       PoolableConnectionFactory poolableConnectionFactory;
207       
208       PooledDatabaseConnectionFactorySetupReader setupReader
209           = new PooledDatabaseConnectionFactorySetupReader(strConnectionPoolName);
210
211       int iInitialPoolSize = setupReader.getIntegerParameterValue(
212                PooledDatabaseConnectionFactorySetupReader.DBPOOL_INITIAL_SIZE).intValue();
213       int iMinimalPoolSize = setupReader.getIntegerParameterValue(
214                PooledDatabaseConnectionFactorySetupReader.DBPOOL_MIN_SIZE).intValue();
215       int iMaximalPoolSize = setupReader.getIntegerParameterValue(
216                PooledDatabaseConnectionFactorySetupReader.DBPOOL_MAX_SIZE).intValue();
217       boolean bCanGrow = setupReader.getBooleanParameterValue(
218                PooledDatabaseConnectionFactorySetupReader.DBPOOL_CAN_GROW).booleanValue();
219       long lMaxWaitTimeForConnection = setupReader.getLongParameterValue(
220                PooledDatabaseConnectionFactorySetupReader.DBPOOL_WAIT_PERIOD).longValue();
221       boolean bValidateOnBorrow = setupReader.getBooleanParameterValue(
222                PooledDatabaseConnectionFactorySetupReader.DBPOOL_VALIDATE_BORROW).booleanValue();
223       boolean bValidateOnReturn = setupReader.getBooleanParameterValue(
224                PooledDatabaseConnectionFactorySetupReader.DBPOOL_VALIDATE_RETURN).booleanValue();
225       boolean bValidateOnIdle = setupReader.getBooleanParameterValue(
226                PooledDatabaseConnectionFactorySetupReader.DBPOOL_VALIDATE_IDLE).booleanValue();
227       long lTimeBetweenEvictionRunsMillis = setupReader.getLongParameterValue(
228                PooledDatabaseConnectionFactorySetupReader.DBPOOL_IDLE_CHECK_PERIOD).longValue();
229       int iNumTestsPerEvictionRun = setupReader.getIntegerParameterValue(
230                PooledDatabaseConnectionFactorySetupReader.DBPOOL_IDLE_CHECK_SIZE).intValue();
231       long lMinEvictableIdleTimeMillis = setupReader.getLongParameterValue(
232                PooledDatabaseConnectionFactorySetupReader.DBPOOL_IDLE_PERIOD).longValue();
233       int iTransactionIsolation
234              = DatabaseImpl.getInstance().getTransactionIsolation(
235                   PooledDatabaseConnectionFactorySetupReader.convertTransactionIsolationToConstant(
236                      setupReader.getStringParameterValue(
237                         PooledDatabaseConnectionFactorySetupReader.DBPOOL_TRANSACTION_ISOLATION
238                            ).toString()));
239       int iPreparedStatementCacheSize = setupReader.getIntegerParameterValue(
240                PooledDatabaseConnectionFactorySetupReader.DBPOOL_PREPSTATEMENT_CACHE_SIZE
241                   ).intValue();
242       
243       // First, we'll need a ObjectPool that serves as the actual pool of
244
// connections. We'll use a GenericObjectPool instance, although
245
// any ObjectPool implementation will suffice.
246
connectionPool = new GenericObjectPool(
247                               null, // factory will be specified below
248
iMaximalPoolSize,
249                               bCanGrow ? GenericObjectPool.WHEN_EXHAUSTED_GROW
250                                        : GenericObjectPool.WHEN_EXHAUSTED_BLOCK,
251                               lMaxWaitTimeForConnection,
252                               iMaximalPoolSize, // max idle - if no connections are used
253
// the pool should not fall under this size
254
iMinimalPoolSize, // min idle - if connection count falls
255
// under this limit (e.g. closed connections)
256
// new connections will be created
257
bValidateOnBorrow,
258                               bValidateOnReturn,
259                               lTimeBetweenEvictionRunsMillis,
260                               iNumTestsPerEvictionRun,
261                               lMinEvictableIdleTimeMillis,
262                               bValidateOnIdle);
263
264       
265       // Next, we'll create a ConnectionFactory that the pool will use to
266
// create Connections.
267
// I am using DriverManagerConnectionFactory instead of DriverConnectionFactory
268
// because it allows me to specify user name and password directly
269
connectionFactory = new DriverManagerConnectionFactory(
270                                  strUrl, strUser, strPassword);
271
272       // This configuration of prepared statement caching is inspired by
273
// Commons-DBCP Wiki avaiabe at http://wiki.apache.org/jakarta-commons/DBCP
274
// null can be used as parameter because this parameter is set in
275
// PoolableConnectionFactory when creating a new PoolableConnection
276
// 0 according to documentation should mean no limit
277
KeyedObjectPoolFactory statementPool = null;
278       if (iPreparedStatementCacheSize >= 0)
279       {
280          statementPool = new GenericKeyedObjectPoolFactory(null,
281                                                            iPreparedStatementCacheSize);
282       }
283       
284       // Now we'll create the PoolableConnectionFactory, which wraps
285
// the "real" Connections created by the ConnectionFactory with
286
// the classes that implement the pooling functionality.
287
poolableConnectionFactory = new PoolableConnectionFactory(
288                                          connectionFactory,
289                                          connectionPool,
290                                          statementPool,
291                                          DatabaseImpl.getInstance().getConnectionTestStatement(),
292                                          false, // not read-only connection
293
false, // Default auto commit is false
294
iTransactionIsolation);
295
296       // PoolableConnectionFactory doesn't support the initialSize attribute of
297
// DBCP so I have replicated the code from BasicDataSource v1.37 here
298
try
299       {
300          for (int iIndex = 0; iIndex < iInitialPoolSize; iIndex++)
301          {
302             connectionPool.addObject();
303          }
304       }
305       catch (Exception JavaDoc e)
306       {
307          throw new OSSDatabaseAccessException("Error preloading the connection pool", e);
308       }
309       
310       if (GlobalConstants.ERROR_CHECKING)
311       {
312          // Put this check here to trick checkstyle
313
assert poolableConnectionFactory != null
314                 : "Poolable connection factoryh cannot be null.";
315       }
316       
317       return connectionPool;
318    }
319
320    /**
321     * {@inheritDoc}
322     */

323    protected void closeConnectionPool(
324       ConnectionPoolDefinition connectionpool
325    ) throws OSSException
326    {
327       try
328       {
329          ((ObjectPool)connectionpool.getConnectionPool()).close();
330       }
331       catch (Exception JavaDoc eExc)
332       {
333          // ObjectPool throws Exception so convert it to something more meaningful here
334
throw new OSSDatabaseAccessException("Cannot close connection pool.", eExc);
335       }
336    }
337 }
338
Popular Tags