This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-dbcp.git
commit fdc855e5ded81631c89c9b9142e64bde8507216e Author: Gary Gregory <gardgreg...@gmail.com> AuthorDate: Tue Jul 30 14:24:45 2019 -0400 Split out factory code out of BasicDataSource in small factory classes. This helps reduce the size and complexity of BasicDataSource and fixes a Checkstyle violation for the class being too big. --- .../org/apache/commons/dbcp2/BasicDataSource.java | 146 +++++---------------- .../commons/dbcp2/BasicDataSourceFactory.java | 4 +- .../commons/dbcp2/ConnectionFactoryFactory.java | 79 +++++++++++ .../commons/dbcp2/DriverConnectionFactory.java | 110 ---------------- .../org/apache/commons/dbcp2/DriverFactory.java | 81 ++++++++++++ 5 files changed, 196 insertions(+), 224 deletions(-) diff --git a/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java b/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java index fd6b4fb..243a29f 100644 --- a/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java +++ b/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java @@ -469,67 +469,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean */ 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'"); - } - - return createConnectionFactory(driverToUse); + return ConnectionFactoryFactory.createConnectionFactory(this, DriverFactory.createDriver(this)); } /** @@ -831,6 +771,19 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean } /** + * Returns the ConnectionFactoryClassName that has been configured for use by this pool. + * <p> + * Note: This getter only returns the last value set by a call to {@link #setConnectionFactoryClassName(String)}. + * </p> + * + * @return the ConnectionFactoryClassName that has been configured for use by this pool. + * @since 2.7.0 + */ + public String getConnectionFactoryClassName() { + return this.connectionFactoryClassName; + } + + /** * Returns the list of SQL statements executed when a physical connection is first created. Returns an empty list if * there are no initialization statements configured. * @@ -991,19 +944,6 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean } /** - * Returns the ConnectionFactoryClassName that has been configured for use by this pool. - * <p> - * Note: This getter only returns the last value set by a call to {@link #setConnectionFactoryClassName(String)}. - * </p> - * - * @return the ConnectionFactoryClassName that has been configured for use by this pool. - * @since 2.7.0 - */ - public String getConnectionFactoryClassName() { - return this.connectionFactoryClassName; - } - - /** * Returns the value of the flag that controls whether or not connections being returned to the pool will be checked * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit * setting is {@code false} when the connection is returned. It is <code>true</code> by default. @@ -1599,12 +1539,14 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean /** * Logs the given throwable. - * + * @param message TODO * @param throwable the throwable. + * * @since 2.7.0 */ - protected void log(Throwable throwable) { + protected void log(String message, Throwable throwable) { if (logWriter != null) { + logWriter.println(message); throwable.printStackTrace(logWriter); } } @@ -1715,6 +1657,8 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean this.autoCommitOnReturn = autoCommitOnReturn; } + // ----------------------------------------------------- DataSource Methods + /** * Sets the state caching flag. * @@ -1724,7 +1668,19 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean this.cacheState = cacheState; } - // ----------------------------------------------------- DataSource Methods + /** + * Sets the ConnectionFactory class name. + * + * @param connectionFactoryClassName A class name. + * @since 2.7.0 + */ + public void setConnectionFactoryClassName(final String connectionFactoryClassName) { + if (isEmpty(connectionFactoryClassName)) { + this.connectionFactoryClassName = null; + } else { + this.connectionFactoryClassName = connectionFactoryClassName; + } + } /** * Sets the list of SQL statements to be executed when a physical connection is first created. @@ -1974,20 +1930,6 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean } /** - * Sets the ConnectionFactory class name. - * - * @param connectionFactoryClassName A class name. - * @since 2.7.0 - */ - public void setConnectionFactoryClassName(final String connectionFactoryClassName) { - if (isEmpty(connectionFactoryClassName)) { - this.connectionFactoryClassName = null; - } else { - this.connectionFactoryClassName = connectionFactoryClassName; - } - } - - /** * Sets the value of the flag that controls whether or not connections being returned to the pool will be checked * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit * setting is {@code false} when the connection is returned. It is <code>true</code> by default. @@ -2214,6 +2156,8 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean } } + // ------------------------------------------------------ Protected Methods + /** * Sets the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections are * available when the idle object evictor runs. The value of this property has no effect unless @@ -2229,8 +2173,6 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean } } - // ------------------------------------------------------ Protected Methods - /** * Sets the value of the {@link #numTestsPerEvictionRun} property. * @@ -2515,22 +2457,4 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean config.setJmxNamePrefix(Constants.JMX_CONNECTION_POOL_PREFIX); } - private ConnectionFactory createConnectionFactory(final Driver driver) throws SQLException { - if (connectionFactoryClassName != null) { - try { - Class<?> connectionFactoryFromCCL = Class.forName(connectionFactoryClassName); - return (ConnectionFactory) connectionFactoryFromCCL - .getConstructor(Driver.class, String.class, Properties.class) - .newInstance(driver, url, connectionProperties); - } catch (final Exception t) { - final String message = "Cannot load ConnectionFactory implementation '" + connectionFactoryClassName - + "'"; - logWriter.println(message); - t.printStackTrace(logWriter); - throw new SQLException(message, t); - } - } - return new DriverConnectionFactory(driver, url, connectionProperties); - } - } diff --git a/src/main/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java b/src/main/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java index e826cff..945d163 100644 --- a/src/main/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java +++ b/src/main/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java @@ -552,11 +552,9 @@ public class BasicDataSourceFactory implements ObjectFactory { value = properties.getProperty(PROP_CONNECTION_FACTORY_CLASS_NAME); if (value != null) { - dataSource.setConnectionFactoryClassName(value); + dataSource.setConnectionFactoryClassName(value); } - - // DBCP-215 // Trick to make sure that initialSize connections are created if (dataSource.getInitialSize() > 0) { diff --git a/src/main/java/org/apache/commons/dbcp2/ConnectionFactoryFactory.java b/src/main/java/org/apache/commons/dbcp2/ConnectionFactoryFactory.java new file mode 100644 index 0000000..5d635bb --- /dev/null +++ b/src/main/java/org/apache/commons/dbcp2/ConnectionFactoryFactory.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.dbcp2; + +import java.sql.Driver; +import java.sql.SQLException; +import java.util.Properties; + +/* + * Creates {@link ConnectionFactory} instances. + * + * @since 2.7.0 + */ +class ConnectionFactoryFactory { + + /** + * Creates a new {@link DriverConnectionFactory} allowing for an override through + * {@link BasicDataSource#getDriverClassName()}. + * + * @param basicDataSource Configures creation. + * @param driver The JDBC driver. + * @return a new {@link DriverConnectionFactory} allowing for a {@link BasicDataSource#getDriverClassName()} + * override. + * @throws SQLException Thrown when instantiation fails. + */ + static ConnectionFactory createConnectionFactory(final BasicDataSource basicDataSource, final Driver driver) + throws SQLException { + final Properties connectionProperties = basicDataSource.getConnectionProperties(); + final String url = basicDataSource.getUrl(); + // Set up the driver connection factory we will use + final String user = basicDataSource.getUsername(); + if (user != null) { + connectionProperties.put("user", user); + } else { + basicDataSource.log("DBCP DataSource configured without a 'username'"); + } + + final String pwd = basicDataSource.getPassword(); + if (pwd != null) { + connectionProperties.put("password", pwd); + } else { + basicDataSource.log("DBCP DataSource configured without a 'password'"); + } + if (basicDataSource != null) { + final String connectionFactoryClassName = basicDataSource.getConnectionFactoryClassName(); + if (connectionFactoryClassName != null) { + try { + final Class<?> connectionFactoryFromCCL = Class.forName(connectionFactoryClassName); + return (ConnectionFactory) connectionFactoryFromCCL + .getConstructor(Driver.class, String.class, Properties.class) + .newInstance(driver, url, connectionProperties); + } catch (final Exception t) { + final String message = "Cannot load ConnectionFactory implementation '" + connectionFactoryClassName + + "'"; + basicDataSource.log(message, t); + throw new SQLException(message, t); + } + } + } + // Defaults to DriverConnectionFactory + return new DriverConnectionFactory(driver, url, connectionProperties); + } + +} diff --git a/src/main/java/org/apache/commons/dbcp2/DriverConnectionFactory.java b/src/main/java/org/apache/commons/dbcp2/DriverConnectionFactory.java index 1e25e4d..0434584 100644 --- a/src/main/java/org/apache/commons/dbcp2/DriverConnectionFactory.java +++ b/src/main/java/org/apache/commons/dbcp2/DriverConnectionFactory.java @@ -18,7 +18,6 @@ package org.apache.commons.dbcp2; import java.sql.Connection; import java.sql.Driver; -import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; @@ -29,115 +28,6 @@ import java.util.Properties; */ public class DriverConnectionFactory implements ConnectionFactory { - /** - * 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 ConnectionFactory 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(); - - final Properties connectionProperties = basicDataSource.getConnectionProperties(); - - 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) { - connectionProperties.put("user", user); - } else { - basicDataSource.log("DBCP DataSource configured without a 'username'"); - } - - final String pwd = basicDataSource.getPassword(); - if (pwd != null) { - connectionProperties.put("password", pwd); - } else { - basicDataSource.log("DBCP DataSource configured without a 'password'"); - } - - return createConnectionFactory(basicDataSource, driverToUse); - } - private static ConnectionFactory createConnectionFactory(final BasicDataSource basicDataSource, final Driver driver) throws SQLException { - final String connectionFactoryClassName = basicDataSource.getConnectionFactoryClassName(); - final Properties connectionProperties = basicDataSource.getConnectionProperties(); - final String url = basicDataSource.getUrl(); - if (connectionFactoryClassName != null) { - try { - final Class<?> connectionFactoryFromCCL = Class.forName(connectionFactoryClassName); - return (ConnectionFactory) connectionFactoryFromCCL - .getConstructor(Driver.class, String.class, Properties.class) - .newInstance(driver, url, connectionProperties); - } catch (final Exception t) { - final String message = "Cannot load ConnectionFactory implementation '" + connectionFactoryClassName - + "'"; - basicDataSource.log(message); - basicDataSource.log(t); - throw new SQLException(message, t); - } - } - return new DriverConnectionFactory(driver, url, connectionProperties); - } private final String connectionString; private final Driver driver; diff --git a/src/main/java/org/apache/commons/dbcp2/DriverFactory.java b/src/main/java/org/apache/commons/dbcp2/DriverFactory.java new file mode 100644 index 0000000..2a05453 --- /dev/null +++ b/src/main/java/org/apache/commons/dbcp2/DriverFactory.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.dbcp2; + +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.SQLException; + +/* + * Creates {@link Driver} instances. + * + * @since 2.7.0 + */ +class DriverFactory { + + static Driver createDriver(final BasicDataSource basicDataSource) throws SQLException { + // Load the JDBC driver class + Driver driverToUse = basicDataSource.getDriver(); + String driverClassName = basicDataSource.getDriverClassName(); + ClassLoader driverClassLoader = basicDataSource.getDriverClassLoader(); + 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, 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, t); + throw new SQLException(message, t); + } + } + return driverToUse; + } + +}