mkalen 2005/03/16 09:51:19
Modified: src/java/org/apache/ojb/broker/accesslayer Tag:
OJB_1_0_RELEASE ConnectionFactoryDBCPImpl.java
. Tag: OJB_1_0_RELEASE release-notes.txt
Log:
Fix DBCP connection factory to call platform-specific connection init.
Resolve issue with statement caching in both DBCP pool and Oracle-driver by
disabling DBCP-caching if platform=Oracle9i (since DBCP does not know how to
manage Oracle server-side cursors correctly).
Revision Changes Path
No revision
No revision
1.10.2.1 +177 -45
db-ojb/src/java/org/apache/ojb/broker/accesslayer/ConnectionFactoryDBCPImpl.java
Index: ConnectionFactoryDBCPImpl.java
===================================================================
RCS file:
/home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/ConnectionFactoryDBCPImpl.java,v
retrieving revision 1.10
retrieving revision 1.10.2.1
diff -u -r1.10 -r1.10.2.1
--- ConnectionFactoryDBCPImpl.java 23 May 2004 16:36:53 -0000 1.10
+++ ConnectionFactoryDBCPImpl.java 16 Mar 2005 17:51:18 -0000 1.10.2.1
@@ -1,6 +1,6 @@
package org.apache.ojb.broker.accesslayer;
-/* Copyright 2002-2004 The Apache Software Foundation
+/* Copyright 2002-2005 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,60 +21,63 @@
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.KeyedObjectPoolFactory;
import org.apache.commons.pool.ObjectPool;
+import org.apache.commons.pool.KeyedPoolableObjectFactory;
import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
+import org.apache.commons.pool.impl.GenericKeyedObjectPool;
import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
import org.apache.ojb.broker.util.ClassHelper;
import org.apache.ojb.broker.util.logging.Logger;
import org.apache.ojb.broker.util.logging.LoggerFactory;
+import org.apache.ojb.broker.PBKey;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Collections;
/**
- * ConnectionFactory implementation using jakarta-DBCP
+ * ConnectionFactory implementation using Jakarta DBCP and Commons Pool
* to pool driver based connections.
*
- * (based on a proposal of Dirk Verbeek - Thanks).
+ * Based on a proposal of Dirk Verbeek - Thanks.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Armin Waibel</a>
* @version $Id$
*/
public class ConnectionFactoryDBCPImpl extends ConnectionFactoryAbstractImpl
{
+
private Logger log =
LoggerFactory.getLogger(ConnectionFactoryDBCPImpl.class);
- private Map poolMap = new HashMap();
+ /** Key=PBKey, value=ObjectPool. */
+ private Map poolMap = Collections.synchronizedMap(new HashMap());
+ /** Key=PBKey, value=PoolingDataSource. */
+ private Map dsMap = Collections.synchronizedMap(new HashMap());
+ /** Synchronize object for operations not synchronized on Map only. */
+ private Object poolSynch = new Object();
public Connection getConnectionFromPool(JdbcConnectionDescriptor jcd)
throws LookupException
{
- DataSource ds = (DataSource) poolMap.get(jcd.getPBKey());
- if (ds == null) // found no pool for PBKey
- {
- try
- {
- // setup new pool
- ds = setupPool(jcd);
- poolMap.put(jcd.getPBKey(), ds);
- }
- catch (Exception e)
- {
- log.error("Could not setup DataSource for " + jcd, e);
- throw new LookupException(e);
- }
- }
+ final DataSource ds = getDataSource(jcd);
+
+ // Returned DS is never null, exception are logged by getDataSource
and gets
+ // re-thrown here since we don't catch them
+
+ Connection conn;
try
{
- Connection con = ds.getConnection();
- return con;
+ conn = ds.getConnection();
}
catch (SQLException e)
{
- throw new LookupException("Can't get connection from
DBCP-DataSource", e);
+ throw new LookupException("Could not get connection from DBCP
DataSource", e);
}
+ return conn;
}
public void returnConnectionToPool(JdbcConnectionDescriptor jcd,
Connection con)
@@ -82,7 +85,7 @@
{
try
{
- // we using datasources, thus close return connection to pool
+ // We are using datasources, thus close returns connection to
pool
con.close();
}
catch (SQLException e)
@@ -92,11 +95,82 @@
}
/**
- * Override this method to setup your own pool
+ * Closes all managed pools.
*/
- protected DataSource setupPool(JdbcConnectionDescriptor jcd)
+ public void releaseAllResources()
{
- log.info("Create new DBCP connection pool:" + jcd);
+ super.releaseAllResources();
+ synchronized (poolSynch)
+ {
+ if (!poolMap.isEmpty())
+ {
+ Collection pools = poolMap.values();
+ Iterator iterator = pools.iterator();
+ ObjectPool op = null;
+ while (iterator.hasNext())
+ {
+ try
+ {
+ op = (ObjectPool) iterator.next();
+ op.close();
+ }
+ catch (Exception e)
+ {
+ log.error("Exception occured while closing
ObjectPool " + op, e);
+ }
+ }
+ poolMap.clear();
+ }
+ dsMap.clear();
+ }
+ }
+
+ /**
+ * Returns the DBCP DataSource for the specified connection descriptor,
+ * after creating a new DataSource if needed.
+ * @param jcd the descriptor for which to return a DataSource
+ * @return a DataSource, after creating a new pool if needed.
+ * Guaranteed to never be null.
+ * @throws LookupException if pool is not in cache and cannot be created
+ */
+ protected DataSource getDataSource(JdbcConnectionDescriptor jcd)
+ throws LookupException
+ {
+ final PBKey key = jcd.getPBKey();
+ DataSource ds = (DataSource) dsMap.get(key);
+ if (ds == null)
+ {
+ // Found no pool for PBKey
+ try
+ {
+ synchronized (poolSynch)
+ {
+ // Setup new object pool
+ ObjectPool pool = setupPool(jcd);
+ poolMap.put(key, pool);
+ // Create a DBCP PoolingDataSource from the object pool
+ ds = createPoolingDataSource(pool);
+ dsMap.put(key, ds);
+ }
+ }
+ catch (Exception e)
+ {
+ log.error("Could not setup DBCP DataSource for " + jcd, e);
+ throw new LookupException(e);
+ }
+ }
+ return ds;
+ }
+
+ /**
+ * Returns a new ObjectPool for the specified connection descriptor.
+ * Override this method to setup your own pool.
+ * @param jcd the connection descriptor for which to set up the pool
+ * @return a newly created object pool
+ */
+ protected ObjectPool setupPool(JdbcConnectionDescriptor jcd)
+ {
+ log.info("Create new ObjectPool for DBCP connections:" + jcd);
try
{
@@ -121,11 +195,6 @@
// First, we'll need a ObjectPool that serves as the
// actual pool of connections.
- //
- // We'll use a GenericObjectPool instance, although
- // any ObjectPool implementation will suffice.
- //
- // TODO: make objectPool configurable at runtime?
ObjectPool connectionPool = createObjectPool(conf);
// Next, we'll create a ConnectionFactory that the
@@ -134,7 +203,7 @@
//
org.apache.commons.dbcp.ConnectionFactory connectionFactory =
createConnectionFactory(jcd);
- KeyedObjectPoolFactory statementPoolFactory =
createStatementPoolFactory(null);
+ KeyedObjectPoolFactory statementPoolFactory =
createStatementPoolFactory(jcd);
// set the validation query
String validationQuery =
jcd.getConnectionPoolDescriptor().getValidationQuery();
boolean defaultReadOnly = false;
@@ -159,31 +228,94 @@
defaultAutoCommit,
ac);
- //
- // Finally, we create the PoolingDriver itself,
- // passing in the object pool we created.
- //
- PoolingDataSource dataSource =
createPoolingDataSource(poolableConnectionFactory.getPool());
- return dataSource;
+ return poolableConnectionFactory.getPool();
}
protected ObjectPool createObjectPool(GenericObjectPool.Config config)
{
+ // We'll use a GenericObjectPool instance, although
+ // any ObjectPool implementation will suffice.
+ //
+ // TODO: make objectPool configurable at runtime?
return new GenericObjectPool(null, config);
}
- protected org.apache.commons.dbcp.ConnectionFactory
createConnectionFactory(JdbcConnectionDescriptor jcd)
+ protected KeyedObjectPoolFactory
createStatementPoolFactory(JdbcConnectionDescriptor jcd)
{
- return new DriverManagerConnectionFactory(getDbURL(jcd),
jcd.getUserName(), jcd.getPassWord());
- }
+ final String platform = jcd.getDbms();
+ if (platform.equals("Oracle9i"))
+ {
+ // mkalen: let the platform set Oracle-specific statement pooling
+ return null;
+ }
- protected KeyedObjectPoolFactory createStatementPoolFactory(Object obj)
- {
- return new GenericKeyedObjectPoolFactory(null);
+ final KeyedObjectPoolFactory stmtPoolFactory;
+ final KeyedPoolableObjectFactory objectFactory = null;
+ final GenericKeyedObjectPool.Config factoryConfig = new
GenericKeyedObjectPool.Config();
+ /*
+ // TODO: mkalen: allow to configure PreparedStatement pool
+ final int maxTotalStmts = 100;
+ factoryConfig.maxActive = (int) (maxTotalStmts * 0.7);
+ factoryConfig.maxIdle = (int) (maxTotalStmts * 0.3);
+ factoryConfig.maxTotal = maxTotalStmts;
+ factoryConfig.testOnBorrow = true;
+ factoryConfig.testWhileIdle = true;
+ factoryConfig.testOnReturn = true;
+ factoryConfig.numTestsPerEvictionRun = factoryConfig.maxTotal;
+ factoryConfig.minEvictableIdleTimeMillis = 30 * 1000;
+ */
+ stmtPoolFactory = new GenericKeyedObjectPoolFactory(objectFactory,
factoryConfig);
+ return stmtPoolFactory;
}
protected PoolingDataSource createPoolingDataSource(ObjectPool pool)
{
return new PoolingDataSource(pool);
}
+
+ protected org.apache.commons.dbcp.ConnectionFactory
createConnectionFactory(JdbcConnectionDescriptor jcd)
+ {
+ return new ConPoolFactory(jcd);
+ }
+
+
//**************************************************************************************
+ // Inner classes
+
//************************************************************************************
+
+ /**
+ * Inner class used as factory for connection pooling.
+ * Adhers to OJB platform specification by calling platform-specific
init methods
+ * on newly created connections.
+ * @see DriverManagerConnectionFactory
+ */
+ class ConPoolFactory extends DriverManagerConnectionFactory
+ {
+
+ private final JdbcConnectionDescriptor jcd;
+
+ public ConPoolFactory(JdbcConnectionDescriptor jcd)
+ {
+ super(getDbURL(jcd), jcd.getUserName(), jcd.getPassWord());
+ this.jcd = jcd;
+ }
+
+ public Connection createConnection() throws SQLException
+ {
+ final Connection conn = super.createConnection();
+ if (conn != null)
+ {
+ try
+ {
+ initializeJdbcConnection(conn, jcd);
+ }
+ catch (LookupException e)
+ {
+ log.error("Platform dependent initialization of
connection failed", e);
+ }
+ }
+ return conn;
+ }
+
+ }
+
}
No revision
No revision
1.54.2.35 +4 -5 db-ojb/release-notes.txt
Index: release-notes.txt
===================================================================
RCS file: /home/cvs/db-ojb/release-notes.txt,v
retrieving revision 1.54.2.34
retrieving revision 1.54.2.35
diff -u -r1.54.2.34 -r1.54.2.35
--- release-notes.txt 16 Mar 2005 11:38:17 -0000 1.54.2.34
+++ release-notes.txt 16 Mar 2005 17:51:18 -0000 1.54.2.35
@@ -40,6 +40,9 @@
please see comments in OJB.properties file.
CHANGES:
+- When using Oracl9i platform and DBCP connection factory, no
PreparedStatement caching will occur
+ in the DBCP pool (Oracle JDBC-driver statement caching is performed by the
platform as default).
+ statement pool, to avoid running out of server-side cursors when using
Oracle9i platform.
- Oracle9i default platform should now be usable and have large LOB support
in JBoss environemnts,
please try the default Oracle9i platform and report your results to the
ojb-user list.
- Oracle9i default platform should now be usable and have large LOB support
in BEA WebLogic,
@@ -151,10 +154,6 @@
in production environments. The future of the OTM layer will be subject
for discussion on the
OJB developers list, if you are using it - please subscribe to ojb-dev and
make your voice heard.
- Oracle9i platform: when using statement batching, there is a 2k limit on
BLOB + 4k limit on CLOB.
-- Oracle9i platform: when using ConnectionFactoryDBCPImpl OJB can run out of
Oracle cursors,
- since prepared statements are cached by the default DBCP connection
factory. A work-around
- is to extend ConnectionFActoryDBCPImpl and override the
createStatementPoolFactory()-method
- with a null-return (=no DBCP PreparedStatement cache).
---------------------------------------------------------------------
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]