You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by ar...@apache.org on 2006/02/22 22:28:16 UTC

svn commit: r379915 - /db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/ConnectionFactoryDBCPImpl.java

Author: arminw
Date: Wed Feb 22 13:28:13 2006
New Revision: 379915

URL: http://svn.apache.org/viewcvs?rev=379915&view=rev
Log:
fix OJB-97, have to extend several classes of dbcp library to fix unexpected behavior

Modified:
    db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/ConnectionFactoryDBCPImpl.java

Modified: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/ConnectionFactoryDBCPImpl.java
URL: http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/ConnectionFactoryDBCPImpl.java?rev=379915&r1=379914&r2=379915&view=diff
==============================================================================
--- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/ConnectionFactoryDBCPImpl.java (original)
+++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/accesslayer/ConnectionFactoryDBCPImpl.java Wed Feb 22 13:28:13 2006
@@ -15,9 +15,21 @@
  * limitations under the License.
  */
 
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
 import org.apache.commons.dbcp.AbandonedConfig;
 import org.apache.commons.dbcp.AbandonedObjectPool;
+import org.apache.commons.dbcp.ConnectionFactory;
 import org.apache.commons.dbcp.DriverManagerConnectionFactory;
+import org.apache.commons.dbcp.PoolableConnection;
 import org.apache.commons.dbcp.PoolableConnectionFactory;
 import org.apache.commons.dbcp.PoolingDataSource;
 import org.apache.commons.pool.KeyedObjectPoolFactory;
@@ -32,16 +44,6 @@
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 import org.apache.ojb.broker.util.logging.LoggerWrapperPrintWriter;
 
