JDBC / OSGi and how to dynamically load drivers without explicitly specifying dependencies in the bundle?

This is a biggie.

I have a well-structured, but monolithic code base that has a primitive modular architecture (all modules implement interfaces, but have the same class path). I understand the stupidity of this approach and the problems it presents when I go to deploy on application servers that may have different conflicting versions of my library.

Currently, I am addicted to about 30 cans, and I am in the middle of the way, although they are picked up. Now, some of my modules easily declare version-specific versions, such as my network components. They statically refer to classes in the JRE and other BNDded libraries, but my associated JDBC components are created through Class.forName (...) and can use any of several drivers.

I break everything down into OSGi packages by service area.

  • My main classes / interfaces.
  • Information about related components.
  • Database Access Components (via JDBC).
  • etc....

I want my code to be able to be used without OSGi through a single jar file with all my dependencies and without OSGi in general (via JARJAR), and also be modular using OSGi metadata and granular packets with information dependency.

  • How to configure my package and my code so that it can dynamically use any driver on the classpath and / or in the OSGi container environment (Felix / Equinox / etc.)?

  • Is there any execution method during discovery in an OSGi container that is compatible with containers (Felix / Equinox / etc.)?

  • Do I need to use a different class loading mechanism if I'm in an OSGi container?

  • Do I need to import OSGi classes into my project in order to be able to load an unknown JDBC driver while working through the database module?

  • I also have a second way to get the driver (via JNDI, which is really applicable when working on the application server), do I need to change the JNDI passcode for application servers that support OSGi?

+6
java jdbc modularity osgi
source share
3 answers
  • Using any driver in OSGi requires the use of the DynamicImport-Package: * operator so that your package can resolve these packages when loading the driver from Class.forName (..).
  • Probably the easiest way is to try to access the class that is in the org.osgi.framework package. At the very least, it should always be in an OSGi environment (see snippet below). There are more complex mechanisms, so let me know if you need something more advanced. Also, take a look at the OSGi R4.2 base specification, clause 3.8.9, which shows some methods for finding the Bundle and BundleContext classes, and therefore indirect help helps you determine whether you are within or not.
  • It depends on what you are doing, no general yes or no answer here. OSGi uses class loaders and does it in a way that is not "typical" for a standard Java application, but depending on what you are doing, you might not notice.
  • Not.
  • Take a look at the recently released OSGi specifications. They have a chapter on JNDI integration in OSGi, which probably allows you to leave your code (pretty much) unmodified.

A simple sample snippet:

public static boolean inOSGi() { try { Class.forName("org.osgi.framework.FrameworkUtil"); return true; } catch (ClassNotFoundException e) { return false; } } 

Just make sure that if you put this code in a package, the package should import org.osgi.framework (otherwise it will never find this class).

+7
source share

I created the JDBC driver manager for OSGI in RCP Eclipse and I will tell you how to play well with OSGI. First, forget about DynamicImport-Package, the only good way to use OSGI is to install / start / stop packages and use the OSGI engine in the way it was designed.

  • You have a JDBC package and create another driver package that has DriverClass initialization, connection logic and adds the necessary shared libraries like dbcp2 and pool2.

  • Export the driver package as JAR / ZIP and include it in your JDBC package as a resource.

  • Have your JDBC package unzip the driver package in the workspace.

     String workdir= Platform.getStateLocation(jdbc_bundle).toPortableString(); 
  • Programmatically add driver banks and modify the driver package MANIFEST.MF file accordingly.

  • Download the driver package programmatically from the workspace

     getBundleContext().installBundle("file:/"+workdir); 
  • Use bundle.start (), stop (), uninstall () if necessary when programmatically changing the list of drivers.

0
source share

pax-jdbc can be used to delegate data using a declarative method, which means that you can create a configuration entry in the ConfigAdmin service, and the data source can be accessed via JNDI. The JDBC driver is deployed as a package. (most of them have OSGi version)

For example:

PID configuration id - org.ops4j.datasource-test

Properties:

 osgi.jdbc.driver.name=H2 databaseName=test user=sa password= dataSourceName=testds-h2 

The service is identified by the dataSourceName. So you can filter it with (& (objectclass = javax.sql.DataSource) (dataSourceName = test2)).

And you can access the data source through JNDI:

 osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=test2) 
0
source share

All Articles