views:

239

answers:

1

I inherited some code that is using the Apache commons-dbcp Connection pools in an OSGi bundle. This code works fine with Eclipse/Equinox OSGi version 3.4.3 (R34x_v20081215), commons-dbcp 1.2.2 and the postgres jdbc3 8.3.603 bundles from springsource.org.

I wanted to modernize, maybe this was my first mistake!

When I use the new version of Felix or Equinox OSGI Cores with the new postgresql JDBC3 or JDBC4 bundles along with the latest version of commons-dbcp (1.4.1), I am getting a classloading issue. I have done numerous searches and found that the commons-dbcp code should have a fix DBCP-214, but it still seems to fail.

I have tried to put the org.postgresql on the commons-dbcp MANIFEST.MF import-package line, but that did not work either.

I wrote a simple test in an activator that first does a basic class.forName() and DriverManager.getConnection(), this works fine, but when I add in BasicDataSource() and setup the connection with BasicDataSource.getConnection(), I get the ClassNotFoundException. See the code example below.

Thanks in Advance for any help, suggestions, ...

Sau!

// This one fails with an exception
public void dsTest() {
    BasicDataSource bds = new BasicDataSource();
    ClassLoader cl;

    try {
        logger.debug("ContextClassLoader: {}", 
        Thread.currentThread().getContextClassLoader().toString());
        cl = this.getClass().getClassLoader();
        logger.debug("ClassLoader: {}", cl); 

        if (bds.getDriverClassLoader() != null) {
            logger.debug(bds.getDriverClassLoader().toString());
        }
        // The failure is the same with and with the setDriverClassLoader() line
        bds.setDriverClassLoader(cl);
        bds.setDriverClassName("org.postgresql.Driver");
        bds.setUrl("jdbc:postgresql://127.0.0.1/dbname");
        bds.setUsername("user");
        bds.setPassword("pword");
        Class.forName("org.postgresql.Driver").newInstance();
        conn = bds.getConnection();
        Statement st = conn.createStatement();
        ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM table");
        conn.close();
        logger.debug("Closed DataSource Test");
    } catch (Exception ex) {
        ex.printStackTrace();
        logger.debug("Exception: {} ", ex.getMessage());
    }
}

// This one works
public void managerTest() {
    ClassLoader cl;
    try {
        cl = this.getClass().getClassLoader();
        logger.debug("ClassLoader: {}", cl);
        Class.forName("org.postgresql.Driver").newInstance();
        String url = "jdbc:postgresql://127.0.0.1/dbname";
        conn = DriverManager.getConnection(url, "user", "pword");

        Statement st = conn.createStatement();
        ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM table");
        conn.close();
        logger.debug("Closed Manger Test");
    } catch (Exception ex) {
        ex.printStackTrace();
        logger.debug("Exception: {} ", ex.getMessage());
    }
}
A: 

Hi,

this is due to the fact that the commons-dbcp bundle cannot look at the actual driver class, because of the osgi class loader. The solution to this is to attach a fragment to the commons-dbcp class with Dynamic Import *. The actual headers that you need in your MANIFEST are the following:

Fragment-Host: org.apache.commons.dbcp DynamicImport-Package: *

After this, the code you mentioned worked. Hope this doesnt come too late.

maquina