Thursday, January 28, 2016

Unwrap native oracle connection from WAS connection

The JDBC objects provided by WAS are wrappers, wrapping the underlying jdbc driver objects. Examples are Connection, Statement, ResultSet etc. There may be scenarios where applications will have to access the wrapped objects, usually for invoking non jdbc standard & vendor specific methods and types. Traditionally cWAS has provided the WSCallHelper utility to help applications access the native connections and invoke vendor specific methods. However JDBC4.0 provided a more cleaner and standard way to achieve the same by introducing the java.sql.Wrapper interface and is generally called as the Wrapper Pattern. The Wrapper interface describes the standard mechanism to access the wrapped objects with the methods isWrapperFor() and unwrap(). Here is a sample code snippet which applications can make use of to access the native oracle connection

 InitialContext ctx = new InitialContext(parms); 
 DataSource ds = (DataSource)ctx.lookup(jndi); 
 Connection conn = ds.getConnection(); 
 if (conn.isWrapperFor(oracle.jdbc.OracleConnection.class)) { 
    OracleConnection oraCon=conn.unwrap(oracle.jdbc.OracleConnection.class);
    // PERFORM ORACLE DRIVER SPECIFIC CALLS USING oraCon ..... 
 } 
conn.close();  

Now the above code snippet will work like a charm in most environments. But at times there is a chance to hit the following exception if you unwrap without doing a isWrapperFor() check.

java.sql.SQLException: DSRA9122E: com.ibm.ws.rsadapter.jdbc.WSJdbcConnection@d3t7e556 does not wrap any objects of type oracle.jdbc.OracleConnection.      

The most possible cause of this problem is due to classloader mismatch and for the unwrap to work the specified interface class (ie oracle.jdbc.OracleConnection) must be loaded with the same classloader that is used by the dataSource/jdbcDriver. And how this mismatch can happen ? 

.When you have applications packaging the JDBC driver jars along with them in addition to the the JDBC driver classpath provided in the datasource JDBC provider configuration,  then a classloader mismatch is very much possible. Always avoid packing jdbc driver jars within the application.

Note: These are Nihilson's personal views and does not reflect that of his employer in any way!!

1 comment:

Tim said...

Hi - interesting post!

I am experiencing this exact issue. The problem is, we need those Oracle classes on our application classpath because we need to do Oracle-specific things (we're using Data Change Notifications). So how do you suggest we load the classes into our application?

If the classes aren't packaged with the application, the app doesn't deploy because it can't find the classes.

I tried putting the JDBC classes in a WAS global library, but then you get this same error you described in your post.

This only seem to be in issue for Websphere (it doesn't happen in Weblogic). The only other thing I can think of now is to somehow load the Oracle JDBC classes using the WAS classloader (not sure how to get this though)...any ideas?