"No suitable driver found" exception with multiple classloaders

Bug #876476 reported by Thomas Becker
10
This bug affects 2 people
Affects Status Importance Assigned to Milestone
BoneCP
Fix Released
Medium
Wallace Wadge

Bug Description

Hi all,

we're encountering a "No suitable driver found" Exception in the following scenario:

- Jetty Servlet Engine doing Session persistency via jdbc (no matter what database driver is used, we tried with postgres and mysql)
- webapp using bonecp to connect to a mysql database

Everything works fine if we disable session persistency via jdbc by jetty. The root cause is BoneCP.obtainInitialRawConnection is doing an immediate DriverManager.getConnection() call, but the mysql driver hasn't been loaded by the webapps classloader yet. The reason this works fine when we disable session persistency via jdbc in jetty is that DriverManager.initialized is false then and the getConnection call will initialize DriverManager and thus load all drivers it can find by the current classloader.

BoneCP should take better care to initialize the Driver before trying to do a getConnection and rely on DriverManager to take care for registering the driver.

Could you please also confirm that this error only affects the first getConnection call and that the datasource should work fine after the exception is being thrown?

I can give you further details if needed.

Cheers,
Thomas

Stacktrace:

 [Sep 21 01:50:22] ERROR (JCLLoggerAdapter.java:456) - Unable to open a test connection to the given database. JDBC url = jdbc:mysql://somemysqldb:3306/somedb, username = username. Terminating connection pool. Original Exception: ------^M
java.sql.SQLException: No suitable driver found for jdbc:mysql://somemysqldb:3306/somedb
        at java.sql.DriverManager.getConnection(DriverManager.java:602)
        at java.sql.DriverManager.getConnection(DriverManager.java:185)
        at com.jolbox.bonecp.BoneCP.obtainRawInternalConnection(BoneCP.java:230)
        at com.jolbox.bonecp.BoneCP.<init>(BoneCP.java:255)
        at com.jolbox.bonecp.BoneCPDataSource.maybeInit(BoneCPDataSource.java:127)
        at com.jolbox.bonecp.BoneCPDataSource.getConnection(BoneCPDataSource.java:89)
        at com.jolbox.bonecp.BoneCPDataSource$$FastClassByCGLIB$$d9d91e76.invoke(<generated>)
        at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
        at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:688)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
        at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:621)
        at com.operative.framework.dao.common.OperativeBasicDataSource$$EnhancerByCGLIB$$3517e69d.getConnection(<generated>)
        at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:81)
        at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:111)
        at org.hibernate.cfg.Configuration.buildSettingsInternal(Configuration.java:2119)
        at org.hibernate.cfg.Configuration.buildSettings(Configuration.java:2115)
        at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1339)
        at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:867)
        at org.springframework.orm.hibernate3.LocalSessionFactoryBean.newSessionFactory(LocalSessionFactoryBean.java:860)
        at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:779)
        at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:211)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:322)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedMap(BeanDefinitionValueResolver.java:378)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:161)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1325)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1086)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:322)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1325)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1086)

Revision history for this message
Wallace Wadge (wwadge) wrote :

Hi,

That initial call is a sanity check to make sure the URL etc you have passed in are valid.

I'm not very familiar on the way you're asking me to initialize the driver - can you elaborate a bit pls or provide me with some pointers?

Thanks re hint re website being down -- provider being idiotic as usual. Should become active in a few hours as DNS propagates.

Revision history for this message
Thomas Becker (tbecker) wrote :

Hi Wallace,

thanks for the quick reply. :) You could for example just call Class.forName([Driver]) before doing the getConnection call or check if the driver is available by doing a DriverManager.getDriver() call upfront and if not (exception thrown) call DriverManager.registerDriver().

Just to mention it: The getConnection call you do initially in BoneCP.obtainRawInternalConnection() will iniitialize the driver successfully as the method called in DriverManager line 576 will register the driver. But that's already inside the loop where it iterates over the available drivers so the iteration will stop before the index of the new driver and the "no suitable driver" exception is being thrown in DriverManager line 602. So afterwards BoneCP will be able to obtain connections using the driver which failed on the first call. But am not sure on the side effects it might have, because the exception is thrown inside the constructor of BoneCP.

Cheers,
Thomas

Wallace Wadge (wwadge)
Changed in bonecp:
status: New → Confirmed
importance: Undecided → Medium
assignee: nobody → Wallace Wadge (wwadge)
Revision history for this message
Thomas Becker (tbecker) wrote :

Hi Wallace,

thanks for confirming the bug. Do you have any plans/estimations when you'll be able to fix it and when you'll cut a new release? We're encountering this issue in production and would love to have it fixed soon.

Cheers,
Thomas

Revision history for this message
Wallace Wadge (wwadge) wrote :

Fixed!

(Sorry for very late reply -- new kid in the house ate up all my time!)

Revision history for this message
Wallace Wadge (wwadge) wrote :

In 0.8.x branch.

Changed in bonecp:
status: Confirmed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.