diff --git a/springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/jdbc/AuthorizationJdbcDriver.java b/springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/jdbc/AuthorizationJdbcDriver.java index 93045795..d7c5acb0 100644 --- a/springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/jdbc/AuthorizationJdbcDriver.java +++ b/springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/jdbc/AuthorizationJdbcDriver.java @@ -6,52 +6,131 @@ import java.sql.*; import java.util.Enumeration; import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; public class AuthorizationJdbcDriver implements Driver { - private Driver driver; + /** + * Cache driver by URL to avoid repeated traversal. + * Thread-safe since multiple connections may be created concurrently. + */ + private final ConcurrentHashMap driverCache = new ConcurrentHashMap<>(); + + /** + * Cached reference to any non-self driver (for methods without URL). + */ + private volatile Driver anyDriverCache; @Override public Connection connect(String url, Properties info) throws SQLException { - return new ConnectionProxy(driver.connect(url, info)); + Driver targetDriver = getTargetDriver(url); + if (targetDriver == null) { + return null; + } + return new ConnectionProxy(targetDriver.connect(url, info)); } @Override public boolean acceptsURL(String url) throws SQLException { + return getTargetDriver(url) != null; + } + + /** + * Get target driver for the given URL. + * Uses cached result if available, otherwise finds and caches. + */ + private Driver getTargetDriver(String url) throws SQLException { + // Fast path: check cache first + Driver cached = driverCache.get(url); + if (cached != null) { + return cached; + } + + // Cache miss: find and cache + Driver found = findDriver(url); + if (found != null) { + driverCache.putIfAbsent(url, found); + } + return found; + } + + /** + * Find the target driver that accepts the URL from DriverManager. + */ + private Driver findDriver(String url) throws SQLException { Enumeration drivers = DriverManager.getDrivers(); while (drivers.hasMoreElements()) { Driver driver = drivers.nextElement(); - if (driver.acceptsURL(url)) { - this.driver = driver; - return true; + if (driver != this && driver.acceptsURL(url)) { + return driver; } } - return false; + return null; } @Override public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { - return driver.getPropertyInfo(url, info); + Driver driver = getTargetDriver(url); + if (driver != null) { + return driver.getPropertyInfo(url, info); + } + return new DriverPropertyInfo[0]; } @Override public int getMajorVersion() { - return driver.getMajorVersion(); + return getAnyDriver().getMajorVersion(); } @Override public int getMinorVersion() { - return driver.getMinorVersion(); + return getAnyDriver().getMinorVersion(); } @Override public boolean jdbcCompliant() { - return driver.jdbcCompliant(); + Driver driver = getAnyDriver(); + return driver != null && driver.jdbcCompliant(); } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { - return driver.getParentLogger(); + return getAnyDriver().getParentLogger(); + } + + /** + * Get any registered driver other than this one. + * Caches the first found result since driver set doesn't change at runtime. + */ + private Driver getAnyDriver() { + // Double-checked locking for lazy initialization + Driver cached = anyDriverCache; + if (cached != null) { + return cached; + } + synchronized (this) { + cached = anyDriverCache; + if (cached != null) { + return cached; + } + anyDriverCache = findAnyDriver(); + return anyDriverCache; + } + } + + /** + * Find any registered driver other than this one. + * Used for methods that don't have URL available. + */ + private Driver findAnyDriver() { + Enumeration drivers = DriverManager.getDrivers(); + while (drivers.hasMoreElements()) { + Driver driver = drivers.nextElement(); + if (driver != this) { + return driver; + } + } + throw new IllegalStateException("No JDBC driver found"); } }