Thursday, December 18, 2008

Sharing an Oracle JDBC pool in SMX4

In a previous post, I talked about how to share a JDBC pool using ServiceMix4; in that example, I used a Postgres connection pool. I wanted to the same with Oracle as the base driver and the commons-dbcp pooling library and went on my merry way. But then, disaster struck: I got a dreaded ClassNotFound exception. "Can this be?" I thought... isn't OSGi supposed to shield me from class-loading hell and put some colour back into my graying hair?

Delving in, I figured out what the issue was, and, I'm glad to say, the ServiceMix OSGi kernel was behaving exactly as it should. I had wrapped the commons-dbcp JAR without much thought: it turns out that code in the commons org.apache.commons.dbcp.BasicDataSource class (see below) is doing a Class.forName() call to load the oracle.jdbc.driver.OracleDriver class.

<bean id="oracle-ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:BLAH"/>
<property name="username" value="blah"/>
<property name="password" value="blah"/>
<property name="maxActive" value="10"/>
<property name="poolPreparedStatements" value="true"/>
</bean>

Now, OSGi bundles have to specify the packages they import using the Import-Package tag. That's all well and good if you know what these packages are in advance. Poor commons-dbcp can't know in advance what kind of driver it should load, so Import-Package just doesn't work here. Instead, you've got to allow the commons-dbcp bundle to import anything: you can do this using the DynamicImport-Package tag, setting it to DynamicImport-Package: *.

We're currently patching the commons-dbcp bundle on the ServiceMix bundle repository so that it includes the DynamicImport-Package: * tag by default.

4 comments:

Gita said...

Hi,
I am experiencing an issue with smx 4.2 with dbcp and oracle driver.
I am configuring activemq_broker.xml inside smx4.2 to use oracle persistency.
Then I deployed dbcp in isgi as below
osgi:install -s mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-dbcp/1.2.2_5
then deployed oracle driver as below
osgi:install -s file:C:/phaseforward/workspace/servicemix/apache-servicemix-4.2.0/lib/ojdbc14.jar

I am getting error as below. Any help would be greatly appreciated
Thank you in advance.
Caused by: java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver

Ade said...

Hi Gita,

I think you might want to use 'wrap:' before the path of the ojdbc14.jar. AFAIR, the jar is not an OSGi bundle, so you have to instruct SMX to wrap it as a bundle.

Let me know how you get on - in the meantime, if you have any other technical questions around FUSE, you should post them up onto the forums at fusesource.com!

Unknown said...

Hi, I have a problem with DB connection.
I'v creted bundle with ojdbc that contains ojdbc5.
I'v defined feature:

mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-dbcp/1.2.2_5
mvn:org.apache.servicemix.examples.jdbc-test/pl.touk.bundles.ojdbc5/11.1.0.7.0


Everyting is fine till using Class.forName("oracle.jdbc.driver.OracleDriver"); in my service implementation.
I'm getting ClassNotFoundException: oracle.jdbc.OracleDriver.

Could you please give me some advice how to manage with that problem ?

Ade said...

Hi Kes,

Not sure what the problem is here, but I'm wondering have you added the correct dynamic imports into the bundle that you're calling Class.forName("...")? Dynamic imports are crucial for when you're doing dynamic class loading.

Hope that helps. If not, then the best place to follow up on question like this would be on the ServiceMix or Karaf user mailing lists. Checkout the lists on servicemix.apache.org and karaf.apache.org.