-import javax.sql.DataSource;
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Properties;
-
 /**
  * ConnectionFactory implementation using Commons DBCP and Commons Pool API
  * to pool connections.
@@ -81,7 +83,7 @@
         {
             conn = ds.getConnection();
         }
-        catch (SQLException e)
+        catch(SQLException e)
         {
             throw new LookupException("Could not get connection from DBCP DataSource", e);
         }
@@ -94,40 +96,43 @@
         try
         {
             // We are using datasources, thus close returns connection to pool
-            con.close();
+            
+            // we have to check 'isClosed', because otherwise method
+            // org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.checkOpen
+            // will throw an unexpected exception (see javadoc for Coonection.close()) when
+            // con.close() is called several times.
+            if(!con.isClosed()) con.close();
         }
-        catch (SQLException e)
+        catch(SQLException e)
         {
             log.warn("Connection close failed", e);
         }
     }
 
-    /**
-     * Closes all managed pools.
-     */
+    /** Closes all managed pools. */
     public void releaseAllResources()
     {
         super.releaseAllResources();
-        synchronized (poolSynch)
+        synchronized(poolSynch)
         {
-            if (!poolMap.isEmpty())
+            if(!poolMap.isEmpty())
             {
                 Collection pools = poolMap.values();
                 Iterator iterator = pools.iterator();
                 ObjectPool op = null;
-                while (iterator.hasNext())
+                while(iterator.hasNext())
                 {
                     try
                     {
                         op = (ObjectPool) iterator.next();
-                        if (op instanceof GenericObjectPool)
+                        if(op instanceof GenericObjectPool)
                         {
                             // deactivates the idle evictor thread
-                            ((GenericObjectPool)op).setTimeBetweenEvictionRunsMillis(-1);
+                            ((GenericObjectPool) op).setTimeBetweenEvictionRunsMillis(-1);
                         }
                         op.close();
                     }
-                    catch (Exception e)
+                    catch(Exception e)
                     {
                         log.error("Exception occured while closing ObjectPool " + op, e);
                     }
@@ -141,9 +146,10 @@
     /**
      * 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.
+     *         Guaranteed to never be null.
      * @throws LookupException if pool is not in cache and cannot be created
      */
     protected DataSource getDataSource(JdbcConnectionDescriptor jcd)
@@ -151,12 +157,12 @@
     {
         final PBKey key = jcd.getPBKey();
         DataSource ds = (DataSource) dsMap.get(key);
-        if (ds == null)
+        if(ds == null)
         {
             // Found no pool for PBKey
             try
             {
-                synchronized (poolSynch)
+                synchronized(poolSynch)
                 {
                     // Setup new object pool
                     ObjectPool pool = setupPool(jcd);
@@ -166,7 +172,7 @@
                     dsMap.put(key, ds);
                 }
             }
-            catch (Exception e)
+            catch(Exception e)
             {
                 log.error("Could not setup DBCP DataSource for " + jcd, e);
                 throw new LookupException(e);
@@ -178,6 +184,7 @@
     /**
      * 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
      */
@@ -189,17 +196,17 @@
         {
             ClassHelper.newInstance(jcd.getDriver());
         }
-        catch (InstantiationException e)
+        catch(InstantiationException e)
         {
-            log.fatal("Unable to instantiate the driver class: " + jcd.getDriver() + " in ConnectionFactoryDBCImpl!" , e);
+            log.fatal("Unable to instantiate the driver class: " + jcd.getDriver() + " in ConnectionFactoryDBCImpl!", e);
         }
-        catch (IllegalAccessException e)
+        catch(IllegalAccessException e)
         {
-            log.fatal("IllegalAccessException while instantiating the driver class: " + jcd.getDriver() + " in ConnectionFactoryDBCImpl!" , e);
+            log.fatal("IllegalAccessException while instantiating the driver class: " + jcd.getDriver() + " in ConnectionFactoryDBCImpl!", e);
         }
-        catch (ClassNotFoundException e)
+        catch(ClassNotFoundException e)
         {
-            log.fatal("Could not find the driver class : " + jcd.getDriver() + " in ConnectionFactoryDBCImpl!" , e);
+            log.fatal("Could not find the driver class : " + jcd.getDriver() + " in ConnectionFactoryDBCImpl!", e);
         }
 
         // Get the configuration for the connection pool
@@ -232,7 +239,7 @@
         // the classes that implement the pooling functionality.
         //
         final PoolableConnectionFactory poolableConnectionFactory;
-        poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,
+        poolableConnectionFactory = new OJBPoolableConnectionFactory(connectionFactory,
                 connectionPool,
                 statementPoolFactory,
                 validationQuery,
@@ -248,9 +255,12 @@
         final GenericObjectPool connectionPool;
         final boolean doRemoveAbandoned = ac != null && ac.getRemoveAbandoned();
 
-        if (doRemoveAbandoned) {
+        if(doRemoveAbandoned)
+        {
             connectionPool = new AbandonedObjectPool(null, ac);
-        } else {
+        }
+        else
+        {
             connectionPool = new GenericObjectPool();
         }
         connectionPool.setMaxActive(config.maxActive);
@@ -269,7 +279,7 @@
     protected KeyedObjectPoolFactory createStatementPoolFactory(JdbcConnectionDescriptor jcd)
     {
         final String platform = jcd.getDbms();
-        if (platform.startsWith("Oracle9i"))
+        if(platform.startsWith("Oracle9i"))
         {
             // mkalen: let the platform set Oracle-specific statement pooling
             return null;
@@ -279,21 +289,21 @@
         GenericKeyedObjectPoolFactory statementPoolFactory = null;
         final Properties properties = jcd.getConnectionPoolDescriptor().getDbcpProperties();
         final String poolStmtParam = properties.getProperty(PARAM_NAME_POOL_STATEMENTS);
-        if (poolStmtParam != null && Boolean.valueOf(poolStmtParam).booleanValue())
+        if(poolStmtParam != null && Boolean.valueOf(poolStmtParam).booleanValue())
         {
             int maxOpenPreparedStatements = GenericKeyedObjectPool.DEFAULT_MAX_TOTAL;
             final String maxOpenPrepStmtString = properties.getProperty(PARAM_NAME_STATEMENT_POOL_MAX_TOTAL);
-            if (maxOpenPrepStmtString != null)
+            if(maxOpenPrepStmtString != null)
             {
                 maxOpenPreparedStatements = Integer.parseInt(maxOpenPrepStmtString);
             }
             // Use the same values as Commons DBCP BasicDataSource
             statementPoolFactory = new GenericKeyedObjectPoolFactory(null,
-                        -1, // unlimited maxActive (per key)
-                        GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
-                        0, // maxWait
-                        1, // maxIdle (per key)
-                        maxOpenPreparedStatements);
+                    -1, // unlimited maxActive (per key)
+                    GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
+                    0, // maxWait
+                    1, // maxIdle (per key)
+                    maxOpenPreparedStatements);
         }
         return statementPoolFactory;
     }
@@ -304,15 +314,15 @@
      * @param jcd the OJB connection descriptor for the pool to be wrapped
      * @param connectionPool the connection pool to be wrapped
      * @return a DataSource attached to the connection pool.
-     * Connections will be wrapped using DBCP PoolGuard, that will not allow
-     * unwrapping unless the "accessToUnderlyingConnectionAllowed=true" configuration
-     * is specified.
+     *         Connections will be wrapped using DBCP PoolGuard, that will not allow
+     *         unwrapping unless the "accessToUnderlyingConnectionAllowed=true" configuration
+     *         is specified.
      */
     protected DataSource wrapAsDataSource(JdbcConnectionDescriptor jcd,
                                           ObjectPool connectionPool)
     {
         final boolean allowConnectionUnwrap;
-        if (jcd == null)
+        if(jcd == null)
         {
             allowConnectionUnwrap = false;
         }
@@ -331,7 +341,8 @@
         if(jcd != null)
         {
             final AbandonedConfig ac = jcd.getConnectionPoolDescriptor().getAbandonedConfig();
-            if (ac.getRemoveAbandoned() && ac.getLogAbandoned()) {
+            if(ac.getRemoveAbandoned() && ac.getLogAbandoned())
+            {
                 final LoggerWrapperPrintWriter loggerPiggyBack;
                 loggerPiggyBack = new LoggerWrapperPrintWriter(log, Logger.ERROR);
                 dataSource.setLogWriter(loggerPiggyBack);
@@ -355,8 +366,8 @@
      *
      * @param jcd the jdbc-connection-alias for which we are creating a ConnectionFactory
      * @return a DriverManager-based ConnectionFactory that creates Connection instances
-     * using DriverManager, and that follows the lifecycle contract defined in OJB
-     * {@link org.apache.ojb.broker.platforms.Platform} API.
+     *         using DriverManager, and that follows the lifecycle contract defined in OJB
+     *         {@link org.apache.ojb.broker.platforms.Platform} API.
      */
     protected org.apache.commons.dbcp.ConnectionFactory createConnectionFactory(JdbcConnectionDescriptor jcd)
     {
@@ -370,8 +381,9 @@
 
     /**
      * mkalen: Left for binary API-compatibility with OJB 1.0.3 (don't break users' factories)
-     * @deprecated since OJB 1.0.4,
-     * please use {@link #createConnectionPool(org.apache.commons.pool.impl.GenericObjectPool.Config, org.apache.commons.dbcp.AbandonedConfig)}
+     *
+     * @deprecated since OJB 1.0.4, please use
+     * {@link #createConnectionPool(org.apache.commons.pool.impl.GenericObjectPool.Config, org.apache.commons.dbcp.AbandonedConfig)}
      */
     protected ObjectPool createObjectPool(GenericObjectPool.Config config)
     {
@@ -380,8 +392,9 @@
 
     /**
      * mkalen: Left for binary API-compatibility with OJB 1.0.3 (don't break users' factories)
-     * @deprecated since OJB 1.0.4,
-     * please use {@link #wrapAsDataSource(org.apache.ojb.broker.metadata.JdbcConnectionDescriptor, org.apache.commons.pool.ObjectPool)}
+     *
+     * @deprecated since OJB 1.0.4, please use
+     * {@link #wrapAsDataSource(org.apache.ojb.broker.metadata.JdbcConnectionDescriptor, org.apache.commons.pool.ObjectPool)}
      */
     protected PoolingDataSource createPoolingDataSource(ObjectPool connectionPool)
     {
@@ -393,6 +406,8 @@
 
     // ----- end deprecated methods -----
 
+
+    
     //**************************************************************************************
     // Inner classes
     //************************************************************************************
@@ -401,6 +416,7 @@
      * Inner class used as factory for DBCP connection pooling.
      * Adhers to OJB platform specification by calling platform-specific init methods
      * on newly created connections.
+     *
      * @see org.apache.ojb.broker.platforms.Platform#initializeJdbcConnection
      */
     class ConPoolFactory extends DriverManagerConnectionFactory
@@ -417,13 +433,13 @@
         public Connection createConnection() throws SQLException
         {
             final Connection conn = super.createConnection();
-            if (conn != null)
+            if(conn != null)
             {
                 try
                 {
                     initializeJdbcConnection(conn, jcd);
                 }
-                catch (LookupException e)
+                catch(LookupException e)
                 {
                     log.error("Platform dependent initialization of connection failed", e);
                 }
@@ -431,6 +447,138 @@
             return conn;
         }
 
+    }
+
+    /**
+     * Specific OJB version of {@link org.apache.commons.dbcp.PoolableConnectionFactory}. This is
+     * needed because the DBCP version cause some unexpected behavior - see overridden methods
+     * {@link #passivateObject(Object)}, {@link #activateObject(Object)} and {@link #makeObject()}.
+     */
+    static class OJBPoolableConnectionFactory extends PoolableConnectionFactory
+    {
+        public OJBPoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, boolean defaultReadOnly, boolean defaultAutoCommit)
+        {
+            super(connFactory, pool, stmtPoolFactory, validationQuery, defaultReadOnly, defaultAutoCommit);
+        }
+
+        public OJBPoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, boolean defaultReadOnly, boolean defaultAutoCommit, int defaultTransactionIsolation)
+        {
+            super(connFactory, pool, stmtPoolFactory, validationQuery, defaultReadOnly, defaultAutoCommit, defaultTransactionIsolation);
+        }
+
+        public OJBPoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, boolean defaultReadOnly, boolean defaultAutoCommit, AbandonedConfig config)
+        {
+            super(connFactory, pool, stmtPoolFactory, validationQuery, defaultReadOnly, defaultAutoCommit, config);
+        }
+
+        public OJBPoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, boolean defaultReadOnly, boolean defaultAutoCommit, int defaultTransactionIsolation, AbandonedConfig config)
+        {
+            super(connFactory, pool, stmtPoolFactory, validationQuery, defaultReadOnly, defaultAutoCommit, defaultTransactionIsolation, config);
+        }
+
+        public OJBPoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, boolean defaultReadOnly, boolean defaultAutoCommit, int defaultTransactionIsolation, String defaultCatalog, AbandonedConfig config)
+        {
+            super(connFactory, pool, stmtPoolFactory, validationQuery, defaultReadOnly, defaultAutoCommit, defaultTransactionIsolation, defaultCatalog, config);
+        }
+
+        public OJBPoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, Boolean defaultReadOnly, boolean defaultAutoCommit, int defaultTransactionIsolation, String defaultCatalog, AbandonedConfig config)
+        {
+            super(connFactory, pool, stmtPoolFactory, validationQuery, defaultReadOnly, defaultAutoCommit, defaultTransactionIsolation, defaultCatalog, config);
+        }
+
+        /**
+         * Don't change autocommit state - This is handled by OJB.
+         */
+        public void passivateObject(final Object obj) throws Exception
+        {
+            if(obj instanceof OJBPoolableConnection)
+            {
+                OJBPoolableConnection conn = (OJBPoolableConnection) obj;
+                conn.clearWarnings();
+                // do not change, will be managed by OJB
+                //conn.setAutoCommit(true);
+
+                conn.passivate();
+            }
+            else
+            {
+                super.passivateObject(obj);
+            }
+        }
+
+        /**
+         * Don't change autocommit state, don't rollback connection when autocommit
+         * is set false and connection is not readonly - This is handled by OJB.
+         */
+        public void activateObject(final Object obj) throws Exception
+        {
+            if(obj instanceof OJBPoolableConnection)
+            {
+                OJBPoolableConnection conn = (OJBPoolableConnection) obj;
+                conn.activate();
+                // do not change, will be managed by OJB
+                // conn.setAutoCommit(_defaultAutoCommit);
+                if(_defaultTransactionIsolation != -1 && _defaultTransactionIsolation != conn.getTransactionIsolation())
+                {
+                    conn.setTransactionIsolation(_defaultTransactionIsolation);
+                }
+                if(_defaultReadOnly.booleanValue() != conn.isReadOnly())
+                {
+                    conn.setReadOnly(_defaultReadOnly.booleanValue());
+                }
+                if(_defaultCatalog != null)
+                {
+                    conn.setCatalog(_defaultCatalog);
+                }
+            }
+            else
+            {
+                super.activateObject(obj);
+            }
+        }
+
+        /**
+         * Wraps the {@link org.apache.commons.dbcp.PoolableConnection} with
+         * {@link org.apache.ojb.broker.accesslayer.ConnectionFactoryDBCPImpl.OJBPoolableConnection}
+         * to allow access to protected methods.
+         */
+        synchronized public Object makeObject() throws Exception
+        {
+            PoolableConnection con = (PoolableConnection) super.makeObject();
+            return new OJBPoolableConnection(con, _pool, _config);
+        }
+    }
+
+    /**
+     * Needed to allow usage of methods {@link #activate()} and {@link #passivate()}
+     * in class {@link org.apache.ojb.broker.accesslayer.ConnectionFactoryDBCPImpl.OJBPoolableConnectionFactory}.
+     */
+    static class OJBPoolableConnection extends PoolableConnection
+    {
+        public OJBPoolableConnection(final Connection conn, final ObjectPool pool)
+        {
+            super(conn, pool);
+        }
+
+        public OJBPoolableConnection(final Connection conn, final ObjectPool pool, final AbandonedConfig config)
+        {
+            super(conn, pool, config);
+        }
+
+        protected void activate()
+        {
+            super.activate();
+        }
+
+        protected void passivate() throws SQLException
+        {
+            super.passivate();
+        }
+
+        public synchronized void close() throws SQLException
+        {
+            if(!isClosed()) super.close();
+        }
     }
 
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org