aaron.chu
aaron.chu

Reputation: 195

why DriverManager.getConnection does not use "acceptsURL" method from Driver.class

I'm reading JDBC code. In DriverManager.getConnection, I find it works like this: it tries to connect every Driver it knows until it success.

Here is the code:

        for(DriverInfo aDriver : registeredDrivers) {
            // If the caller does not have permission to load the driver then
            // skip it.
            if(isDriverAllowed(aDriver.driver, callerCL)) {
                try {
                    println("    trying " + aDriver.driver.getClass().getName());
                    Connection con = aDriver.driver.connect(url, info);
                    if (con != null) {
                        // Success!
                        println("getConnection returning " + aDriver.driver.getClass().getName());
                        return (con);
                    }
                } catch (SQLException ex) {
                    if (reason == null) {
                        reason = ex;
                    }
                }

            } else {
                println("    skipping: " + aDriver.getClass().getName());
            }

        }

But there is a method "acceptsURL" from interface Driver:

    boolean acceptsURL(String url) throws SQLException;

So my question is, why DriverManager does not call this method before it do the real connection to filter unrelated drivers?

Or with code, may be this is better?

        for(DriverInfo aDriver : registeredDrivers) {
            // If the caller does not have permission to load the driver then
            // skip it.
            if(isDriverAllowed(aDriver.driver, callerCL) && aDriver.driver.acceptsURL(url)) {
                try {
                    println("    trying " + aDriver.driver.getClass().getName());
                    Connection con = aDriver.driver.connect(url, info);
                    if (con != null) {
                        // Success!
                        println("getConnection returning " + aDriver.driver.getClass().getName());
                        return (con);
                    }
                } catch (SQLException ex) {
                    if (reason == null) {
                        reason = ex;
                    }
                }

            } else {
                println("    skipping: " + aDriver.getClass().getName());
            }

        }

Upvotes: 1

Views: 579

Answers (1)

Mark Rotteveel
Mark Rotteveel

Reputation: 109257

The DriverManager reference implementation (OpenJDK) doesn't use acceptsUrl. That doesn't necessarily mean there are no DriverManager implementations using it. In fact, as far as I recall, earlier Sun Java implementations did call acceptsURL. The main reason it isn't called, is that the JDBC specification requires DriverManager to call connect on each registered driver anyway. See below.

Nothing in the specification or API documentation says that DriverManager must use acceptsURL. The JDBC 4.3 specification on this only says (section 9.2 The Driver interface):

The DriverManager class invokes Driver methods when it wishes to interact with a registered driver. The Driver interface also includes the method acceptsURL. The DriverManager can use this method to determine which of its registered drivers it should use for a given URL.

(emphasis mine)

Note the use of the word can instead of must or will.

The subsequent paragraph says:

When the DriverManager is trying to establish a connection, it calls that driver’s connect method and passes the driver the URL. If the Driver implementation understands the URL, it will return a Connection object or throw a SQLException if a connection cannot be maded [sic] to the database. If the Driver implementation does not understand the URL, it will return null.

In addition, section 9.4 The DriverManager class says:

  • getConnection — the method the JDBC client invokes to establish a connection. The invocation includes a JDBC URL, which the DriverManager passes to each driver in its list until it finds one whose Driver.connect method recognizes the URL. That driver returns a Connection object to the DriverManager, which in turn passes it to the application.

(emphasis mine)

How I read this, calling Driver.connect on each driver is required anyway, so there is no point for the implementation to call acceptsURL.

Now, as to why the JDBC specification is written this way, I don't know, and I'm a member of the JSR-221 (JDBC 4) Expert Group myself. When I joined the Expert Group the implementation (and specification) was already this way, so I'm not aware of its history. However, I'm not sure you'll get a better answer here than above unsatisfactory answer (it is so because the specification says so).

However, if I had to guess, it is probably to do with the fact that for some drivers determining if they can accept an URL could be relatively complex or expensive. In that case it is better to just try and connect, because for a driver rejecting the URL the cost is (or should be) the same as just calling acceptsURL, while for a driver that will actually accept the URL, the cost would be hit twice if DriverManager would first call acceptsURL followed by a connect.

This doesn't mean that the acceptsURL method is entirely without value. Some applications (eg some query tools or reporting tools) use it to discover which driver(s) would handle a specific URL, so they can interrogate the Driver implementation(s) for their supported connection properties (Driver.getPropertyInfo​) so they can populate there connection wizard with the available properties. Other programs could use it to get information like its version (Driver.getMajorVersion, Driver.getMinorVersion), parent logger (Driver.getParentLogger) or JDBC compliancy (Driver.jdbcCompliant).

Upvotes: 4

Related Questions