Announcement Announcement Module
Collapse

Spring Dynamic Modules forum decommissioned in favor of Eclipse Gemini Blueprint

With the official first release of Eclipse Gemini Blueprint shipped, the migration of the Spring Dynamic Modules code base to the Eclipse Foundation, as part of the Gemini project, has been completed.

As such, this forum has been decommissioned in favour of the Eclipse Gemini forums.
See more
See less
CNFE when loading mysql jdbc driver Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • CNFE when loading mysql jdbc driver

    Hi There,
    I've trying to deploy the petclinic sample that comes with Spring DM 1.1.1 to ServiceMix 4. Since now SMX runs on top of an OSGi Platform (Apache Felix) and supports Spring DM, I felt like giving the samples that come with Spring DM a try. I was able to deploy and start the contract module, and the sample-mysql module(???). I was able to deploy the sample-jdbc module, but when I try to start it I get the exception below.
    Before deploying and starting the above modules I deployed and started the following modules, which I found in the spring framework's osgi repository:
    [ 112] [Active ] [ 50] Commons Lang (2.4)
    [ 113] [Active ] [ 50] spring-jdbc (2.5.5)
    [ 114] [Active ] [ 50] c3p0.osgi (0.9.1.SNAPSHOT)
    [ 115] [Active ] [ 50] mysql-connector-java.osgi (3.1.14.SNAPSHOT)

    Here is the exception I'm getting:

    21:05:28,214 | WARN | er$PoolThread-#0 | DriverManagerDataSource | log.log4j.Log4jMLog$Log4jMLogger 161 | Could not load driverClass com.mysql.jdbc.Driver
    java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
    at org.apache.felix.framework.searchpolicy.R4SearchPo licyCore.findClass(R4SearchPolicyCore.java:200)
    at org.apache.felix.framework.searchpolicy.R4SearchPo licy.findClass(R4SearchPolicy.java:45)
    at org.apache.felix.framework.searchpolicy.ContentCla ssLoader.loadClass(ContentClassLoader.java:109)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:2 51)
    at java.lang.ClassLoader.loadClassInternal(ClassLoade r.java:374)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:169)
    at com.mchange.v2.c3p0.DriverManagerDataSource.ensure DriverLoaded(DriverManagerDataSource.java:100)
    at com.mchange.v2.c3p0.DriverManagerDataSource.getCon nection(DriverManagerDataSource.java:132)
    at com.mchange.v2.c3p0.WrapperConnectionPoolDataSourc e.getPooledConnection(WrapperConnectionPoolDataSou rce.java:182)
    at com.mchange.v2.c3p0.WrapperConnectionPoolDataSourc e.getPooledConnection(WrapperConnectionPoolDataSou rce.java:171)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$ 1PooledConnectionResourcePoolManager.acquireResour ce(C3P0PooledConnectionPool.java:137)
    at com.mchange.v2.resourcepool.BasicResourcePool.doAc quire(BasicResourcePool.java:1014)
    at com.mchange.v2.resourcepool.BasicResourcePool.acce ss$800(BasicResourcePool.java:32)
    at com.mchange.v2.resourcepool.BasicResourcePool$Acqu ireTask.run(BasicResourcePool.java:1810)
    at com.mchange.v2.async.ThreadPoolAsynchronousRunner$ PoolThread.run(ThreadPoolAsynchronousRunner.java:5 47)
    Caused by: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
    at org.apache.felix.framework.searchpolicy.R4SearchPo licyCore.findClassOrResource(R4SearchPolicyCore.ja va:488)
    at org.apache.felix.framework.searchpolicy.R4SearchPo licyCore.findClass(R4SearchPolicyCore.java:187)
    ... 15 more



    Here are the manifests for each of the petclinic modules in the order I deployed them:
    Contract:
    ======
    Bundle-SymbolicName: [DEMO]OSGi_Domain
    Bundle-Name: sample-contract
    Bundle-Version: 1.0
    Export-Package: org.springframework.osgi.samples.petclinic;version ="1.0.0"
    Import-Package: org.springframework.dao,
    org.apache.commons.lang.builder


    mysql implementation:
    ==============
    Bundle-Version: 1.0
    Bundle-SymbolicName: [DEMO]OSGi_Sample_mySQL
    Bundle-Name: sample-mysqldb
    Import-Package: org.springframework.beans.factory.config,
    org.springframework.dao,
    org.springframework.jdbc,
    com.mysql.jdbc,
    org.springframework.context,
    com.mchange.v2.c3p0,
    javax.sql,
    org.springframework.osgi.samples.petclinic



    Jdbc:
    ====
    Bundle-Version: 1.0
    Bundle-SymbolicName: [DEMO]OSGi_JDBC_Impl
    Bundle-Name: sample-jdbc
    Import-Package: org.springframework.osgi.samples.petclinic;version ="1.0.0",
    org.springframework.dao,
    org.springframework.jdbc.core,
    org.springframework.jdbc.core.support,
    org.springframework.jdbc.object,
    org.springframework.context,
    org.springframework.jmx.export,
    org.springframework.jmx.export.assembler,
    com.mysql.jdbc,
    com.mchange.v2.c3p0,
    javax.sql,
    org.apache.commons.lang.builder



    Please let me know if I'm doing something wrong or missing anything.

    Thanks in advanced,

    - Roberto Rojas
    Software Architect
    Chariot Solutions

  • #2
    Roberto, first of all please use [ c o d e ] tags when posting code.
    I'll check the sample to see what's the problem - it's likely a missing import. By the way, the petclinic sample you refer to is about to be retired in 1.2.0 release - there are other samples in place that show better the web integration and service consumption.
    1.2.0 M1 is scheduled for release this week so if you can wait, I recommend using that for starters.

    Comment


    • #3
      Costin,

      Thanks for replying.
      I'll be more careful next time and use the code tags.

      I agree with the idea of separating the modules in the way is done in the
      petclinic sample. Would Spring DM 1.2.0 M1 come with a similar sample?
      I can certainly wait.


      Cheers,

      - Roberto Rojas
      Software Architect
      Chariot Solutions

      Comment


      • #4
        The separation is present in other samples as well. 1.2.0 M1 will provide a MVC sample that uses Spring 2.5 MVC annotations. The petclinic sample started out of a conference demo and is based rather on JMX as an UI rather then on a web application.
        Additionally, since SpringSource application platform already features petclinic fully (along with other features and other samples), it doesn't add a lot of value to keep the sample in Spring-DM.

        Comment


        • #5
          Costin,

          The value I found in the petclinic sample was the ability to expose the data a layer in a modular fashion. This sample could be used as a starting point, so that, if an existing application had a separate data access module, this module could be OSGi-fied and provided as a bundle and deployed on any OSGi platform, like the one used by SMX4.
          I'll take a look at the Weather sample in the meantime while 1.2.0 M1 is coming out.

          I think Spring DM and OSGi are pretty exciting technologies that could provide a lot of benefits to the ESB implementations.


          Thanks,
          Roberto Rojas
          Software Architect
          Chariot Solutions

          Comment


          • #6
            Make your your own c3p0-Bundle...

            Hi rjrojan,

            i had the same problem the last days. I was looking the samples in Spring-DM too and did all the same they did but it didn't work. Then i looked to the import section on the DataSourcePool-Bundles c3p0 and dbcp. And i think it can not work because both haven't any import for the driver-class-package(s).

            As you can see here in the Enterprise-Bundle-Repository at SpringSource:
            http://www.springsource.com/reposito...ersion=0.9.1.2

            On the end you find the import-section. There are no imports fo "com.mysql.jdbc" or "org.hsqldb.jdbc" or whatever. With "dpcp" it is the same.

            You can fix this by building your own bundle for the DSPool-Bundle with adding the needed import-package header for the driver you want to use. It's not so hard. Look at the springframework-svn-repo how they did it with external-libs and the maven-bundle-plugin.
            I did it with dbcp and it works for me. So i will improve my DSPool-Bundles with all needed imports for all kind of drivers we use in our company.

            An other issue with the imports you postet are in the "JDBC_IMPL". It is the implementation of the Clinic-Interface. As i understand the layering in the right way, this bundle sits between the web and the datasource. So if the mysql-impl-bundle expose a osgi:service with an interface of javax.sql.Datasource and that's all the jdbc-impl-bundle needs. Why do we have imports of "mysql" and "c3p0" ? It should be not aware of what Driver we use or what DS-Pool-Implementation we use. All it has to know is the javax.sql.DataSource-Interface.
            Maybe this comes from the automatic imports of the maven-bundle-plugin. So you can avoid this by using scope "provided" on your deps.

            Spring-DM 1.2 maybe will be cleaned up. OSGi is sometimes a bit tricky with all these "imports" and "exports", so it should be clearer for beginners of osgi and spring-dm.

            Jörg
            Last edited by bellmann29; Sep 4th, 2008, 03:19 PM.

            Comment


            • #7
              Hi Jörg,

              You've got a great point there. I'm not sure that I'm completely sold with the solution though, so I started thinking about the classloader and OSGi bundles.
              And I thought well, maybe this is where Spring IoC can help. Instead of having the ComboPooledDataSource load the class using Class.forName, an instance of the Driver class could be passed to it.
              That way only the bundle with spring context performing the injection needs to provide the package-import and not the DB-Pool bundle include the packages of the jdbc driver to use.

              So I came up with this other way of solving the problem and changed the bundle-context.xml for the petclinic.sample.mysql to provide the datasource in this manner:

              Code:
              <bean id="jdbcDriverClass" class="com.chariotsolutions.springosgi.jdbc.JdbcDriverBootstrap"  factory-method="forName">
              	 	 <constructor-arg value="${jdbc.driverClassName}" />
              	 </bean>
              	 
              	   
              	 <bean id="unPooledDataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource" >
              		<property name="driverClass" ref="jdbcDriverClass" />
              		<property name="url" value="${jdbc.url}" />
              		<property name="username" value="${jdbc.username}"/>
              		<property name="password" value="${jdbc.password}"/>
              	 </bean> 
              
              	
              	 <bean id="dataSource" class="com.mchange.v2.c3p0.DataSources" factory-method="pooledDataSource" >
              	 		<constructor-arg ref="unPooledDataSource"/>
                   </bean>
              The trick is in the class JdbcDriverBootstrap. It does the Class.forName call from within the Bundle that does include the jdbc driver's exported package.
              Here is the code for that class:

              Code:
                 public class JdbcDriverBootstrap {
              	public static Class forName(String className) throws ClassNotFoundException {
              		System.out.println("loading Class for className: " + className);
              		return Class.forName(className);
              	}
              
              }
              As you can see all it does is just wrap the Class.forName method call.
              For the bean jdbcDriverClass, I've also tried using the java.lang.Class directly, but I got the same CNFE error.


              I agree on your point about the packages being imported in a higher level module. Those higher level modules should not care about the implementation of the service.



              Roberto Rojas
              Software Architect
              Chariot Solutions

              Comment


              • #8
                For things to work nicely inside OSGi you need to use the proper class loader. Class.forName() w/o a classloader doesn't do that - there are numerous blogs on the internet discussing it (I'd recommend reading BJ Hargrave's). The idea is good though so consider importing the driver class inside the assembling package and then loading the class directly through spring into C3P0. Briefly looking at c3p0 reveals that it expects all the properties as Strings and then tries to convert them (the driver by class by using Class.forName()) which is not the recommended way.
                It's likely there is a way to pass directly the Driver class, the alternative being to use another datasource (connection pooling) library that allows more configuration options.
                Note that one problem with DriverManager is that it's a VM-wide class and thus it cannot support multiple version of the same driver.

                Comment


                • #9
                  This works ...

                  Hi rjrojas and Costin,

                  i got a working solution for that problem. As you said Costin there are some other datasources or implementations of datasources. I looked around in the javadoc for dbcp and c3p0 and the following
                  configuration works.

                  Code:
                  	<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
                  		<property name="location" value="jdbc.properties"/>
                  	</bean>
                  	
                  	<bean id="mysqlDataSource" class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
                  		<property name="createDatabaseIfNotExist" value="true"/>
                  		<property name="url" value="${jdbc.url}"/>
                  		<property name="user" value="${jdbc.username}"/>
                  		<property name="password" value="${jdbc.password}"/>
                  	</bean>
                  
                  	<!-- Commons-DBCP -->
                  	<bean id="dataSource" class="org.apache.commons.dbcp.datasources.SharedPoolDataSource" lazy-init="false" destroy-method="close">
                  		<property name="connectionPoolDataSource" ref="mysqlDataSource"/>
                  		<property name="maxActive" value="20"/>
                  		<property name="maxIdle" value="3"/>
                  	</bean>
                  	
                  	<!-- c3p0 -->
                          <!-- not tested yet, but should work same way
                  	<bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource" lazy-init="false">
                  		<property name="connectionPoolDataSource" ref="mysqlDataSource"/>
                  		<property name="maxPoolSize" value="15"/>
                  		<property name="minPoolSize" value="3"/>
                  	</bean>
                  	-->
                  	
                  	<!-- export the existing datasource bean into OSGi -->
                  	<osgi:service id="classificationDataSource" ref="dataSource">
                  		<osgi:interfaces>
                  			<value>javax.sql.DataSource</value>
                  		</osgi:interfaces>
                  	</osgi:service>
                  My Manifest-Entries here:

                  Code:
                  ....
                  Import-Package: com.mysql.jdbc;version="[5.1.0,5.5.0)",com.mysql.jdbc.
                  
                   jdbc2.optional;version="[5.1.0,5.5.0)",org.apache.commons.dbcp;versio
                  
                   n="1.2.2.osgi",org.apache.commons.dbcp.datasources;version="1.2.2.osg
                  
                   i",org.apache.commons.logging;version="1.1.1",org.springframework.bea
                  
                   ns.factory.config;version="[2.5.0,3.0.0)",org.springframework.context
                  
                   ;version="[2.5.0,3.0.0)"
                  ....
                  My Test-Code

                  Code:
                  	@Override
                  	protected String[] getTestBundlesNames() {
                  		List<String> bundles = new ArrayList<String>();
                      	bundles.add("com.mysql.jdbc, com.springsource.com.mysql.jdbc, 5.1.6");
                      	bundles.add("org.apache.commons, com.springsource.org.apache.commons.logging, 1.1.1");
                      	bundles.add("org.apache.commons, com.springsource.org.apache.commons.pool, 1.4.0");
                      	bundles.add("org.apache.commons, com.springsource.org.apache.commons.dbcp, 1.2.2.osgi");
                      	//
                      	bundles.add("***.******.*****, ********.ds.mysql, 0.0.1-SNAPSHOT");
                  		return (String[])bundles.toArray(new String[bundles.size()]);
                  	}
                  
                  
                  	public void testMySQLConnection() throws Exception{
                  		waitOnContextCreation("****.*****.*****.ds.mysql");
                  		ServiceReference ref = bundleContext.getServiceReference(DataSource.class.getName());
                  		assertNotNull(ref);
                  		Connection con = null;
                  		try{
                  			DataSource ds = (DataSource)bundleContext.getService(ref);
                  			assertNotNull(ds);
                  			con = ds.getConnection();
                  			assertNotNull(con);
                  			System.out.println("Ich habe eine Connection....");
                  		}finally{
                  			bundleContext.ungetService(ref);
                  			if(con != null){
                  				try {
                  					con.close();
                  					System.out.println("Connection geschlossen....");
                  				} catch (Exception e) {
                  					e.printStackTrace();
                  				} finally{
                  					con = null;
                  				}
                  			}
                  		}
                  	}

                  Hope this helps.


                  Jörg

                  Comment


                  • #10
                    Hi Jörg,
                    I like this approach even better. thx.


                    Hi Costin,
                    Thanks for pointing out the issue with Class.forName(). It's certainly an important thing to know.


                    Roberto

                    Comment

                    Working...
                    X