[Checkstyle] Move DriverConnectionFactory creation from BasicDataSource
to a factory method _in_ DriverConnectionFactory. This moves the factory
code closer to home and fixes a checkstyle violation that had
BasicDataSource over 2,500 lines of source code.
diff --git a/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java b/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java
index c6a4c34..6dd7320 100644
--- a/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java
+++ b/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java
@@ -467,69 +467,7 @@
* If the connection factort cannot be created
*/
protected ConnectionFactory createConnectionFactory() throws SQLException {
- // Load the JDBC driver class
- Driver driverToUse = this.driver;
-
- if (driverToUse == null) {
- Class<?> driverFromCCL = null;
- if (driverClassName != null) {
- try {
- try {
- if (driverClassLoader == null) {
- driverFromCCL = Class.forName(driverClassName);
- } else {
- driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);
- }
- } catch (final ClassNotFoundException cnfe) {
- driverFromCCL = Thread.currentThread().getContextClassLoader().loadClass(driverClassName);
- }
- } catch (final Exception t) {
- final String message = "Cannot load JDBC driver class '" + driverClassName + "'";
- logWriter.println(message);
- t.printStackTrace(logWriter);
- throw new SQLException(message, t);
- }
- }
-
- try {
- if (driverFromCCL == null) {
- driverToUse = DriverManager.getDriver(url);
- } else {
- // Usage of DriverManager is not possible, as it does not
- // respect the ContextClassLoader
- // N.B. This cast may cause ClassCastException which is handled below
- driverToUse = (Driver) driverFromCCL.getConstructor().newInstance();
- if (!driverToUse.acceptsURL(url)) {
- throw new SQLException("No suitable driver", "08001");
- }
- }
- } catch (final Exception t) {
- final String message = "Cannot create JDBC driver of class '"
- + (driverClassName != null ? driverClassName : "") + "' for connect URL '" + url + "'";
- logWriter.println(message);
- t.printStackTrace(logWriter);
- throw new SQLException(message, t);
- }
- }
-
- // Set up the driver connection factory we will use
- final String user = userName;
- if (user != null) {
- connectionProperties.put("user", user);
- } else {
- log("DBCP DataSource configured without a 'username'");
- }
-
- final String pwd = password;
- if (pwd != null) {
- connectionProperties.put("password", pwd);
- } else {
- log("DBCP DataSource configured without a 'password'");
- }
-
- final ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driverToUse, url,
- connectionProperties);
- return driverConnectionFactory;
+ return DriverConnectionFactory.createConnectionFactory(this);
}
/**
@@ -868,7 +806,6 @@
return connectionPool;
}
- // For unit testing
Properties getConnectionProperties() {
return connectionProperties;
}
@@ -1583,12 +1520,18 @@
}
}
- protected void log(final String message) {
+ void log(final String message) {
if (logWriter != null) {
logWriter.println(message);
}
}
+ void log(Throwable throwable) {
+ if (logWriter != null) {
+ throwable.printStackTrace(logWriter);
+ }
+ }
+
@Override
public void postDeregister() {
// NO-OP
@@ -1709,6 +1652,8 @@
this.cacheState = cacheState;
}
+ // ----------------------------------------------------- DataSource Methods
+
/**
* Sets the list of SQL statements to be executed when a physical connection is first created.
* <p>
@@ -1737,8 +1682,6 @@
}
}
- // ----------------------------------------------------- DataSource Methods
-
/**
* Sets the connection properties passed to driver.connect(...).
* <p>
@@ -2228,6 +2171,8 @@
}
}
+ // ------------------------------------------------------ Protected Methods
+
/**
* Sets the value of the {@link #numTestsPerEvictionRun} property.
*
@@ -2242,8 +2187,6 @@
}
}
- // ------------------------------------------------------ Protected Methods
-
/**
* <p>
* Sets the {@link #password}.
diff --git a/src/main/java/org/apache/commons/dbcp2/DriverConnectionFactory.java b/src/main/java/org/apache/commons/dbcp2/DriverConnectionFactory.java
index 1b4f5dd..a99ff9f 100644
--- a/src/main/java/org/apache/commons/dbcp2/DriverConnectionFactory.java
+++ b/src/main/java/org/apache/commons/dbcp2/DriverConnectionFactory.java
@@ -18,6 +18,7 @@
import java.sql.Connection;
import java.sql.Driver;
+import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
@@ -33,6 +34,93 @@
private final Properties properties;
/**
+ * Creates a JDBC connection factory for the given data source. The JDBC driver is loaded using the following
+ * algorithm:
+ * <ol>
+ * <li>If a Driver instance has been specified via {@link #setDriver(Driver)} use it</li>
+ * <li>If no Driver instance was specified and {@link #driverClassName} is specified that class is loaded using the
+ * {@link ClassLoader} of this class or, if {@link #driverClassLoader} is set, {@link #driverClassName} is loaded
+ * with the specified {@link ClassLoader}.</li>
+ * <li>If {@link #driverClassName} is specified and the previous attempt fails, the class is loaded using the
+ * context class loader of the current thread.</li>
+ * <li>If a driver still isn't loaded one is loaded via the {@link DriverManager} using the specified {@link #url}.
+ * </ol>
+ * <p>
+ * This method exists so subclasses can replace the implementation class.
+ * </p>
+ *
+ * @return A new connection factory.
+ *
+ * @throws SQLException If the connection factory cannot be created
+ */
+ static DriverConnectionFactory createConnectionFactory(final BasicDataSource basicDataSource) throws SQLException {
+ // Load the JDBC driver class
+ Driver driverToUse = basicDataSource.getDriver();
+ final String driverClassName = basicDataSource.getDriverClassName();
+ final ClassLoader driverClassLoader = basicDataSource.getDriverClassLoader();
+ final String url = basicDataSource.getUrl();
+
+ if (driverToUse == null) {
+ Class<?> driverFromCCL = null;
+ if (driverClassName != null) {
+ try {
+ try {
+ if (driverClassLoader == null) {
+ driverFromCCL = Class.forName(driverClassName);
+ } else {
+ driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);
+ }
+ } catch (final ClassNotFoundException cnfe) {
+ driverFromCCL = Thread.currentThread().getContextClassLoader().loadClass(driverClassName);
+ }
+ } catch (final Exception t) {
+ final String message = "Cannot load JDBC driver class '" + driverClassName + "'";
+ basicDataSource.log(message);
+ basicDataSource.log(t);
+ throw new SQLException(message, t);
+ }
+ }
+
+ try {
+ if (driverFromCCL == null) {
+ driverToUse = DriverManager.getDriver(url);
+ } else {
+ // Usage of DriverManager is not possible, as it does not
+ // respect the ContextClassLoader
+ // N.B. This cast may cause ClassCastException which is handled below
+ driverToUse = (Driver) driverFromCCL.getConstructor().newInstance();
+ if (!driverToUse.acceptsURL(url)) {
+ throw new SQLException("No suitable driver", "08001");
+ }
+ }
+ } catch (final Exception t) {
+ final String message = "Cannot create JDBC driver of class '"
+ + (driverClassName != null ? driverClassName : "") + "' for connect URL '" + url + "'";
+ basicDataSource.log(message);
+ basicDataSource.log(t);
+ throw new SQLException(message, t);
+ }
+ }
+
+ // Set up the driver connection factory we will use
+ final String user = basicDataSource.getUsername();
+ if (user != null) {
+ basicDataSource.addConnectionProperty("user", user);
+ } else {
+ basicDataSource.log("DBCP DataSource configured without a 'username'");
+ }
+
+ final String pwd = basicDataSource.getPassword();
+ if (pwd != null) {
+ basicDataSource.addConnectionProperty("password", pwd);
+ } else {
+ basicDataSource.log("DBCP DataSource configured without a 'password'");
+ }
+
+ return new DriverConnectionFactory(driverToUse, url, basicDataSource.getConnectionProperties());
+ }
+
+ /**
* Constructs a connection factory for a given Driver.
*
* @param driver