This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/master by this push: new 799345a Update Commons DBCP2 799345a is described below commit 799345aa5a0dcce468fe27f65c9129431c9bbf82 Author: Mark Thomas <ma...@apache.org> AuthorDate: Thu Aug 1 22:09:08 2019 +0100 Update Commons DBCP2 --- MERGE.txt | 2 +- .../apache/tomcat/dbcp/dbcp2/AbandonedTrace.java | 14 +- .../apache/tomcat/dbcp/dbcp2/BasicDataSource.java | 444 ++++++------- .../tomcat/dbcp/dbcp2/BasicDataSourceFactory.java | 9 +- .../dbcp/dbcp2/ConnectionFactoryFactory.java | 77 +++ .../tomcat/dbcp/dbcp2/DelegatingConnection.java | 67 +- .../tomcat/dbcp/dbcp2/DelegatingResultSet.java | 4 +- .../tomcat/dbcp/dbcp2/DelegatingStatement.java | 57 +- .../tomcat/dbcp/dbcp2/DriverConnectionFactory.java | 2 + .../apache/tomcat/dbcp/dbcp2/DriverFactory.java | 81 +++ .../org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java | 2 +- .../dbcp/dbcp2/PoolableCallableStatement.java | 29 +- .../dbcp/dbcp2/PoolablePreparedStatement.java | 33 +- .../apache/tomcat/dbcp/dbcp2/SQLExceptionList.java | 51 ++ .../dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java | 691 +++++++++++---------- .../dbcp2/cpdsadapter/PooledConnectionImpl.java | 81 +++ .../dbcp2/datasources/InstanceKeyDataSource.java | 20 +- .../datasources/InstanceKeyDataSourceFactory.java | 2 +- webapps/docs/changelog.xml | 4 + 19 files changed, 988 insertions(+), 682 deletions(-) diff --git a/MERGE.txt b/MERGE.txt index dd72706..396405a 100644 --- a/MERGE.txt +++ b/MERGE.txt @@ -63,7 +63,7 @@ Sub-tree src/main/java/org/apache/commons/dbcp2 src/main/resources/org/apache/commons/dbcp2 The SHA1 ID for the most recent commit to be merged to Tomcat is: -dcdbc72acf51155d2a6c3f10461d9712a3623686 (2019-04-24) +87d9e3a66b896d81339a0947d001837ad2651605 (2019-08-01) Pool2 Sub-tree diff --git a/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java b/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java index ea6d5a2..3969480 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java @@ -155,7 +155,7 @@ public class AbandonedTrace implements TrackedUse { final Iterator<WeakReference<AbandonedTrace>> iter = traceList.iterator(); while (iter.hasNext()) { final AbandonedTrace traceInList = iter.next().get(); - if (trace.equals(traceInList)) { + if (trace != null && trace.equals(traceInList)) { iter.remove(); break; } else if (traceInList == null) { @@ -165,4 +165,16 @@ public class AbandonedTrace implements TrackedUse { } } } + + /** + * Removes this object the source object is tracing. + * + * @param source The object tracing + * @since 2.7.0 + */ + protected void removeThisTrace(final Object source) { + if (source instanceof AbandonedTrace) { + AbandonedTrace.class.cast(source).removeTrace(this); + } + } } diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java index ba3e38a..6345a22 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java @@ -76,8 +76,6 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean private static final Log log = LogFactory.getLog(BasicDataSource.class); - // ------------------------------------------------------------- Properties - static { // Attempt to prevent deadlocks - see DBCP - 272 DriverManager.getDrivers(); @@ -108,6 +106,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean } } + @SuppressWarnings("resource") protected static void validateConnectionFactory(final PoolableConnectionFactory connectionFactory) throws Exception { PoolableConnection conn = null; @@ -315,6 +314,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 @@ -380,10 +384,8 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * be called before the first connection is retrieved (along with all the other configuration property setters). * Calls to this method after the connection pool has been initialized have no effect. * - * @param name - * Name of the custom connection property - * @param value - * Value of the custom connection property + * @param name Name of the custom connection property + * @param value Value of the custom connection property */ public void addConnectionProperty(final String name, final String value) { connectionProperties.put(name, value); @@ -408,8 +410,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * exceptions. * </p> * - * @throws SQLException - * if an error occurs closing idle connections + * @throws SQLException if an error occurs closing idle connections */ @Override public synchronized void close() throws SQLException { @@ -458,77 +459,17 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * 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 factort cannot be created + * @throws SQLException 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 ConnectionFactoryFactory.createConnectionFactory(this, DriverFactory.createDriver(this)); } /** @@ -540,8 +481,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * positive value causes {@link GenericObjectPool}'s eviction timer to be started. * </p> * - * @param factory - * The factory to use to create new connections for this pool. + * @param factory The factory to use to create new connections for this pool. */ protected void createConnectionPool(final PoolableConnectionFactory factory) { // Create an object pool to contain our active connections @@ -574,8 +514,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * </p> * * @return The current internal DataSource or a newly created instance if it has not yet been created. - * @throws SQLException - * if the object pool cannot be created. + * @throws SQLException if the object pool cannot be created. */ protected DataSource createDataSource() throws SQLException { if (closed) { @@ -648,7 +587,8 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean throw new SQLException("Error preloading the connection pool", e); } - // If timeBetweenEvictionRunsMillis > 0, start the pool's evictor task + // If timeBetweenEvictionRunsMillis > 0, start the pool's evictor + // task startPoolMaintenance(); dataSource = newDataSource; @@ -660,8 +600,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Creates the actual data source instance. This method only exists so that subclasses can replace the * implementation class. * - * @throws SQLException - * if unable to create a datasource instance + * @throws SQLException if unable to create a datasource instance * * @return A new DataSource instance */ @@ -674,12 +613,9 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean /** * Creates an object pool used to provide pooling support for {@link Connection JDBC connections}. * - * @param factory - * the object factory - * @param poolConfig - * the object pool configuration - * @param abandonedConfig - * the abandoned objects configuration + * @param factory the object factory + * @param poolConfig the object pool configuration + * @param abandonedConfig the abandoned objects configuration * @return a non-null instance */ protected GenericObjectPool<PoolableConnection> createObjectPool(final PoolableConnectionFactory factory, @@ -698,10 +634,8 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Creates the PoolableConnectionFactory and attaches it to the connection pool. This method only exists so * subclasses can replace the default implementation. * - * @param driverConnectionFactory - * JDBC connection factory - * @throws SQLException - * if an error occurs creating the PoolableConnectionFactory + * @param driverConnectionFactory JDBC connection factory + * @throws SQLException if an error occurs creating the PoolableConnectionFactory * * @return A new PoolableConnectionFactory configured with the current configuration of this BasicDataSource */ @@ -738,6 +672,17 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean } /** + * Manually evicts idle connections + * + * @throws Exception when there is a problem evicting idle objects. + */ + public void evict() throws Exception { + if (connectionPool != null) { + connectionPool.evict(); + } + } + + /** * Gets the print writer used by this configuration to log information on abandoned objects. * * @return The print writer used by this configuration to log information on abandoned objects. @@ -788,8 +733,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean /** * Creates (if necessary) and return a connection to the database. * - * @throws SQLException - * if a database access error occurs + * @throws SQLException if a database access error occurs * @return a database connection */ @Override @@ -812,24 +756,34 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean /** * <strong>BasicDataSource does NOT support this method.</strong> * - * @param user - * Database user on whose behalf the Connection is being made - * @param pass - * The database user's password + * @param user Database user on whose behalf the Connection is being made + * @param pass The database user's password * - * @throws UnsupportedOperationException - * always thrown. - * @throws SQLException - * if a database access error occurs + * @throws UnsupportedOperationException always thrown. + * @throws SQLException if a database access error occurs * @return nothing - always throws UnsupportedOperationException */ @Override public Connection getConnection(final String user, final String pass) throws SQLException { - // This method isn't supported by the PoolingDataSource returned by the createDataSource + // This method isn't supported by the PoolingDataSource returned by the + // createDataSource throw new UnsupportedOperationException("Not supported by BasicDataSource"); } /** + * 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. * @@ -856,7 +810,6 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean return connectionPool; } - // For unit testing Properties getConnectionProperties() { return connectionProperties; } @@ -1096,15 +1049,15 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool. * </p> * - * @throws SQLException - * if a database access error occurs - * @throws UnsupportedOperationException - * If the DataSource implementation does not support the login timeout feature. + * @throws SQLException if a database access error occurs + * @throws UnsupportedOperationException If the DataSource implementation does not support the login timeout + * feature. * @return login timeout in seconds */ @Override public int getLoginTimeout() throws SQLException { - // This method isn't supported by the PoolingDataSource returned by the createDataSource + // This method isn't supported by the PoolingDataSource returned by the + // createDataSource throw new UnsupportedOperationException("Not supported by BasicDataSource"); } @@ -1116,8 +1069,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool. * </p> * - * @throws SQLException - * if a database access error occurs + * @throws SQLException if a database access error occurs * @return log writer in use */ @Override @@ -1485,13 +1437,12 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Manually invalidates a connection, effectively requesting the pool to try to close it, remove it from the pool * and reclaim pool capacity. * - * @param connection - * The Connection to invalidate. + * @param connection The Connection to invalidate. * - * @throws IllegalStateException - * if invalidating the connection failed. + * @throws IllegalStateException if invalidating the connection failed. * @since 2.1 */ + @SuppressWarnings("resource") public void invalidateConnection(final Connection connection) throws IllegalStateException { if (connection == null) { return; @@ -1519,18 +1470,6 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean } /** - * Manually evicts idle connections. - * - * @throws Exception Thrown by {@link GenericObjectPool#evict()}. - * @see GenericObjectPool#evict() - */ - public void evict() throws Exception { - if (connectionPool != null) { - connectionPool.evict(); - } - } - - /** * Returns the value of the accessToUnderlyingConnectionAllowed property. * * @return true if access to the underlying connection is allowed, false otherwise. @@ -1551,6 +1490,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 @@ -1588,6 +1537,20 @@ 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(String message, Throwable throwable) { + if (logWriter != null) { + logWriter.println(message); + throwable.printStackTrace(logWriter); + } + } + @Override public void postDeregister() { // NO-OP @@ -1622,8 +1585,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean /** * Removes a custom connection property. * - * @param name - * Name of the custom connection property to remove + * @param name Name of the custom connection property to remove * @see #addConnectionProperty(String, String) */ public void removeConnectionProperty(final String name) { @@ -1633,8 +1595,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean /** * Sets the print writer to be used by this configuration to log information on abandoned objects. * - * @param logWriter - * The new log writer + * @param logWriter The new log writer */ public void setAbandonedLogWriter(final PrintWriter logWriter) { if (abandonedConfig == null) { @@ -1652,9 +1613,8 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * the connection pool should record a stack trace every time a method is called on a pooled connection and retain * the most recent stack trace to aid debugging of abandoned connections. * - * @param usageTracking - * A value of <code>true</code> will enable the recording of a stack trace on every use of a pooled - * connection + * @param usageTracking A value of <code>true</code> will enable the recording of a stack trace on every use of a + * pooled connection */ public void setAbandonedUsageTracking(final boolean usageTracking) { if (abandonedConfig == null) { @@ -1678,8 +1638,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param allow - * Access to the underlying connection is granted when true. + * @param allow Access to the underlying connection is granted when true. */ public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) { this.accessToUnderlyingConnectionAllowed = allow; @@ -1690,25 +1649,40 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * 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. * - * @param autoCommitOnReturn - * Whether or not connections being returned to the pool will be checked and configured with auto-commit. + * @param autoCommitOnReturn Whether or not connections being returned to the pool will be checked and configured + * with auto-commit. * @since 2.6.0 */ public void setAutoCommitOnReturn(final boolean autoCommitOnReturn) { this.autoCommitOnReturn = autoCommitOnReturn; } + // ----------------------------------------------------- DataSource Methods + /** * Sets the state caching flag. * - * @param cacheState - * The new value for the state caching flag + * @param cacheState The new value for the state caching flag */ public void setCacheState(final boolean cacheState) { this.cacheState = cacheState; } /** + * 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. * <p> * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first @@ -1716,14 +1690,13 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param connectionInitSqls - * Collection of SQL statements to execute on connection creation + * @param connectionInitSqls Collection of SQL statements to execute on connection creation */ public void setConnectionInitSqls(final Collection<String> connectionInitSqls) { 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<>(); } @@ -1736,8 +1709,6 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean } } - // ----------------------------------------------------- DataSource Methods - /** * Sets the connection properties passed to driver.connect(...). * <p> @@ -1747,8 +1718,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * NOTE - The "user" and "password" properties will be added explicitly, so they do not need to be included here. * </p> * - * @param connectionProperties - * the connection properties used to create new connections + * @param connectionProperties the connection properties used to create new connections */ public void setConnectionProperties(final String connectionProperties) { Objects.requireNonNull(connectionProperties, "connectionProperties is null"); @@ -1762,7 +1732,8 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean final String value = entry.substring(index + 1); properties.setProperty(name, value); } else { - // no value is empty string which is how java.util.Properties works + // no value is empty string which is how + // java.util.Properties works properties.setProperty(entry, ""); } } @@ -1780,8 +1751,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param defaultAutoCommit - * default auto-commit value + * @param defaultAutoCommit default auto-commit value */ public void setDefaultAutoCommit(final Boolean defaultAutoCommit) { this.defaultAutoCommit = defaultAutoCommit; @@ -1797,14 +1767,13 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param defaultCatalog - * the default catalog + * @param defaultCatalog 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; } } @@ -1812,8 +1781,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Sets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this * connection. <code>null</code> means that the driver default will be used. * - * @param defaultQueryTimeoutSeconds - * The default query timeout in seconds. + * @param defaultQueryTimeoutSeconds The default query timeout in seconds. */ public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) { this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds; @@ -1829,8 +1797,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param defaultReadOnly - * default read-only value + * @param defaultReadOnly default read-only value */ public void setDefaultReadOnly(final Boolean defaultReadOnly) { this.defaultReadOnly = defaultReadOnly; @@ -1846,15 +1813,14 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param defaultSchema - * the default catalog + * @param defaultSchema the default catalog * @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; } } @@ -1868,8 +1834,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param defaultTransactionIsolation - * the default transaction isolation state + * @param defaultTransactionIsolation the default transaction isolation state * @see Connection#getTransactionIsolation */ public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) { @@ -1894,15 +1859,14 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter}. * </p> * - * @param disconnectionSqlCodes - * SQL_STATE codes considered to signal fatal conditions + * @param disconnectionSqlCodes SQL_STATE codes considered to signal fatal conditions * @since 2.1 */ public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) { 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<>(); } @@ -1923,8 +1887,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param driver - * The JDBC Driver instance to use for this pool. + * @param driver The JDBC Driver instance to use for this pool. */ public synchronized void setDriver(final Driver driver) { this.driver = driver; @@ -1940,8 +1903,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param driverClassLoader - * the class loader with which to load the JDBC driver + * @param driverClassLoader the class loader with which to load the JDBC driver */ public synchronized void setDriverClassLoader(final ClassLoader driverClassLoader) { this.driverClassLoader = driverClassLoader; @@ -1957,14 +1919,13 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param driverClassName - * the class name of the JDBC driver + * @param driverClassName the class name of the JDBC driver */ public synchronized void setDriverClassName(final String driverClassName) { - if (driverClassName != null && driverClassName.trim().length() > 0) { - this.driverClassName = driverClassName; - } else { + if (isEmpty(driverClassName)) { this.driverClassName = null; + } else { + this.driverClassName = driverClassName; } } @@ -1973,8 +1934,8 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * 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. * - * @param autoCommitOnReturn - * Whether or not connections being returned to the pool will be checked and configured with auto-commit. + * @param autoCommitOnReturn Whether or not connections being returned to the pool will be checked and configured + * with auto-commit. * @deprecated Use {@link #setAutoCommitOnReturn(boolean)}. */ @Deprecated @@ -1985,8 +1946,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean /** * Sets the EvictionPolicy implementation to use with this connection pool. * - * @param evictionPolicyClassName - * The fully qualified class name of the EvictionPolicy implementation + * @param evictionPolicyClassName The fully qualified class name of the EvictionPolicy implementation */ public synchronized void setEvictionPolicyClassName(final String evictionPolicyClassName) { if (connectionPool != null) { @@ -1997,8 +1957,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean /** * @see #getFastFailValidation() - * @param fastFailValidation - * true means connections created by this factory will fast fail validation + * @param fastFailValidation true means connections created by this factory will fast fail validation * @since 2.1 */ public void setFastFailValidation(final boolean fastFailValidation) { @@ -2015,8 +1974,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param initialSize - * the number of connections created when the pool is initialized + * @param initialSize the number of connections created when the pool is initialized */ public synchronized void setInitialSize(final int initialSize) { this.initialSize = initialSize; @@ -2028,8 +1986,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * this DataSource with JMX and this name is valid this name will be used in preference to any specified by the * other component. * - * @param jmxName - * The JMX name that has been requested for this DataSource + * @param jmxName The JMX name that has been requested for this DataSource */ public void setJmxName(final String jmxName) { this.jmxName = jmxName; @@ -2038,8 +1995,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean /** * Sets the LIFO property. True means the pool behaves as a LIFO queue; false means FIFO. * - * @param lifo - * the new value for the LIFO property + * @param lifo the new value for the LIFO property */ public synchronized void setLifo(final boolean lifo) { this.lifo = lifo; @@ -2049,8 +2005,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean } /** - * @param logAbandoned - * new logAbandoned property value + * @param logAbandoned new logAbandoned property value */ public void setLogAbandoned(final boolean logAbandoned) { if (abandonedConfig == null) { @@ -2068,9 +2023,8 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * not log messages are generated when the pool closes connections due to maximum lifetime exceeded. Set this * property to false to suppress log messages when connections expire. * - * @param logExpiredConnections - * Whether or not log messages are generated when the pool closes connections due to maximum lifetime - * exceeded. + * @param logExpiredConnections Whether or not log messages are generated when the pool closes connections due to + * maximum lifetime exceeded. */ public void setLogExpiredConnections(final boolean logExpiredConnections) { this.logExpiredConnections = logExpiredConnections; @@ -2086,16 +2040,15 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool. * </p> * - * @param loginTimeout - * The new login timeout, or zero for no timeout - * @throws UnsupportedOperationException - * If the DataSource implementation does not support the login timeout feature. - * @throws SQLException - * if a database access error occurs + * @param loginTimeout The new login timeout, or zero for no timeout + * @throws UnsupportedOperationException If the DataSource implementation does not support the login timeout + * feature. + * @throws SQLException if a database access error occurs */ @Override public void setLoginTimeout(final int loginTimeout) throws SQLException { - // This method isn't supported by the PoolingDataSource returned by the createDataSource + // This method isn't supported by the PoolingDataSource returned by the + // createDataSource throw new UnsupportedOperationException("Not supported by BasicDataSource"); } @@ -2107,10 +2060,8 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool. * </p> * - * @param logWriter - * The new log writer - * @throws SQLException - * if a database access error occurs + * @param logWriter The new log writer + * @throws SQLException if a database access error occurs */ @Override public void setLogWriter(final PrintWriter logWriter) throws SQLException { @@ -2129,8 +2080,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param maxConnLifetimeMillis - * The maximum permitted lifetime of a connection in milliseconds. + * @param maxConnLifetimeMillis The maximum permitted lifetime of a connection in milliseconds. */ public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) { this.maxConnLifetimeMillis = maxConnLifetimeMillis; @@ -2141,8 +2091,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * return to the pool. * * @see #getMaxIdle() - * @param maxIdle - * the new value for maxIdle + * @param maxIdle the new value for maxIdle */ public synchronized void setMaxIdle(final int maxIdle) { this.maxIdle = maxIdle; @@ -2161,8 +2110,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param maxOpenStatements - * the new maximum number of prepared statements + * @param maxOpenStatements the new maximum number of prepared statements */ public synchronized void setMaxOpenPreparedStatements(final int maxOpenStatements) { this.maxOpenPreparedStatements = maxOpenStatements; @@ -2172,8 +2120,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Sets the maximum total number of idle and borrows connections that can be active at the same time. Use a negative * value for no limit. * - * @param maxTotal - * the new value for maxTotal + * @param maxTotal the new value for maxTotal * @see #getMaxTotal() */ public synchronized void setMaxTotal(final int maxTotal) { @@ -2186,8 +2133,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean /** * Sets the MaxWaitMillis property. Use -1 to make the pool wait indefinitely. * - * @param maxWaitMillis - * the new value for MaxWaitMillis + * @param maxWaitMillis the new value for MaxWaitMillis * @see #getMaxWaitMillis() */ public synchronized void setMaxWaitMillis(final long maxWaitMillis) { @@ -2200,8 +2146,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean /** * Sets the {@link #minEvictableIdleTimeMillis} property. * - * @param minEvictableIdleTimeMillis - * the minimum amount of time an object may sit idle in the pool + * @param minEvictableIdleTimeMillis the minimum amount of time an object may sit idle in the pool * @see #minEvictableIdleTimeMillis */ public synchronized void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) { @@ -2211,13 +2156,14 @@ 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 * {@link #timeBetweenEvictionRunsMillis} has a positive value. * - * @param minIdle - * the new value for minIdle + * @param minIdle the new value for minIdle * @see GenericObjectPool#setMinIdle(int) */ public synchronized void setMinIdle(final int minIdle) { @@ -2230,8 +2176,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean /** * Sets the value of the {@link #numTestsPerEvictionRun} property. * - * @param numTestsPerEvictionRun - * the new {@link #numTestsPerEvictionRun} value + * @param numTestsPerEvictionRun the new {@link #numTestsPerEvictionRun} value * @see #numTestsPerEvictionRun */ public synchronized void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) { @@ -2241,8 +2186,6 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean } } - // ------------------------------------------------------ Protected Methods - /** * <p> * Sets the {@link #password}. @@ -2253,8 +2196,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param password - * new value for the password + * @param password new value for the password */ public void setPassword(final String password) { this.password = password; @@ -2270,16 +2212,15 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param poolingStatements - * pooling on or off + * @param poolingStatements pooling on or off */ public synchronized void setPoolPreparedStatements(final boolean poolingStatements) { this.poolPreparedStatements = poolingStatements; } /** - * @param removeAbandonedOnBorrow - * true means abandoned connections may be removed when connections are borrowed from the pool. + * @param removeAbandonedOnBorrow true means abandoned connections may be removed when connections are borrowed from + * the pool. * @see #getRemoveAbandonedOnBorrow() */ public void setRemoveAbandonedOnBorrow(final boolean removeAbandonedOnBorrow) { @@ -2294,8 +2235,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean } /** - * @param removeAbandonedOnMaintenance - * true means abandoned connections may be removed on pool maintenance. + * @param removeAbandonedOnMaintenance true means abandoned connections may be removed on pool maintenance. * @see #getRemoveAbandonedOnMaintenance() */ public void setRemoveAbandonedOnMaintenance(final boolean removeAbandonedOnMaintenance) { @@ -2319,8 +2259,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * {@link #getRemoveAbandonedOnMaintenance()} are false. * </p> * - * @param removeAbandonedTimeout - * new abandoned timeout in seconds + * @param removeAbandonedTimeout new abandoned timeout in seconds * @see #getRemoveAbandonedTimeout() * @see #getRemoveAbandonedOnBorrow() * @see #getRemoveAbandonedOnMaintenance() @@ -2340,8 +2279,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Sets the flag that controls if a connection will be rolled back when it is returned to the pool if auto commit is * not enabled and the connection is not read only. * - * @param rollbackOnReturn - * whether a connection will be rolled back when it is returned to the pool. + * @param rollbackOnReturn whether a connection will be rolled back when it is returned to the pool. */ public void setRollbackOnReturn(final boolean rollbackOnReturn) { this.rollbackOnReturn = rollbackOnReturn; @@ -2351,9 +2289,9 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Sets the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by the * idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool. * - * @param softMinEvictableIdleTimeMillis - * minimum amount of time a connection may sit idle in the pool before it is eligible for eviction, - * assuming there are minIdle idle connections in the pool. + * @param softMinEvictableIdleTimeMillis minimum amount of time a connection may sit idle in the pool before it is + * eligible for eviction, assuming there are minIdle idle connections in the + * pool. * @see #getSoftMinEvictableIdleTimeMillis */ public synchronized void setSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) { @@ -2367,8 +2305,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Sets the {@link #testOnBorrow} property. This property determines whether or not the pool will validate objects * before they are borrowed from the pool. * - * @param testOnBorrow - * new value for testOnBorrow property + * @param testOnBorrow new value for testOnBorrow property */ public synchronized void setTestOnBorrow(final boolean testOnBorrow) { this.testOnBorrow = testOnBorrow; @@ -2381,8 +2318,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Sets the {@link #testOnCreate} property. This property determines whether or not the pool will validate objects * immediately after they are created by the pool * - * @param testOnCreate - * new value for testOnCreate property + * @param testOnCreate new value for testOnCreate property */ public synchronized void setTestOnCreate(final boolean testOnCreate) { this.testOnCreate = testOnCreate; @@ -2395,8 +2331,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Sets the <code>testOnReturn</code> property. This property determines whether or not the pool will validate * objects before they are returned to the pool. * - * @param testOnReturn - * new value for testOnReturn property + * @param testOnReturn new value for testOnReturn property */ public synchronized void setTestOnReturn(final boolean testOnReturn) { this.testOnReturn = testOnReturn; @@ -2409,8 +2344,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * Sets the <code>testWhileIdle</code> property. This property determines whether or not the idle object evictor * will validate connections. * - * @param testWhileIdle - * new value for testWhileIdle property + * @param testWhileIdle new value for testWhileIdle property */ public synchronized void setTestWhileIdle(final boolean testWhileIdle) { this.testWhileIdle = testWhileIdle; @@ -2422,8 +2356,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean /** * Sets the {@link #timeBetweenEvictionRunsMillis} property. * - * @param timeBetweenEvictionRunsMillis - * the new time between evictor runs + * @param timeBetweenEvictionRunsMillis the new time between evictor runs * @see #timeBetweenEvictionRunsMillis */ public synchronized void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) { @@ -2443,8 +2376,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param url - * the new value for the JDBC connection url + * @param url the new value for the JDBC connection url */ public synchronized void setUrl(final String url) { this.url = url; @@ -2460,8 +2392,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param userName - * the new value for the JDBC connection user name + * @param userName the new value for the JDBC connection user name */ public void setUsername(final String userName) { this.userName = userName; @@ -2477,14 +2408,13 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param validationQuery - * the new value for the validation query + * @param validationQuery 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; } } @@ -2497,8 +2427,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean * setLoginTimeout, getLoginTimeout, getLogWriter.</code> * </p> * - * @param validationQueryTimeoutSeconds - * new validation query timeout value in seconds + * @param validationQueryTimeoutSeconds new validation query timeout value in seconds */ public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) { this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds; @@ -2527,4 +2456,5 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean config.setJmxNameBase(base.toString()); config.setJmxNamePrefix(Constants.JMX_CONNECTION_POOL_PREFIX); } + } diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java index eff9a7c..158b944 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java +++ b/java/org/apache/tomcat/dbcp/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,11 @@ 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/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactoryFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactoryFactory.java new file mode 100644 index 0000000..708ee3a --- /dev/null +++ b/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactoryFactory.java @@ -0,0 +1,77 @@ +/* + * 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.tomcat.dbcp.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'"); + } + 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/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java index 5869a36..21d77eb 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java @@ -34,6 +34,7 @@ import java.sql.SQLXML; import java.sql.Savepoint; import java.sql.Statement; import java.sql.Struct; +import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -87,19 +88,20 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i /** * Returns a string representation of the metadata associated with the innermost delegate connection. */ + @SuppressWarnings("resource") @Override public synchronized String toString() { - String s = null; + String str = null; - final Connection c = this.getInnermostDelegateInternal(); - if (c != null) { + final Connection conn = this.getInnermostDelegateInternal(); + if (conn != null) { try { - if (c.isClosed()) { - s = "connection is closed"; + if (conn.isClosed()) { + str = "connection is closed"; } else { final StringBuffer sb = new StringBuffer(); sb.append(hashCode()); - final DatabaseMetaData meta = c.getMetaData(); + final DatabaseMetaData meta = conn.getMetaData(); if (meta != null) { sb.append(", URL="); sb.append(meta.getURL()); @@ -107,19 +109,14 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i sb.append(meta.getUserName()); sb.append(", "); sb.append(meta.getDriverName()); - s = sb.toString(); + str = sb.toString(); } } } catch (final SQLException ex) { // Ignore } } - - if (s == null) { - s = super.toString(); - } - - return s; + return str != null ? str : super.toString(); } /** @@ -142,6 +139,7 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i * connection to compare innermost delegate with * @return true if innermost delegate equals <code>c</code> */ + @SuppressWarnings("resource") public boolean innermostDelegateEquals(final Connection c) { final Connection innerCon = getInnermostDelegateInternal(); if (innerCon == null) { @@ -174,15 +172,16 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i * * @return innermost delegate. */ + @SuppressWarnings("resource") public final Connection getInnermostDelegateInternal() { - Connection c = connection; - while (c != null && c instanceof DelegatingConnection) { - c = ((DelegatingConnection<?>) c).getDelegateInternal(); - if (this == c) { + Connection conn = connection; + while (conn != null && conn instanceof DelegatingConnection) { + conn = ((DelegatingConnection<?>) conn).getDelegateInternal(); + if (this == conn) { return null; } } - return c; + return conn; } /** @@ -251,6 +250,18 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i throw e; } + /** + * Handles the given {@code SQLException}. + * + * @param <T> The throwable type. + * @param e The SQLException + * @return the given {@code SQLException} + * @since 2.7.0 + */ + protected <T extends Throwable> T handleExceptionNoThrow(final T e) { + return e; + } + private void initializeStatement(final DelegatingStatement ds) throws SQLException { if (defaultQueryTimeoutSeconds != null && defaultQueryTimeoutSeconds.intValue() != ds.getQueryTimeout()) { ds.setQueryTimeout(defaultQueryTimeoutSeconds.intValue()); @@ -606,23 +617,35 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i } protected void passivate() throws SQLException { - // The JDBC spec requires that a Connection close any open + // The JDBC specification requires that a Connection close any open // Statement's when it is closed. // DBCP-288. Not all the traced objects will be statements final List<AbandonedTrace> traces = getTrace(); - if (traces != null && traces.size() > 0) { + if (traces != null && traces.isEmpty()) { + final List<Exception> thrown = new ArrayList<>(); final Iterator<AbandonedTrace> traceIter = traces.iterator(); while (traceIter.hasNext()) { final Object trace = traceIter.next(); if (trace instanceof Statement) { - ((Statement) trace).close(); + try { + ((Statement) trace).close(); + } catch (Exception e) { + thrown.add(e); + } } else if (trace instanceof ResultSet) { // DBCP-265: Need to close the result sets that are // generated via DatabaseMetaData - ((ResultSet) trace).close(); + try { + ((ResultSet) trace).close(); + } catch (Exception e) { + thrown.add(e); + } } } clearTrace(); + if (!thrown.isEmpty()) { + throw new SQLExceptionList(thrown); + } } setLastUsed(0); } diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java index 256a29d..0f61d1f 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java @@ -186,11 +186,11 @@ public final class DelegatingResultSet extends AbandonedTrace implements ResultS public void close() throws SQLException { try { if (statement != null) { - ((AbandonedTrace) statement).removeTrace(this); + removeThisTrace(statement); statement = null; } if (connection != null) { - ((AbandonedTrace) connection).removeTrace(this); + removeThisTrace(connection); connection = null; } resultSet.close(); diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java index 44aa05d..d4f9355 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java @@ -21,6 +21,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.Statement; +import java.util.ArrayList; import java.util.List; /** @@ -125,35 +126,53 @@ public class DelegatingStatement extends AbandonedTrace implements Statement { if (isClosed()) { return; } + final List<Exception> thrown = new ArrayList<>(); try { - try { - if (connection != null) { - connection.removeTrace(this); - connection = null; - } + if (connection != null) { + connection.removeTrace(this); + connection = null; + } - // The JDBC spec requires that a statement close any open - // ResultSet's when it is closed. - // FIXME The PreparedStatement we're wrapping should handle this for us. - // See bug 17301 for what could happen when ResultSets are closed twice. - final List<AbandonedTrace> resultSets = getTrace(); - if (resultSets != null) { - final ResultSet[] set = resultSets.toArray(new ResultSet[resultSets.size()]); - for (final ResultSet element : set) { - element.close(); + // The JDBC spec requires that a statement close any open + // ResultSet's when it is closed. + // FIXME The PreparedStatement we're wrapping should handle this for us. + // See bug 17301 for what could happen when ResultSets are closed twice. + final List<AbandonedTrace> resultSetList = getTrace(); + if (resultSetList != null) { + final int size = resultSetList.size(); + final ResultSet[] resultSets = resultSetList.toArray(new ResultSet[size]); + for (final ResultSet resultSet : resultSets) { + if (resultSet != null) { + try { + resultSet.close(); + } catch (Exception e) { + if (connection != null) { + // Does not rethrow e. + connection.handleExceptionNoThrow(e); + } + thrown.add(e); + } } clearTrace(); } - if (statement != null) { - statement.close(); + try { + statement.close(); + } catch (Exception e) { + if (connection != null) { + // Does not rethrow e. + connection.handleExceptionNoThrow(e); + } + thrown.add(e); + } } - } catch (final SQLException e) { - handleException(e); } } finally { closed = true; statement = null; + if (!thrown.isEmpty()) { + throw new SQLExceptionList(thrown); + } } } @@ -615,7 +634,7 @@ public class DelegatingStatement extends AbandonedTrace implements Statement { } /* - * Note was protected prior to JDBC 4 + * Note: This method was protected prior to JDBC 4. */ @Override public boolean isClosed() throws SQLException { diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java index 7e26052..45444ec 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java @@ -29,7 +29,9 @@ import java.util.Properties; public class DriverConnectionFactory implements ConnectionFactory { private final String connectionString; + private final Driver driver; + private final Properties properties; /** diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DriverFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/DriverFactory.java new file mode 100644 index 0000000..82af50d --- /dev/null +++ b/java/org/apache/tomcat/dbcp/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.tomcat.dbcp.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; + } + +} diff --git a/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java b/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java index b4ee5b9..eb0d09d 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java @@ -304,7 +304,7 @@ public class Jdbc41Bridge { return (T) resultSet.getURL(columnLabel); } throw new SQLFeatureNotSupportedException( - String.format("resultSet=%s, columnLabel=%,d, type=%s", resultSet, columnLabel, type)); + String.format("resultSet=%s, columnLabel=%s, type=%s", resultSet, columnLabel, type)); } } diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java index 486da28..9c0be44 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java @@ -21,6 +21,7 @@ import java.sql.CallableStatement; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; import java.util.List; import org.apache.tomcat.dbcp.pool2.KeyedObjectPool; @@ -67,9 +68,7 @@ public class PoolableCallableStatement extends DelegatingCallableStatement { // Remove from trace now because this statement will be // added by the activate method. - if (getConnectionInternal() != null) { - getConnectionInternal().removeTrace(this); - } + removeThisTrace(getConnectionInternal()); } /** @@ -115,21 +114,29 @@ public class PoolableCallableStatement extends DelegatingCallableStatement { @Override public void passivate() throws SQLException { setClosedInternal(true); - if (getConnectionInternal() != null) { - getConnectionInternal().removeTrace(this); - } + removeThisTrace(getConnectionInternal()); // The JDBC spec requires that a statement close any open // ResultSet's when it is closed. // FIXME The PreparedStatement we're wrapping should handle this for us. // See DBCP-10 for what could happen when ResultSets are closed twice. - final List<AbandonedTrace> resultSets = getTrace(); - if (resultSets != null) { - final ResultSet[] set = resultSets.toArray(new ResultSet[resultSets.size()]); - for (final ResultSet element : set) { - element.close(); + final List<AbandonedTrace> resultSetList = getTrace(); + if (resultSetList != null) { + final List<Exception> thrown = new ArrayList<>(); + final ResultSet[] resultSets = resultSetList.toArray(new ResultSet[resultSetList.size()]); + for (final ResultSet resultSet : resultSets) { + if (resultSet != null) { + try { + resultSet.close(); + } catch (Exception e) { + thrown.add(e); + } + } } clearTrace(); + if (!thrown.isEmpty()) { + throw new SQLExceptionList(thrown); + } } super.passivate(); diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java index 29136d0..d8e45c4 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java @@ -20,6 +20,7 @@ package org.apache.tomcat.dbcp.dbcp2; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; import java.util.List; import org.apache.tomcat.dbcp.pool2.KeyedObjectPool; @@ -29,6 +30,7 @@ import org.apache.tomcat.dbcp.pool2.KeyedObjectPool; * {@link PreparedStatement}s. * <p> * My {@link #close} method returns me to my containing pool. (See {@link PoolingConnection}.) + * </p> * * @param <K> * the key type @@ -37,6 +39,7 @@ import org.apache.tomcat.dbcp.pool2.KeyedObjectPool; * @since 2.0 */ public class PoolablePreparedStatement<K> extends DelegatingPreparedStatement { + /** * The {@link KeyedObjectPool} from which I was obtained. */ @@ -50,7 +53,7 @@ public class PoolablePreparedStatement<K> extends DelegatingPreparedStatement { private volatile boolean batchAdded = false; /** - * Constructor + * Constructor. * * @param stmt * my underlying {@link PreparedStatement} @@ -69,9 +72,7 @@ public class PoolablePreparedStatement<K> extends DelegatingPreparedStatement { // Remove from trace now because this statement will be // added by the activate method. - if (getConnectionInternal() != null) { - getConnectionInternal().removeTrace(this); - } + removeThisTrace(getConnectionInternal()); } /** @@ -128,21 +129,29 @@ public class PoolablePreparedStatement<K> extends DelegatingPreparedStatement { clearBatch(); } setClosedInternal(true); - if (getConnectionInternal() != null) { - getConnectionInternal().removeTrace(this); - } + removeThisTrace(getConnectionInternal()); // The JDBC spec requires that a statement closes any open // ResultSet's when it is closed. // FIXME The PreparedStatement we're wrapping should handle this for us. // See bug 17301 for what could happen when ResultSets are closed twice. - final List<AbandonedTrace> resultSets = getTrace(); - if (resultSets != null) { - final ResultSet[] set = resultSets.toArray(new ResultSet[resultSets.size()]); - for (final ResultSet element : set) { - element.close(); + final List<AbandonedTrace> resultSetList = getTrace(); + if (resultSetList != null) { + final List<Exception> thrown = new ArrayList<>(); + final ResultSet[] resultSets = resultSetList.toArray(new ResultSet[resultSetList.size()]); + for (final ResultSet resultSet : resultSets) { + if (resultSet != null) { + try { + resultSet.close(); + } catch (Exception e) { + thrown.add(e); + } + } } clearTrace(); + if (!thrown.isEmpty()) { + throw new SQLExceptionList(thrown); + } } super.passivate(); diff --git a/java/org/apache/tomcat/dbcp/dbcp2/SQLExceptionList.java b/java/org/apache/tomcat/dbcp/dbcp2/SQLExceptionList.java new file mode 100644 index 0000000..b740ba0 --- /dev/null +++ b/java/org/apache/tomcat/dbcp/dbcp2/SQLExceptionList.java @@ -0,0 +1,51 @@ +/* + * 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.tomcat.dbcp.dbcp2; + +import java.sql.SQLException; +import java.util.List; + +/** + * A SQLException based on a list of Throwable causes. + * <p> + * The first exception in the list is used as this exception's cause and is accessible with the usual + * {@link #getCause()} while the complete list is accessible with {@link #getCauseList()}. + * </p> + * + * @since 2.7.0 + */ +public class SQLExceptionList extends SQLException { + + private static final long serialVersionUID = 1L; + private final List<? extends Throwable> causeList; + + /** + * Creates a new exception caused by a list of exceptions. + * + * @param causeList a list of cause exceptions. + */ + public SQLExceptionList(List<? extends Throwable> causeList) { + super(String.format("%,d exceptions: %s", Integer.valueOf(causeList.size()), causeList), causeList.get(0)); + this.causeList = causeList; + } + + public List<? extends Throwable> getCauseList() { + return causeList; + } + +} diff --git a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java index fe0944f..27ad570 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java @@ -86,6 +86,11 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl private static final String GET_CONNECTION_CALLED = "A PooledConnection was already requested from this source, " + "further initialization is not allowed."; + static { + // Attempt to prevent deadlocks - see DBCP - 272 + DriverManager.getDrivers(); + } + /** Description */ private String description; @@ -106,13 +111,13 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl /** Log stream. NOT USED */ private transient PrintWriter logWriter; - // PreparedStatement pool properties private boolean poolPreparedStatements; private int maxIdle = 10; private long timeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; private int numTestsPerEvictionRun = -1; private int minEvictableIdleTimeMillis = -1; + private int maxPreparedStatements = -1; /** Whether or not getConnection has been called */ @@ -121,11 +126,6 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl /** Connection properties passed to JDBC Driver */ private Properties connectionProperties; - static { - // Attempt to prevent deadlocks - see DBCP - 272 - DriverManager.getDrivers(); - } - /** * Controls access to the underlying connection */ @@ -138,6 +138,208 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl } /** + * Throws an IllegalStateException, if a PooledConnection has already been requested. + */ + private void assertInitializationAllowed() throws IllegalStateException { + if (getConnectionCalled) { + throw new IllegalStateException(GET_CONNECTION_CALLED); + } + } + + private boolean getBooleanContentString(RefAddr ra) { + return Boolean.valueOf(getStringContent(ra)).booleanValue(); + } + + /** + * Gets the connection properties passed to the JDBC driver. + * + * @return the JDBC connection properties used when creating connections. + */ + public Properties getConnectionProperties() { + return connectionProperties; + } + + /** + * Gets the value of description. This property is here for use by the code which will deploy this datasource. It is + * not used internally. + * + * @return value of description, may be null. + * @see #setDescription(String) + */ + public String getDescription() { + return description; + } + + /** + * Gets the driver class name. + * + * @return value of driver. + */ + public String getDriver() { + return driver; + } + + private int getIntegerStringContent(final RefAddr ra) { + return Integer.parseInt(getStringContent(ra)); + } + + /** + * Gets the maximum time in seconds that this data source can wait while attempting to connect to a database. NOT + * USED. + */ + @Override + public int getLoginTimeout() { + return loginTimeout; + } + + /** + * Gets the log writer for this data source. NOT USED. + */ + @Override + public PrintWriter getLogWriter() { + return logWriter; + } + + /** + * Gets the maximum number of statements that can remain idle in the pool, without extra ones being released, or + * negative for no limit. + * + * @return the value of maxIdle + */ + public int getMaxIdle() { + return this.maxIdle; + } + + /** + * Gets the maximum number of prepared statements. + * + * @return maxPrepartedStatements value + */ + public int getMaxPreparedStatements() { + return maxPreparedStatements; + } + + /** + * Gets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the + * idle object evictor (if any). + * + * @see #setMinEvictableIdleTimeMillis + * @see #setTimeBetweenEvictionRunsMillis + * @return the minimum amount of time a statement may sit idle in the pool. + */ + public int getMinEvictableIdleTimeMillis() { + return minEvictableIdleTimeMillis; + } + + /** + * Gets the number of statements to examine during each run of the idle object evictor thread (if any.) + * + * @see #setNumTestsPerEvictionRun + * @see #setTimeBetweenEvictionRunsMillis + * @return the number of statements to examine during each run of the idle object evictor thread (if any.) + */ + public int getNumTestsPerEvictionRun() { + return numTestsPerEvictionRun; + } + + /** + * Implements {@link ObjectFactory} to create an instance of this class + */ + @Override + public Object getObjectInstance(final Object refObj, final Name name, final Context context, + final Hashtable<?, ?> env) throws Exception { + // The spec says to return null if we can't create an instance + // of the reference + DriverAdapterCPDS cpds = null; + if (refObj instanceof Reference) { + final Reference ref = (Reference) refObj; + if (ref.getClassName().equals(getClass().getName())) { + RefAddr ra = ref.get("description"); + if (isNotEmpty(ra)) { + setDescription(getStringContent(ra)); + } + + ra = ref.get("driver"); + if (isNotEmpty(ra)) { + setDriver(getStringContent(ra)); + } + ra = ref.get("url"); + if (isNotEmpty(ra)) { + setUrl(getStringContent(ra)); + } + ra = ref.get(KEY_USER); + if (isNotEmpty(ra)) { + setUser(getStringContent(ra)); + } + ra = ref.get(KEY_PASSWORD); + if (isNotEmpty(ra)) { + setPassword(getStringContent(ra)); + } + + ra = ref.get("poolPreparedStatements"); + if (isNotEmpty(ra)) { + setPoolPreparedStatements(getBooleanContentString(ra)); + } + ra = ref.get("maxIdle"); + if (isNotEmpty(ra)) { + setMaxIdle(getIntegerStringContent(ra)); + } + + ra = ref.get("timeBetweenEvictionRunsMillis"); + if (isNotEmpty(ra)) { + setTimeBetweenEvictionRunsMillis(getIntegerStringContent(ra)); + } + + ra = ref.get("numTestsPerEvictionRun"); + if (isNotEmpty(ra)) { + setNumTestsPerEvictionRun(getIntegerStringContent(ra)); + } + + ra = ref.get("minEvictableIdleTimeMillis"); + if (isNotEmpty(ra)) { + setMinEvictableIdleTimeMillis(getIntegerStringContent(ra)); + } + ra = ref.get("maxPreparedStatements"); + if (isNotEmpty(ra)) { + setMaxPreparedStatements(getIntegerStringContent(ra)); + } + + ra = ref.get("accessToUnderlyingConnectionAllowed"); + if (isNotEmpty(ra)) { + setAccessToUnderlyingConnectionAllowed(getBooleanContentString(ra)); + } + + cpds = this; + } + } + return cpds; + } + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * Gets the value of password for the default user. + * + * @return value of password. + */ + public String getPassword() { + return Utils.toString(userPassword); + } + + /** + * Gets the value of password for the default user. + * + * @return value of password. + * @since 2.4.0 + */ + public char[] getPasswordCharArray() { + return userPassword; + } + + /** * Attempts to establish a database connection using the default user and password. */ @Override @@ -146,7 +348,7 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl } /** - * Attempt to establish a database connection. + * Attempts to establish a database connection. * * @param pooledUserName * name to be used for the connection @@ -208,16 +410,8 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl return pooledConnection; } - @Override - public Logger getParentLogger() throws SQLFeatureNotSupportedException { - throw new SQLFeatureNotSupportedException(); - } - - // ---------------------------------------------------------------------- - // Referenceable implementation - /** - * <CODE>Referenceable</CODE> implementation. + * Implements {@link Referenceable}. */ @Override public Reference getReference() throws NamingException { @@ -243,256 +437,110 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl return ref; } - // ---------------------------------------------------------------------- - // ObjectFactory implementation - - /** - * implements ObjectFactory to create an instance of this class - */ - @Override - public Object getObjectInstance(final Object refObj, final Name name, final Context context, - final Hashtable<?, ?> env) throws Exception { - // The spec says to return null if we can't create an instance - // of the reference - DriverAdapterCPDS cpds = null; - if (refObj instanceof Reference) { - final Reference ref = (Reference) refObj; - if (ref.getClassName().equals(getClass().getName())) { - RefAddr ra = ref.get("description"); - if (ra != null && ra.getContent() != null) { - setDescription(ra.getContent().toString()); - } - - ra = ref.get("driver"); - if (ra != null && ra.getContent() != null) { - setDriver(ra.getContent().toString()); - } - ra = ref.get("url"); - if (ra != null && ra.getContent() != null) { - setUrl(ra.getContent().toString()); - } - ra = ref.get(KEY_USER); - if (ra != null && ra.getContent() != null) { - setUser(ra.getContent().toString()); - } - ra = ref.get(KEY_PASSWORD); - if (ra != null && ra.getContent() != null) { - setPassword(ra.getContent().toString()); - } - - ra = ref.get("poolPreparedStatements"); - if (ra != null && ra.getContent() != null) { - setPoolPreparedStatements(Boolean.valueOf(ra.getContent().toString()).booleanValue()); - } - ra = ref.get("maxIdle"); - if (ra != null && ra.getContent() != null) { - setMaxIdle(Integer.parseInt(ra.getContent().toString())); - } - - ra = ref.get("timeBetweenEvictionRunsMillis"); - if (ra != null && ra.getContent() != null) { - setTimeBetweenEvictionRunsMillis(Integer.parseInt(ra.getContent().toString())); - } - - ra = ref.get("numTestsPerEvictionRun"); - if (ra != null && ra.getContent() != null) { - setNumTestsPerEvictionRun(Integer.parseInt(ra.getContent().toString())); - } - - ra = ref.get("minEvictableIdleTimeMillis"); - if (ra != null && ra.getContent() != null) { - setMinEvictableIdleTimeMillis(Integer.parseInt(ra.getContent().toString())); - } - ra = ref.get("maxPreparedStatements"); - if (ra != null && ra.getContent() != null) { - setMaxPreparedStatements(Integer.parseInt(ra.getContent().toString())); - } - - ra = ref.get("accessToUnderlyingConnectionAllowed"); - if (ra != null && ra.getContent() != null) { - setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(ra.getContent().toString()).booleanValue()); - } - - cpds = this; - } - } - return cpds; - } - - /** - * Throws an IllegalStateException, if a PooledConnection has already been requested. - */ - private void assertInitializationAllowed() throws IllegalStateException { - if (getConnectionCalled) { - throw new IllegalStateException(GET_CONNECTION_CALLED); - } + private String getStringContent(RefAddr ra) { + return ra.getContent().toString(); } - // ---------------------------------------------------------------------- - // Properties - /** - * Gets the connection properties passed to the JDBC driver. - * - * @return the JDBC connection properties used when creating connections. - */ - public Properties getConnectionProperties() { - return connectionProperties; - } - - /** - * <p> - * Sets the connection properties passed to the JDBC driver. - * </p> - * - * <p> - * If <code>props</code> contains "user" and/or "password" properties, the corresponding instance properties are - * set. If these properties are not present, they are filled in using {@link #getUser()}, {@link #getPassword()} - * when {@link #getPooledConnection()} is called, or using the actual parameters to the method call when - * {@link #getPooledConnection(String, String)} is called. Calls to {@link #setUser(String)} or - * {@link #setPassword(String)} overwrite the values of these properties if <code>connectionProperties</code> is not - * null. - * </p> - * - * @param props - * Connection properties to use when creating new connections. - * @throws IllegalStateException - * if {@link #getPooledConnection()} has been called - */ - public void setConnectionProperties(final Properties props) { - assertInitializationAllowed(); - connectionProperties = props; - if (connectionProperties != null) { - if (connectionProperties.containsKey(KEY_USER)) { - setUser(connectionProperties.getProperty(KEY_USER)); - } - if (connectionProperties.containsKey(KEY_PASSWORD)) { - setPassword(connectionProperties.getProperty(KEY_PASSWORD)); - } - } - } - - /** - * Gets the value of description. This property is here for use by the code which will deploy this datasource. It is - * not used internally. - * - * @return value of description, may be null. - * @see #setDescription(String) - */ - public String getDescription() { - return description; - } - - /** - * Sets the value of description. This property is here for use by the code which will deploy this datasource. It is - * not used internally. - * - * @param v - * Value to assign to description. - */ - public void setDescription(final String v) { - this.description = v; - } - - /** - * Gets the value of password for the default user. - * - * @return value of password. - * @since 2.4.0 - */ - public char[] getPasswordCharArray() { - return userPassword; - } - - /** - * Gets the value of password for the default user. + * Gets the number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no + * idle object evictor thread will be run. * - * @return value of password. + * @return the value of the evictor thread timer + * @see #setTimeBetweenEvictionRunsMillis(long) */ - public String getPassword() { - return Utils.toString(userPassword); + public long getTimeBetweenEvictionRunsMillis() { + return timeBetweenEvictionRunsMillis; } /** - * Sets the value of password for the default user. + * Gets the value of url used to locate the database for this datasource. * - * @param userPassword - * Value to assign to password. - * @throws IllegalStateException - * if {@link #getPooledConnection()} has been called + * @return value of url. */ - public void setPassword(final char[] userPassword) { - assertInitializationAllowed(); - this.userPassword = Utils.clone(userPassword); - update(connectionProperties, KEY_PASSWORD, Utils.toString(this.userPassword)); + public String getUrl() { + return url; } /** - * Sets the value of password for the default user. + * Gets the value of default user (login or user name). * - * @param userPassword - * Value to assign to password. - * @throws IllegalStateException - * if {@link #getPooledConnection()} has been called + * @return value of user. */ - public void setPassword(final String userPassword) { - assertInitializationAllowed(); - this.userPassword = Utils.toCharArray(userPassword); - update(connectionProperties, KEY_PASSWORD, userPassword); + public String getUser() { + return userName; } /** - * Gets the value of url used to locate the database for this datasource. + * Returns the value of the accessToUnderlyingConnectionAllowed property. * - * @return value of url. + * @return true if access to the underlying is allowed, false otherwise. */ - public String getUrl() { - return url; + public synchronized boolean isAccessToUnderlyingConnectionAllowed() { + return this.accessToUnderlyingConnectionAllowed; + } + + private boolean isNotEmpty(RefAddr ra) { + return ra != null && ra.getContent() != null; } /** - * Sets the value of URL string used to locate the database for this datasource. + * Whether to toggle the pooling of <code>PreparedStatement</code>s * - * @param v - * Value to assign to url. - * @throws IllegalStateException - * if {@link #getPooledConnection()} has been called + * @return value of poolPreparedStatements. */ - public void setUrl(final String v) { - assertInitializationAllowed(); - this.url = v; + public boolean isPoolPreparedStatements() { + return poolPreparedStatements; } /** - * Gets the value of default user (login or user name). + * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to + * the underlying connection. (Default: false) * - * @return value of user. + * @param allow + * Access to the underlying connection is granted when true. */ - public String getUser() { - return userName; + public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) { + this.accessToUnderlyingConnectionAllowed = allow; } /** - * Sets the value of default user (login or user name). + * Sets the connection properties passed to the JDBC driver. + * <p> + * If <code>props</code> contains "user" and/or "password" properties, the corresponding instance properties are + * set. If these properties are not present, they are filled in using {@link #getUser()}, {@link #getPassword()} + * when {@link #getPooledConnection()} is called, or using the actual parameters to the method call when + * {@link #getPooledConnection(String, String)} is called. Calls to {@link #setUser(String)} or + * {@link #setPassword(String)} overwrite the values of these properties if <code>connectionProperties</code> is not + * null. + * </p> * - * @param v - * Value to assign to user. + * @param props + * Connection properties to use when creating new connections. * @throws IllegalStateException * if {@link #getPooledConnection()} has been called */ - public void setUser(final String v) { + public void setConnectionProperties(final Properties props) { assertInitializationAllowed(); - this.userName = v; - update(connectionProperties, KEY_USER, v); + connectionProperties = props; + if (connectionProperties != null) { + if (connectionProperties.containsKey(KEY_USER)) { + setUser(connectionProperties.getProperty(KEY_USER)); + } + if (connectionProperties.containsKey(KEY_PASSWORD)) { + setPassword(connectionProperties.getProperty(KEY_PASSWORD)); + } + } } /** - * Gets the driver class name. + * Sets the value of description. This property is here for use by the code which will deploy this datasource. It is + * not used internally. * - * @return value of driver. + * @param v + * Value to assign to description. */ - public String getDriver() { - return driver; + public void setDescription(final String v) { + this.description = v; } /** @@ -514,23 +562,6 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl } /** - * Gets the maximum time in seconds that this data source can wait while attempting to connect to a database. NOT - * USED. - */ - @Override - public int getLoginTimeout() { - return loginTimeout; - } - - /** - * Gets the log writer for this data source. NOT USED. - */ - @Override - public PrintWriter getLogWriter() { - return logWriter; - } - - /** * Sets the maximum time in seconds that this data source will wait while attempting to connect to a database. NOT * USED. */ @@ -547,41 +578,6 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl logWriter = out; } - // ------------------------------------------------------------------ - // PreparedStatement pool properties - - /** - * Flag to toggle the pooling of <code>PreparedStatement</code>s - * - * @return value of poolPreparedStatements. - */ - public boolean isPoolPreparedStatements() { - return poolPreparedStatements; - } - - /** - * Flag to toggle the pooling of <code>PreparedStatement</code>s - * - * @param poolPreparedStatements - * true to pool statements. - * @throws IllegalStateException - * if {@link #getPooledConnection()} has been called - */ - public void setPoolPreparedStatements(final boolean poolPreparedStatements) { - assertInitializationAllowed(); - this.poolPreparedStatements = poolPreparedStatements; - } - - /** - * Gets the maximum number of statements that can remain idle in the pool, without extra ones being released, or - * negative for no limit. - * - * @return the value of maxIdle - */ - public int getMaxIdle() { - return this.maxIdle; - } - /** * Gets the maximum number of statements that can remain idle in the pool, without extra ones being released, or * negative for no limit. @@ -597,41 +593,29 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl } /** - * Gets the number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no - * idle object evictor thread will be run. + * Sets the maximum number of prepared statements. * - * @return the value of the evictor thread timer - * @see #setTimeBetweenEvictionRunsMillis(long) + * @param maxPreparedStatements + * the new maximum number of prepared statements */ - public long getTimeBetweenEvictionRunsMillis() { - return timeBetweenEvictionRunsMillis; + public void setMaxPreparedStatements(final int maxPreparedStatements) { + this.maxPreparedStatements = maxPreparedStatements; } /** - * Sets the number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no - * idle object evictor thread will be run. + * Sets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the + * idle object evictor (if any). When non-positive, no objects will be evicted from the pool due to idle time alone. * - * @param timeBetweenEvictionRunsMillis - * The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, - * no idle object evictor thread will be run. - * @see #getTimeBetweenEvictionRunsMillis() + * @param minEvictableIdleTimeMillis + * minimum time to set (in ms) + * @see #getMinEvictableIdleTimeMillis() + * @see #setTimeBetweenEvictionRunsMillis(long) * @throws IllegalStateException * if {@link #getPooledConnection()} has been called */ - public void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) { + public void setMinEvictableIdleTimeMillis(final int minEvictableIdleTimeMillis) { assertInitializationAllowed(); - this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; - } - - /** - * Gets the number of statements to examine during each run of the idle object evictor thread (if any.) - * - * @see #setNumTestsPerEvictionRun - * @see #setTimeBetweenEvictionRunsMillis - * @return the number of statements to examine during each run of the idle object evictor thread (if any.) - */ - public int getNumTestsPerEvictionRun() { - return numTestsPerEvictionRun; + this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; } /** @@ -655,80 +639,87 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl } /** - * Gets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the - * idle object evictor (if any). + * Sets the value of password for the default user. * - * @see #setMinEvictableIdleTimeMillis - * @see #setTimeBetweenEvictionRunsMillis - * @return the minimum amount of time a statement may sit idle in the pool. + * @param userPassword + * Value to assign to password. + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called */ - public int getMinEvictableIdleTimeMillis() { - return minEvictableIdleTimeMillis; + public void setPassword(final char[] userPassword) { + assertInitializationAllowed(); + this.userPassword = Utils.clone(userPassword); + update(connectionProperties, KEY_PASSWORD, Utils.toString(this.userPassword)); } /** - * Sets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the - * idle object evictor (if any). When non-positive, no objects will be evicted from the pool due to idle time alone. + * Sets the value of password for the default user. * - * @param minEvictableIdleTimeMillis - * minimum time to set (in ms) - * @see #getMinEvictableIdleTimeMillis() - * @see #setTimeBetweenEvictionRunsMillis(long) + * @param userPassword + * Value to assign to password. * @throws IllegalStateException * if {@link #getPooledConnection()} has been called */ - public void setMinEvictableIdleTimeMillis(final int minEvictableIdleTimeMillis) { + public void setPassword(final String userPassword) { assertInitializationAllowed(); - this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; + this.userPassword = Utils.toCharArray(userPassword); + update(connectionProperties, KEY_PASSWORD, userPassword); } /** - * Returns the value of the accessToUnderlyingConnectionAllowed property. + * Whether to toggle the pooling of <code>PreparedStatement</code>s * - * @return true if access to the underlying is allowed, false otherwise. + * @param poolPreparedStatements + * true to pool statements. + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called */ - public synchronized boolean isAccessToUnderlyingConnectionAllowed() { - return this.accessToUnderlyingConnectionAllowed; + public void setPoolPreparedStatements(final boolean poolPreparedStatements) { + assertInitializationAllowed(); + this.poolPreparedStatements = poolPreparedStatements; } /** - * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to - * the underlying connection. (Default: false) + * Sets the number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no + * idle object evictor thread will be run. * - * @param allow - * Access to the underlying connection is granted when true. + * @param timeBetweenEvictionRunsMillis + * The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, + * no idle object evictor thread will be run. + * @see #getTimeBetweenEvictionRunsMillis() + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called */ - public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) { - this.accessToUnderlyingConnectionAllowed = allow; + public void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) { + assertInitializationAllowed(); + this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; } /** - * Gets the maximum number of prepared statements. + * Sets the value of URL string used to locate the database for this datasource. * - * @return maxPrepartedStatements value + * @param v + * Value to assign to url. + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called */ - public int getMaxPreparedStatements() { - return maxPreparedStatements; + public void setUrl(final String v) { + assertInitializationAllowed(); + this.url = v; } /** - * Sets the maximum number of prepared statements. + * Sets the value of default user (login or user name). * - * @param maxPreparedStatements - * the new maximum number of prepared statements + * @param v + * Value to assign to user. + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called */ - public void setMaxPreparedStatements(final int maxPreparedStatements) { - this.maxPreparedStatements = maxPreparedStatements; - } - - private void update(final Properties properties, final String key, final String value) { - if (properties != null) { - if (value == null) { - properties.remove(key); - } else { - properties.setProperty(key, value); - } - } + public void setUser(final String v) { + assertInitializationAllowed(); + this.userName = v; + update(connectionProperties, KEY_USER, v); } /** @@ -765,7 +756,7 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl builder.append(", connectionProperties="); Properties tmpProps = connectionProperties; final String pwdKey = "password"; - if (connectionProperties.contains(pwdKey)) { + if (connectionProperties != null && connectionProperties.contains(pwdKey)) { tmpProps = (Properties) connectionProperties.clone(); tmpProps.remove(pwdKey); } @@ -775,4 +766,14 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl builder.append("]"); return builder.toString(); } + + private void update(final Properties properties, final String key, final String value) { + if (properties != null && key != null) { + if (value == null) { + properties.remove(key); + } else { + properties.setProperty(key, value); + } + } + } } diff --git a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java index 046ce99..6d2456b 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java @@ -181,6 +181,10 @@ class PooledConnectionImpl /** * Creates a {@link PStmtKey} for the given arguments. + * + * @param sql + * The SQL statement. + * @return a {@link PStmtKey} for the given arguments. */ protected PStmtKey createKey(final String sql) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull()); @@ -188,6 +192,13 @@ class PooledConnectionImpl /** * Creates a {@link PStmtKey} for the given arguments. + * + * @param sql + * The SQL statement. + * @param autoGeneratedKeys + * A flag indicating whether auto-generated keys should be returned; one of + * <code>Statement.RETURN_GENERATED_KEYS</code> or <code>Statement.NO_GENERATED_KEYS</code>. + * @return a key to uniquely identify a prepared statement. */ protected PStmtKey createKey(final String sql, final int autoGeneratedKeys) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), autoGeneratedKeys); @@ -195,6 +206,13 @@ class PooledConnectionImpl /** * Creates a {@link PStmtKey} for the given arguments. + * + * @param sql + * The SQL statement. + * @param columnIndexes + * An array of column indexes indicating the columns that should be returned from the inserted row or + * rows. + * @return a key to uniquely identify a prepared statement. */ protected PStmtKey createKey(final String sql, final int columnIndexes[]) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), columnIndexes); @@ -202,6 +220,16 @@ class PooledConnectionImpl /** * Creates a {@link PStmtKey} for the given arguments. + * + * @param sql + * The SQL statement. + * @param resultSetType + * A result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>. + * @param resultSetConcurrency + * A concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or + * <code>ResultSet.CONCUR_UPDATABLE</code>. + * @return a key to uniquely identify a prepared statement. */ protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), resultSetType, @@ -210,6 +238,19 @@ class PooledConnectionImpl /** * Creates a {@link PStmtKey} for the given arguments. + * + * @param sql + * The SQL statement. + * @param resultSetType + * a result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>. + * @param resultSetConcurrency + * A concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or + * <code>ResultSet.CONCUR_UPDATABLE</code> + * @param resultSetHoldability + * One of the following <code>ResultSet</code> constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> + * or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>. + * @return a key to uniquely identify a prepared statement. */ protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) { @@ -220,6 +261,20 @@ class PooledConnectionImpl /** * Creates a {@link PStmtKey} for the given arguments. * + * @param sql + * The SQL statement. + * @param resultSetType + * a result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> + * @param resultSetConcurrency + * A concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or + * <code>ResultSet.CONCUR_UPDATABLE</code>. + * @param resultSetHoldability + * One of the following <code>ResultSet</code> constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> + * or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>. + * @param statementType + * The SQL statement type, prepared or callable. + * @return a key to uniquely identify a prepared statement. * @since 2.4.0 */ protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency, @@ -231,6 +286,17 @@ class PooledConnectionImpl /** * Creates a {@link PStmtKey} for the given arguments. * + * @param sql + * The SQL statement. + * @param resultSetType + * A result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>. + * @param resultSetConcurrency + * A concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or + * <code>ResultSet.CONCUR_UPDATABLE</code>. + * @param statementType + * The SQL statement type, prepared or callable. + * @return a key to uniquely identify a prepared statement. * @since 2.4.0 */ protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency, @@ -241,6 +307,12 @@ class PooledConnectionImpl /** * Creates a {@link PStmtKey} for the given arguments. + * + * @param sql + * The SQL statement. + * @param statementType + * The SQL statement type, prepared or callable. + * @return a key to uniquely identify a prepared statement. */ protected PStmtKey createKey(final String sql, final StatementType statementType) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), statementType); @@ -248,6 +320,12 @@ class PooledConnectionImpl /** * Creates a {@link PStmtKey} for the given arguments. + * + * @param sql + * The SQL statement. + * @param columnNames + * An array of column names indicating the columns that should be returned from the inserted row or rows. + * @return a key to uniquely identify a prepared statement. */ protected PStmtKey createKey(final String sql, final String columnNames[]) { return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), columnNames); @@ -361,6 +439,9 @@ class PooledConnectionImpl /** * Normalizes the given SQL statement, producing a canonical form that is semantically equivalent to the original. + * @param sql + * The SQL statement. + * @return the normalized SQL statement. */ protected String normalizeSQL(final String sql) { return sql.trim(); diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java index a0fe1b4..e50e34d 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java @@ -98,7 +98,7 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable /** Description */ private String description; - /** Environment that may be used to set up a jndi initial context. */ + /** Environment that may be used to set up a JNDI initial context. */ private Properties jndiEnvironment; /** Login TimeOut in seconds */ @@ -146,6 +146,8 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable /** * Throws an IllegalStateException, if a PooledConnection has already been requested. + * + * @throws IllegalStateException Thrown if a PooledConnection has already been requested. */ protected void assertInitializationAllowed() throws IllegalStateException { if (getConnectionCalled) { @@ -520,8 +522,8 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable } /** - * Gets the value of connectionPoolDataSource. This method will return null, if the backing datasource is being - * accessed via jndi. + * Gets the value of connectionPoolDataSource. This method will return null, if the backing data source is being + * accessed via JNDI. * * @return value of connectionPoolDataSource. */ @@ -530,8 +532,8 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable } /** - * Sets the backend ConnectionPoolDataSource. This property should not be set if using jndi to access the - * datasource. + * Sets the backend ConnectionPoolDataSource. This property should not be set if using JNDI to access the + * data source. * * @param v * Value to assign to connectionPoolDataSource. @@ -549,8 +551,8 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable } /** - * Gets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the datasource - * from a jndi service provider. + * Gets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source + * from a JNDI service provider. * * @return value of dataSourceName. */ @@ -559,8 +561,8 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable } /** - * Sets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the datasource - * from a jndi service provider. + * Sets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source + * from a JNDI service provider. * * @param v * Value to assign to dataSourceName. diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java index eb0c8a9..c471d53 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java @@ -120,7 +120,7 @@ abstract class InstanceKeyDataSourceFactory implements ObjectFactory { if (isCorrectClass(ref.getClassName())) { final RefAddr refAddr = ref.get("instanceKey"); if (refAddr != null && refAddr.getContent() != null) { - // object was bound to jndi via Referenceable api. + // object was bound to JNDI via Referenceable API. obj = instanceMap.get(refAddr.getContent()); } else { // Tomcat JNDI creates a Reference out of server.xml diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 0591676..2393a89 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -221,6 +221,10 @@ Update the internal fork of Commons Pool2 to 796e32d (2018-08-01) to pick up the changes Commons Pool2 2.7.0. (markt) </update> + <update> + Update the internal fork of Commons DBCP2 to 87d9e3a (2018-08-01) to + pick up the changes Commons DBCP2 2.7.0 RC1. (markt) + </update> </changelog> </subsection> </section> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org