Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=49667
authormarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Fri, 1 Oct 2010 11:10:51 +0000 (11:10 +0000)
committermarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Fri, 1 Oct 2010 11:10:51 +0000 (11:10 +0000)
Ensure JDBC leak prevention code doesn't trigger the very memory leak it is meant to be fixing.

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1003481 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/catalina/loader/JdbcLeakPrevention.java
webapps/docs/changelog.xml

index 6f10dc8..48b2668 100644 (file)
@@ -23,6 +23,7 @@ import java.sql.DriverManager;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.HashSet;
 import java.util.List;
 
 /**
@@ -41,16 +42,33 @@ public class JdbcLeakPrevention {
     public List<String> clearJdbcDriverRegistrations() throws SQLException {
         List<String> driverNames = new ArrayList<String>();
 
-        // This will list all drivers visible to this class loader
+        /*
+         * DriverManager.getDrivers() has a nasty side-effect of registering
+         * drivers that are visible to this class loader but haven't yet been
+         * loaded. Therefore, the first call to this method a) gets the list
+         * of originally loaded drivers and b) triggers the unwanted
+         * side-effect. The second call gets the complete list of drivers
+         * ensuring that both original drivers and any loaded as a result of the
+         * side-effects are all de-registered.
+         */
+        HashSet<Driver> originalDrivers = new HashSet<Driver>();
         Enumeration<Driver> drivers = DriverManager.getDrivers();
         while (drivers.hasMoreElements()) {
+            originalDrivers.add(drivers.nextElement());
+        }
+        drivers = DriverManager.getDrivers();
+        while (drivers.hasMoreElements()) {
             Driver driver = drivers.nextElement();
             // Only unload the drivers this web app loaded
             if (driver.getClass().getClassLoader() !=
                 this.getClass().getClassLoader()) {
                 continue;
             }
-            driverNames.add(driver.getClass().getCanonicalName());
+            // Only report drivers that were originally registered. Skip any
+            // that were registered as a side-effect of this code.
+            if (originalDrivers.contains(driver)) {
+                driverNames.add(driver.getClass().getCanonicalName());
+            }
             DriverManager.deregisterDriver(driver);
         }
         return driverNames;
index fb838e5..4fbcd4f 100644 (file)
         (markt)
       </fix>
       <fix>
+        <bug>49667</bug>: Ensure that using the JDBC driver memory leak
+        prevention code does not cause a one of the memory leaks it is meant to
+        avoid. (markt)
+      </fix>
+      <fix>
         <bug>49670</bug>: Restore SSO functionality that was broken by Lifecycle
         refactoring. (markt)
       </fix>