Bug 55078 - Configuring a DataSource Resource with dataSourceJNDI does not work as expected
Summary: Configuring a DataSource Resource with dataSourceJNDI does not work as expected
Status: NEW
Alias: None
Product: Tomcat Modules
Classification: Unclassified
Component: jdbc-pool (show other bugs)
Version: unspecified
Hardware: All All
: P2 normal (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
Depends on:
Reported: 2013-06-07 18:57 UTC by Timothy Stewart
Modified: 2013-06-20 20:07 UTC (History)
0 users

Possible fix (26.60 KB, text/plain)
2013-06-07 23:56 UTC, Timothy Stewart

Note You need to log in before you can comment on or make changes to this bug.
Description Timothy Stewart 2013-06-07 18:57:48 UTC
Documentation at http://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html indicates that one may use the dataSourceJNDI attribute to indicate the JNDI name of the datasource to provide connections to the pool.  This actually doesn't work.

In the code for class org.apache.tomcat.jdbc.pool.PooledConnection, we have an outstanding "TODO".

Because of this TODO, the dataSourceJNDI is ignored, and the code ends up going down the connectUsingDriver path, which ultimately logs a SQLException and throws a NamingException.

The following is my current Resource configuration:

		<Resource name="jdbc/dmi/source/dse"
			aliases="dse|dse@$dse" />

		<Resource name="jdbc/dmi/dse"
			maxIdle="16" maxActive="16"
			validationQuery="select 1 from dual"
			dataSourceJNDI="java:comp/env/jdbc/dmi/source/dse" />

Note the "connection source" is an internal corporate datasource instantiated as a bean.  We want to use that bean to provide connections into the Tomcat JDBC pool and have it configured using a dataSourceJNDI reference.

The root-cause stack trace that is logged is:

        at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:243)
        at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:176)
        at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:659)
        at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:601)
        at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:464)
        at org.apache.tomcat.jdbc.pool.ConnectionPool.<init>(ConnectionPool.java:130)
        at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:112)
        at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:99)
        at org.apache.tomcat.jdbc.pool.DataSourceFactory.createDataSource(DataSourceFactory.java:499)
        at org.apache.tomcat.jdbc.pool.DataSourceFactory.getObjectInstance(DataSourceFactory.java:222)
        at org.apache.naming.factory.ResourceFactory.getObjectInstance(ResourceFactory.java:143)
        at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:321)
        at org.apache.naming.NamingContext.lookup(NamingContext.java:826)

PooledConnection code is below.  The problem is clearly the outstanding TODO.

    public void connect() throws SQLException {
        if (released.get()) throw new SQLException("A connection once released, can't be reestablished.");
        if (connection != null) {
            try {
            } catch (Exception x) {
                log.debug("Unable to disconnect previous connection.", x);
            } //catch
        } //end if
        if (poolProperties.getDataSource()==null && poolProperties.getDataSourceJNDI()!=null) {
            //TODO lookup JNDI name

        if (poolProperties.getDataSource()!=null) {
        } else {

        //set up the default state, unless we expect the interceptor to do it
        if (poolProperties.getJdbcInterceptors()==null || poolProperties.getJdbcInterceptors().indexOf(ConnectionState.class.getName())<0 ||
                poolProperties.getJdbcInterceptors().indexOf(ConnectionState.class.getSimpleName())<0) {
            if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) connection.setTransactionIsolation(poolProperties.getDefaultTransactionIsolation());
            if (poolProperties.getDefaultReadOnly()!=null) connection.setReadOnly(poolProperties.getDefaultReadOnly().booleanValue());
            if (poolProperties.getDefaultAutoCommit()!=null) connection.setAutoCommit(poolProperties.getDefaultAutoCommit().booleanValue());
            if (poolProperties.getDefaultCatalog()!=null) connection.setCatalog(poolProperties.getDefaultCatalog());
        this.discarded = false;
        this.lastConnected = System.currentTimeMillis();
Comment 1 Timothy Stewart 2013-06-07 23:56:48 UTC
Created attachment 30407 [details]
Possible fix

Replaced the TODO with a JNDI lookup and set the datasource on the poolProperties before continuing.  This is a possible fix.
Comment 2 Timothy Stewart 2013-06-08 03:56:15 UTC
This problem isn't quite what I thought.  I have some other issue than the one I described.  The org.apache.tomcat.jdbc.pool.DataSourceFactory has code to resolve the DataSource from JNDI, and set it on the PoolConfiguration.  It seems to work for most DataSources in my app, but not this one.

I'm not sure whether to close this bug, or leave it open as a low priority.  I feel the TODO could be resolved, and since the property is on the PooledConnection class configuration, other custom factories might not expect to do the JNDI lookup yourself.  It is very minor at this point, but I think it would be safer for this class to do the resolution if it is not already resolved.

Anyhow, if I find my original problem is a real Tomcat issue, I'll either comment here if related or open something else.
Comment 3 Christopher Schultz 2013-06-10 14:25:05 UTC
So, you are saying that your patch is appropriate, but it still doesn't fix the actual problem you are having?
Comment 4 Mark Thomas 2013-06-20 20:07:55 UTC
Moving to the correct project.