In a plain old classpath context, you would invoke
DriverManager.getConnection()
, maybe after loading the driver class using Class.forName()
, if your driver does not support the Service Provider mechanism which is mandatory for JDBC 4.0.The trouble is, even if your driver does provide the
META-INF/services
metadata, this does not work in OSGi, since DriverManager creates a number of class loader problems by using Class.forName()
internally.I'm working with a variant of the Zentus driver for SQLite, which I've modified slightly to build an OSGi bundle under Java 1.6. I added the service metadata, and indeed my application code now works without loading the driver via
Class.forName()
- as long as the code is running outside of OSGi.There are the following issues:
- The context class loader of the current thread is used to scan for
META-INF/services
resources and to load the referenced classes. This happens during initialization of DriverManager, so it will not catch resources from bundles which are not visible to the current context. - Additional drivers can register with DriverManager, they should do so in static initalization code, so that the driver gets registered when someone calls
Class.forName("my.own.Driver")
. DriverManager.getConnection()
iterates over the registered drivers until it finds one that can process the given URL. Unfortunately, it does a fatal double check to see if the class of that driver is the same that would be obtained by the caller. This amounts to callingClass.forName("some.matching.Driver", ccl)
where ccl is the caller's class loader.
DriverManager.setLogStream(System.out)
.)The third point means that
DriverManager.getConnection()
will always fail if the driver class is not visible to your bundle, so there really is no way to avoid a dependency.Here is an outline of a partial solution:
- Create an OSGi bundle for each JDBC driver you want to use. Add a bundle activator that calls
Class.forName("some.jdbc.Driver")
. This will register the driver with DriverManager when the bundle is started. - For each bundle that needs to create connections using
DriverManager.getConnection()
, add optional dependencies on the JDBC drivers packages for all drivers that you are planning to use.
If you do not need to support legacy code, do not bother using DriverManager and the Service Provider mechanism. After all, this is just a poor man's service registry, and you are much better off using the OSGi Service Registry.
I'll give an example in one of my next posts.
No comments:
Post a Comment