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
The following commit(s) were added to refs/heads/master by this push:
new 8a579d3 [DBCP-547] Add a ConnectionFactory class name setting for
BasicDataSource.createConnectionFactory() #33.
8a579d3 is described below
commit 8a579d304595853012ccf8c2bc93022c383a35bb
Author: Gary Gregory <[email protected]>
AuthorDate: Mon Jul 8 11:13:58 2019 -0400
[DBCP-547] Add a ConnectionFactory class name setting for
BasicDataSource.createConnectionFactory() #33.
- Update version from 2.6.1-SNAPSHOT to 2.7.0 since this commits adds
new public APIs in BasicDataSource.
- Provide an alternative implementation from the PR
https://github.com/apache/commons-dbcp/pull/33 WRT to String value
handling. The handling of empty string for the new APIs is made
consistent with other String APIs instead of what is done in PR 33.
- Formatted new class TesterConnectionFactory differently from the PR
and sorted its methods.
- Closes #33.
---
pom.xml | 4 +-
src/changes/changes.xml | 7 +-
.../org/apache/commons/dbcp2/BasicDataSource.java | 110 ++++++++++++++++-----
.../commons/dbcp2/BasicDataSourceFactory.java | 11 ++-
.../apache/commons/dbcp2/TestBasicDataSource.java | 45 ++++++++-
.../commons/dbcp2/TesterConnectionFactory.java | 84 ++++++++++++++++
6 files changed, 229 insertions(+), 32 deletions(-)
diff --git a/pom.xml b/pom.xml
index 399774a..3d9b8f8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,7 +26,7 @@
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>commons-dbcp2</artifactId>
- <version>2.6.1-SNAPSHOT</version>
+ <version>2.7.0-SNAPSHOT</version>
<name>Apache Commons DBCP</name>
<inceptionYear>2001</inceptionYear>
@@ -293,7 +293,7 @@
<commons.rc.version>RC1</commons.rc.version>
<commons.module.name>org.apache.commons.dbcp2</commons.module.name>
- <commons.release.version>2.6.1</commons.release.version>
+ <commons.release.version>2.7.0</commons.release.version>
<commons.release.desc>for JDBC 4.2 on Java 8</commons.release.desc>
<commons.release.2.version>2.4.0</commons.release.2.version>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 6815b40..53e40a6 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -60,7 +60,7 @@ The <action> type attribute can be add,update,fix,remove.
-->
<body>
- <release version="2.6.1" date="2019-MM-DD" description="This is a minor
release, including bug fixes and enhancements.">
+ <release version="2.7.0" date="2019-MM-DD" description="This is a minor
release, including bug fixes and enhancements.">
<action dev="jleroux" type="add" issue="DBCP-539" due-to="Jacques Le
Roux">
ManagedDataSource#close() should declare used exceptions.
</action>
@@ -71,7 +71,7 @@ The <action> type attribute can be add,update,fix,remove.
Update tests from H2 1.4.198 to 1.4.199.
</action>
<action dev="ggregory" type="update" issue="DBCP-540" due-to="emopers">
- Close ObjectOutputStream before calling toByteArray on underlying
ByteArrayOutputStream #28.
+ Close ObjectOutputStream before calling toByteArray() on underlying
ByteArrayOutputStream #28.
</action>
<action dev="ggregory" type="update" issue="DBCP-541" due-to="Allon
Murienik">
Upgrade to JUnit Jupiter #19.
@@ -85,6 +85,9 @@ The <action> type attribute can be add,update,fix,remove.
<action dev="ggregory" type="update" issue="DBCP-546" due-to="Sergey
Chupov">
Avoid NPE when calling DriverAdapterCPDS.toString().
</action>
+ <action dev="ggregory" type="update" issue="DBCP-547"
due-to="leechoongyon, Gary Gregory">
+ Add a ConnectionFactory class name setting for
BasicDataSource.createConnectionFactory() #33.
+ </action>
</release>
<release version="2.6.0" date="2019-02-14" description="This is a minor
release, including bug fixes and enhancements.">
<action dev="chtompki" type="add" issue="DBCP-534" due-to="Peter Wicks">
diff --git a/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java
b/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java
index 7c46359..3a3d065 100644
--- a/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java
+++ b/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java
@@ -109,7 +109,7 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
}
protected static void validateConnectionFactory(final
PoolableConnectionFactory connectionFactory)
- throws Exception {
+ throws Exception {
PoolableConnection conn = null;
PooledObject<PoolableConnection> p = null;
try {
@@ -315,6 +315,11 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
private volatile int validationQueryTimeoutSeconds = -1;
/**
+ * The fully qualified Java class name of a {@link ConnectionFactory}
implementation.
+ */
+ private String connectionFactoryClassName;
+
+ /**
* These SQL statements run once after a Connection is created.
* <p>
* This property can be used for example to run ALTER SESSION SET
NLS_SORT=XCYECH in an Oracle Database only once
@@ -364,7 +369,7 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
* The PrintWriter to which log messages should be directed.
*/
private volatile PrintWriter logWriter = new PrintWriter(
- new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
+ new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
private AbandonedConfig abandonedConfig;
@@ -504,7 +509,7 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
}
} catch (final Exception t) {
final String message = "Cannot create JDBC driver of class '"
- + (driverClassName != null ? driverClassName : "") +
"' for connect URL '" + url + "'";
+ + (driverClassName != null ? driverClassName : "") + "'
for connect URL '" + url + "'";
logWriter.println(message);
t.printStackTrace(logWriter);
throw new SQLException(message, t);
@@ -526,9 +531,7 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
log("DBCP DataSource configured without a 'password'");
}
- final ConnectionFactory driverConnectionFactory = new
DriverConnectionFactory(driverToUse, url,
- connectionProperties);
- return driverConnectionFactory;
+ return createConnectionFactory(driverToUse);
}
/**
@@ -683,10 +686,10 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
* @return a non-null instance
*/
protected GenericObjectPool<PoolableConnection> createObjectPool(final
PoolableConnectionFactory factory,
- final GenericObjectPoolConfig<PoolableConnection> poolConfig,
final AbandonedConfig abandonedConfig) {
+ final GenericObjectPoolConfig<PoolableConnection> poolConfig, final
AbandonedConfig abandonedConfig) {
GenericObjectPool<PoolableConnection> gop;
- if (abandonedConfig != null &&
(abandonedConfig.getRemoveAbandonedOnBorrow()
- || abandonedConfig.getRemoveAbandonedOnMaintenance())) {
+ if (abandonedConfig != null
+ && (abandonedConfig.getRemoveAbandonedOnBorrow() ||
abandonedConfig.getRemoveAbandonedOnMaintenance())) {
gop = new GenericObjectPool<>(factory, poolConfig,
abandonedConfig);
} else {
gop = new GenericObjectPool<>(factory, poolConfig);
@@ -706,11 +709,11 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
* @return A new PoolableConnectionFactory configured with the current
configuration of this BasicDataSource
*/
protected PoolableConnectionFactory createPoolableConnectionFactory(final
ConnectionFactory driverConnectionFactory)
- throws SQLException {
+ throws SQLException {
PoolableConnectionFactory connectionFactory = null;
try {
connectionFactory = new
PoolableConnectionFactory(driverConnectionFactory,
- ObjectNameWrapper.unwrap(registeredJmxObjectName));
+ ObjectNameWrapper.unwrap(registeredJmxObjectName));
connectionFactory.setValidationQuery(validationQuery);
connectionFactory.setValidationQueryTimeout(validationQueryTimeoutSeconds);
connectionFactory.setConnectionInitSql(connectionInitSqls);
@@ -991,6 +994,20 @@ 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.
@@ -1505,7 +1522,7 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
poolableConnection = connection.unwrap(PoolableConnection.class);
if (poolableConnection == null) {
throw new IllegalStateException(
- "Cannot invalidate connection: Connection is not a
poolable connection.");
+ "Cannot invalidate connection: Connection is not a
poolable connection.");
}
} catch (final SQLException e) {
throw new IllegalStateException("Cannot invalidate connection:
Unwrapping poolable connection failed.", e);
@@ -1551,6 +1568,16 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
}
/**
+ * Delegates in a null-safe manner to {@link String#isEmpty()}.
+ *
+ * @param value the string to test, may be null.
+ * @return boolean false if value is null, otherwise {@link
String#isEmpty()}.
+ */
+ private boolean isEmpty(String value) {
+ return value == null ? true : value.trim().isEmpty();
+ }
+
+ /**
* Returns true if we are pooling statements.
*
* @return true if prepared and callable statements are pooled
@@ -1723,7 +1750,7 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
if (connectionInitSqls != null && connectionInitSqls.size() > 0) {
ArrayList<String> newVal = null;
for (final String s : connectionInitSqls) {
- if (s != null && s.trim().length() > 0) {
+ if (!isEmpty(s)) {
if (newVal == null) {
newVal = new ArrayList<>();
}
@@ -1801,10 +1828,10 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
* the default catalog
*/
public void setDefaultCatalog(final String defaultCatalog) {
- if (defaultCatalog != null && defaultCatalog.trim().length() > 0) {
- this.defaultCatalog = defaultCatalog;
- } else {
+ if (isEmpty(defaultCatalog)) {
this.defaultCatalog = null;
+ } else {
+ this.defaultCatalog = defaultCatalog;
}
}
@@ -1851,10 +1878,10 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
* @since 2.5.0
*/
public void setDefaultSchema(final String defaultSchema) {
- if (defaultSchema != null && defaultSchema.trim().length() > 0) {
- this.defaultSchema = defaultSchema;
- } else {
+ if (isEmpty(defaultSchema)) {
this.defaultSchema = null;
+ } else {
+ this.defaultSchema = defaultSchema;
}
}
@@ -1902,7 +1929,7 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
if (disconnectionSqlCodes != null && disconnectionSqlCodes.size() > 0)
{
HashSet<String> newVal = null;
for (final String s : disconnectionSqlCodes) {
- if (s != null && s.trim().length() > 0) {
+ if (!isEmpty(s)) {
if (newVal == null) {
newVal = new HashSet<>();
}
@@ -1961,10 +1988,25 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
* the class name of the JDBC driver
*/
public synchronized void setDriverClassName(final String driverClassName) {
- if (driverClassName != null && driverClassName.trim().length() > 0) {
+ if (isEmpty(driverClassName)) {
+ this.driverClassName = null;
+ } else {
this.driverClassName = driverClassName;
+ }
+ }
+
+ /**
+ * Sets the ConnectionFactory class name.
+ *
+ * @param connectionFactoryClassName
+ * @since 2.7.0
+ */
+
+ public void setConnectionFactoryClassName(final String
connectionFactoryClassName) {
+ if (isEmpty(connectionFactoryClassName)) {
+ this.connectionFactoryClassName = null;
} else {
- this.driverClassName = null;
+ this.connectionFactoryClassName = connectionFactoryClassName;
}
}
@@ -2481,10 +2523,10 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
* the new value for the validation query
*/
public void setValidationQuery(final String validationQuery) {
- if (validationQuery != null && validationQuery.trim().length() > 0) {
- this.validationQuery = validationQuery;
- } else {
+ if (isEmpty(validationQuery)) {
this.validationQuery = null;
+ } else {
+ this.validationQuery = validationQuery;
}
}
@@ -2527,4 +2569,22 @@ public class BasicDataSource implements DataSource,
BasicDataSourceMXBean, MBean
config.setJmxNameBase(base.toString());
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 dfaab5e..e826cff 100644
--- a/src/main/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java
+++ b/src/main/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java
@@ -87,6 +87,7 @@ public class BasicDataSourceFactory implements ObjectFactory {
private static final String PROP_VALIDATION_QUERY = "validationQuery";
private static final String PROP_VALIDATION_QUERY_TIMEOUT =
"validationQueryTimeout";
private static final String PROP_JMX_NAME = "jmxName";
+ private static final String PROP_CONNECTION_FACTORY_CLASS_NAME =
"connectionFactoryClassName";
/**
* The property name for connectionInitSqls. The associated value String
must be of the form [query;]*
@@ -141,7 +142,8 @@ public class BasicDataSourceFactory implements
ObjectFactory {
PROP_REMOVE_ABANDONED_TIMEOUT, PROP_LOG_ABANDONED,
PROP_ABANDONED_USAGE_TRACKING, PROP_POOL_PREPARED_STATEMENTS,
PROP_MAX_OPEN_PREPARED_STATEMENTS, PROP_CONNECTION_PROPERTIES,
PROP_MAX_CONN_LIFETIME_MILLIS,
PROP_LOG_EXPIRED_CONNECTIONS, PROP_ROLLBACK_ON_RETURN,
PROP_ENABLE_AUTO_COMMIT_ON_RETURN,
- PROP_DEFAULT_QUERY_TIMEOUT, PROP_FAST_FAIL_VALIDATION,
PROP_DISCONNECTION_SQL_CODES, PROP_JMX_NAME };
+ PROP_DEFAULT_QUERY_TIMEOUT, PROP_FAST_FAIL_VALIDATION,
PROP_DISCONNECTION_SQL_CODES, PROP_JMX_NAME,
+ PROP_CONNECTION_FACTORY_CLASS_NAME };
/**
* Obsolete properties from DBCP 1.x. with warning strings suggesting new
properties. LinkedHashMap will guarantee
@@ -548,6 +550,13 @@ public class BasicDataSourceFactory implements
ObjectFactory {
dataSource.setDisconnectionSqlCodes(parseList(value, ','));
}
+ value = properties.getProperty(PROP_CONNECTION_FACTORY_CLASS_NAME);
+ if (value != null) {
+ dataSource.setConnectionFactoryClassName(value);
+ }
+
+
+
// DBCP-215
// Trick to make sure that initialSize connections are created
if (dataSource.getInitialSize() > 0) {
diff --git a/src/test/java/org/apache/commons/dbcp2/TestBasicDataSource.java
b/src/test/java/org/apache/commons/dbcp2/TestBasicDataSource.java
index aee9a65..732bdf0 100644
--- a/src/test/java/org/apache/commons/dbcp2/TestBasicDataSource.java
+++ b/src/test/java/org/apache/commons/dbcp2/TestBasicDataSource.java
@@ -17,8 +17,13 @@
package org.apache.commons.dbcp2;
-import static org.junit.jupiter.api.Assertions.*;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
import java.lang.management.ManagementFactory;
@@ -38,8 +43,8 @@ import org.apache.commons.logging.LogFactory;
import org.hamcrest.CoreMatchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/**
@@ -875,6 +880,42 @@ public class TestBasicDataSource extends
TestConnectionPool {
Assertions.assertNotEquals(Boolean.valueOf(original),
Boolean.valueOf(ds.getConnectionPool().getLogAbandoned()));
}
+
+ /**
+ * JIRA: DBCP-547
+ * Verify that ConnectionFactory interface in
BasicDataSource.createConnectionFactory().
+ */
+ @Test
+ public void testCreateConnectionFactory() throws Exception {
+
+ /** not set ConnectionFactoryClassName */
+ Properties properties = new Properties();
+ properties.put("initialSize", "1");
+ properties.put("driverClassName",
"org.apache.commons.dbcp2.TesterDriver");
+ properties.put("url", "jdbc:apache:commons:testdriver");
+ properties.put("username", "foo");
+ properties.put("password", "bar");
+ BasicDataSource ds =
BasicDataSourceFactory.createDataSource(properties);
+ Connection conn = ds.getConnection();
+ assertNotNull(conn);
+ conn.close();
+ ds.close();
+
+ /** set ConnectionFactoryClassName */
+ properties = new Properties();
+ properties.put("initialSize", "1");
+ properties.put("driverClassName",
"org.apache.commons.dbcp2.TesterDriver");
+ properties.put("url", "jdbc:apache:commons:testdriver");
+ properties.put("username", "foo");
+ properties.put("password", "bar");
+ properties.put("connectionFactoryClassName",
"org.apache.commons.dbcp2.TesterConnectionFactory");
+ ds = BasicDataSourceFactory.createDataSource(properties);
+ conn = ds.getConnection();
+ assertNotNull(conn);
+
+ conn.close();
+ ds.close();
+ }
}
/**
diff --git
a/src/test/java/org/apache/commons/dbcp2/TesterConnectionFactory.java
b/src/test/java/org/apache/commons/dbcp2/TesterConnectionFactory.java
new file mode 100644
index 0000000..7718e02
--- /dev/null
+++ b/src/test/java/org/apache/commons/dbcp2/TesterConnectionFactory.java
@@ -0,0 +1,84 @@
+/*
+ * 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.Connection;
+import java.sql.Driver;
+import java.sql.SQLException;
+import java.util.Properties;
+
+/**
+ * Dummy {@link ConnectionFactory} for testing purpose.
+ */
+public class TesterConnectionFactory implements ConnectionFactory {
+
+ private final String connectionString;
+ private final Driver driver;
+ private final Properties properties;
+
+ /**
+ * Constructs a connection factory for a given Driver.
+ *
+ * @param driver The Driver.
+ * @param connectString The connection string.
+ * @param properties The connection properties.
+ */
+ public TesterConnectionFactory(final Driver driver, final String
connectString, final Properties properties) {
+ this.driver = driver;
+ this.connectionString = connectString;
+ this.properties = properties;
+ }
+
+ @Override
+ public Connection createConnection() throws SQLException {
+ Connection conn = driver.connect(connectionString, properties);
+ doSomething(conn);
+ return conn;
+ }
+
+ private void doSomething(Connection conn) {
+ // do something
+ }
+
+ /**
+ * @return The connection String.
+ */
+ public String getConnectionString() {
+ return connectionString;
+ }
+
+ /**
+ * @return The Driver.
+ */
+ public Driver getDriver() {
+ return driver;
+ }
+
+ /**
+ * @return The Properties.
+ */
+ public Properties getProperties() {
+ return properties;
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getName() + " [" + String.valueOf(driver) + ";"
+ String.valueOf(connectionString) + ";"
+ + String.valueOf(properties) + "]";
+ }
+}