1

I am working on an EAR application(deployed on WLS 12c) that has a feature to configure and test jdbc connection for Oracle. So, in my jsp page the user selects the driver as oracle.jdbc.OracleDriver, enter the connectionurl, username and password and clicks on testConnection. And on doing this, the applicaiton gives back an error stating java.sql.SQLException: No suitable driver found for
jdbc:oracle:thin:@XXX-xx:1525/YYYY

A little brief of the architecture used in this application :

On application startup, we are referring to an xml that has all the JDBC defaults and try to load all the supported jdbc drivers that are present in that xml. And oracle.jdbc.OracleDriver is also one of them. This registering is done through a util class JDBCUtil.java which has 2 static methods : registerDriver(String driverName) and isDriverRegistered(String driverName).

So, the first time that JDBCUtil.registerDriver("oracle.jdbc.OracleDriver") is called, isDriverRegistered returns false and within registerDriver, we are making a call to class.forName(driverName) to load the driver.

The logic within isDriverRegistered gets an enumeration of all the drivers registered with DriverManager by calling DriverManager.getDrivers and checks if the driverName string passed to it equals driver.getClass.getName.

After the 1st call to JDBCUtil for OracleDriver, any subsequent calls to registerDriver for OracleDriver is expected to skip the class.forName because the isDriverRegistered is expected to return true. But upon adding logs statement and debugging, i noticed that everytime registerDriver->isDriverRegistered is called for OracleDriver, it is always returning false. The enumearation obtained by calling DriverManager getDrivers, never contains OracleDriver.

Secondly, In another class JDBCDS.java, we are calling JDBCUtil.registerDriver("oracle.jdbc.OracleDriver") and as expected, in registerDriver function exceute Class.forName("oracle.jdbc.OracleDriver") because isDriverRegistered returns false . In JDBCDS.java, after the call to registerDriver, we call DriverManager.getConnection by passing in the url,usename and password. And this call is throwing SQLException saying NoSuitableDriverFound.

So, as another debug test, i called Class.forName("oracle.jdbc.OracleDriver") in JDBCDS.java and then made a call to DriverManager.getConnection and this time i was able to get a connection successfully.

I have gone through all the question related to NoSuitableDriverFound exception on this forum, but nothing is fitting my issue.

I have tried to call create a new instanc of the driver by calling new oracle.jdbc.OracleDriver() within JDBCDS.java and see if it accepts my url and it does. Moreover, this has also ruled out any classpath problem. The jar is certainly in the classpath. Our classpath includes the following:
com.oracle.db.jdbc7-dms.jar and also weblogic.jar

com.oracle.db.jdbc7-dms.jar internally has a link to ojdbc8dms.jar and weblogic.jar internally has ojdbc8.jar included through the Class-Path attribute of its MANIFEST.MF files in both the cases.

Also, this issue is isolated to only a particular environment. In other environments with the same setup, everything works fine without issues.

From JDBCUtil.java :

static Util Method that is used to register the driver :

public static void registerDriver(String driverName)
{
    // Calls isDriverRegistered,isDriverRegistered returns false, then call Class.forName(driverName)
}

static method to see if driver is alreay registered :

public static boolean isDriverRegistered(String driverName)
{
    //call DriverManager.getDrivers to get all the registered drivers
    if(driver.getClass().getName().equals(driverName))
    {
        return true;  
    }
    return false;
}

Code in JDBCDS.java that is used to perform the test connection:

try {
    JDBCUtil.registerDriver(driver);
    DriverManager.setLoginTimeout(300);
    conn = DriverManager.getConnection(url, username, password); //This code throws No Suitable Driver Found Exception
} catch (SQLException e) { 
    // tried the below as a test

    try
    {
        Class.forName(driver);
    }
    catch(Exception ex)
    {
        Logger.log("Could not load the driver with the current classloader", 4);
        throw e;
    }
    conn = DriverManager.getConnection(url, username, password);//At this step the connection is successfully obtained
}

Both JDBCUtil.java and JDBCDS.java are in the same package.

Can anybody point me towards what i can do further to resolve this issue?

Usagi Miyamoto
  • 6,196
  • 1
  • 19
  • 33
  • You don't need all this, starting from all the `Class.forName()` calls. Just use your `jdbc:oracle...` URL and let the `DriverManager` do the worrying. – user207421 Jul 29 '19 at 07:16
  • Yes, its not needed, but for backward compatibility and for environments where the driver is not JDBC4 compliant, we have retained the code. Moreover, the DriverManager documentation does say that including Class.forName should not cause any problem. Moreover, in my case, the driver doesn't seem to be being picked up by the Service Loader. – Ramya Gummalapuram Jul 29 '19 at 07:22
  • You really have environments with pre-JDBC 4 drivers? Why? Why aren't you distributing the required JDBC drivers with your applications? JDBC 4.0 came out in 2007. – user207421 Jul 29 '19 at 08:24
  • No, we are using the ones that come with weblogic..and at present weblogic has ojdbc8.jar as a part of its installation. I just meant in case some particular customer does want to use it for some reason. Moreover, like i already mentioned, it should ideally not be causing any issue. – Ramya Gummalapuram Jul 29 '19 at 08:31
  • @user207421 The OP seems to put his JDBC driver in his EAR, in that case loading the driver with `Class.forName` is still necessary (although it would be better to use a data source manager by the application server instead). Automatic driver loading only works for JDBC drivers on the initial classpath, not for drivers in a context class path. – Mark Rotteveel Jul 29 '19 at 14:09
  • The problem is likely with how `DriverManager` filters the drivers it can use based on the caller or context class loader. It would suggest a different class loader hierarchy is used for calling the code than what is used for registering the drivers. – Mark Rotteveel Jul 29 '19 at 14:34
  • But the two classed mentioned are in the same package. So i was assuming that both of them would be loaded by the same weblogic application classloader. – Ramya Gummalapuram Jul 29 '19 at 16:43

0 Answers0