Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java Tue Jan 29 15:03:15 2019 @@ -46,6 +46,53 @@ public class PoolableConnectionFactory i private static final Log log = LogFactory.getLog(PoolableConnectionFactory.class); /** + * Internal constant to indicate the level is not set. + */ + static final int UNKNOWN_TRANSACTION_ISOLATION = -1; + + private final ConnectionFactory connectionFactory; + + private final ObjectName dataSourceJmxObjectName; + + private volatile String validationQuery; + + private volatile int validationQueryTimeoutSeconds = -1; + + private Collection<String> connectionInitSqls; + + private Collection<String> disconnectionSqlCodes; + + private boolean fastFailValidation = true; + + private volatile ObjectPool<PoolableConnection> pool; + + private Boolean defaultReadOnly; + + private Boolean defaultAutoCommit; + + private boolean autoCommitOnReturn = true; + + private boolean rollbackOnReturn = true; + + private int defaultTransactionIsolation = UNKNOWN_TRANSACTION_ISOLATION; + + private String defaultCatalog; + + private String defaultSchema; + + private boolean cacheState; + + private boolean poolStatements; + + private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY; + + private long maxConnLifetimeMillis = -1; + + private final AtomicLong connectionIndex = new AtomicLong(0); + + private Integer defaultQueryTimeoutSeconds; + + /** * Creates a new {@code PoolableConnectionFactory}. * * @param connFactory @@ -58,179 +105,135 @@ public class PoolableConnectionFactory i this.dataSourceJmxObjectName = dataSourceJmxObjectName; } - /** - * Sets the query I use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. If - * not specified, {@link Connection#isValid(int)} will be used to validate connections. - * - * @param validationQuery - * a query to use to {@link #validateObject validate} {@link Connection}s. - */ - public void setValidationQuery(final String validationQuery) { - this.validationQuery = validationQuery; + @Override + public void activateObject(final PooledObject<PoolableConnection> p) throws Exception { + + validateLifetime(p); + + final PoolableConnection conn = p.getObject(); + conn.activate(); + + if (defaultAutoCommit != null && conn.getAutoCommit() != defaultAutoCommit.booleanValue()) { + conn.setAutoCommit(defaultAutoCommit.booleanValue()); + } + if (defaultTransactionIsolation != UNKNOWN_TRANSACTION_ISOLATION + && conn.getTransactionIsolation() != defaultTransactionIsolation) { + conn.setTransactionIsolation(defaultTransactionIsolation); + } + if (defaultReadOnly != null && conn.isReadOnly() != defaultReadOnly.booleanValue()) { + conn.setReadOnly(defaultReadOnly.booleanValue()); + } + if (defaultCatalog != null && !defaultCatalog.equals(conn.getCatalog())) { + conn.setCatalog(defaultCatalog); + } + if (defaultSchema != null && !defaultSchema.equals(Jdbc41Bridge.getSchema(conn))) { + Jdbc41Bridge.setSchema(conn, defaultSchema); + } + conn.setDefaultQueryTimeout(defaultQueryTimeoutSeconds); } - /** - * Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a - * response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout. - * - * @param validationQueryTimeoutSeconds - * new validation query timeout value in seconds - */ - public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) { - this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds; + @Override + public void destroyObject(final PooledObject<PoolableConnection> p) throws Exception { + p.getObject().reallyClose(); } /** - * Sets the SQL statements I use to initialize newly created {@link Connection}s. Using {@code null} turns off - * connection initialization. - * - * @param connectionInitSqls - * SQL statement to initialize {@link Connection}s. + * @return The cache state. + * @since Made public in 2.6.0. */ - public void setConnectionInitSql(final Collection<String> connectionInitSqls) { - this.connectionInitSqls = connectionInitSqls; + public boolean getCacheState() { + return cacheState; } /** - * Sets the {@link ObjectPool} in which to pool {@link Connection}s. - * - * @param pool - * the {@link ObjectPool} in which to pool those {@link Connection}s + * @return The connection factory. + * @since Made public in 2.6.0. */ - public synchronized void setPool(final ObjectPool<PoolableConnection> pool) { - if (null != this.pool && pool != this.pool) { - try { - this.pool.close(); - } catch (final Exception e) { - // ignored !?! - } - } - this.pool = pool; + public ConnectionFactory getConnectionFactory() { + return connectionFactory; } - /** - * Returns the {@link ObjectPool} in which {@link Connection}s are pooled. - * - * @return the connection pool - */ - public synchronized ObjectPool<PoolableConnection> getPool() { - return pool; + protected AtomicLong getConnectionIndex() { + return connectionIndex; } /** - * Sets the default "read only" setting for borrowed {@link Connection}s - * - * @param defaultReadOnly - * the default "read only" setting for borrowed {@link Connection}s + * @return The collection of initialization SQL statements. + * @since 2.6.0 */ - public void setDefaultReadOnly(final Boolean defaultReadOnly) { - this.defaultReadOnly = defaultReadOnly; + public Collection<String> getConnectionInitSqls() { + return connectionInitSqls; } /** - * Sets the default "auto commit" setting for borrowed {@link Connection}s - * - * @param defaultAutoCommit - * the default "auto commit" setting for borrowed {@link Connection}s + * @return The data source JMX ObjectName + * @since Made public in 2.6.0. */ - public void setDefaultAutoCommit(final Boolean defaultAutoCommit) { - this.defaultAutoCommit = defaultAutoCommit; + public ObjectName getDataSourceJmxName() { + return dataSourceJmxObjectName; } /** - * Sets the default "Transaction Isolation" setting for borrowed {@link Connection}s - * - * @param defaultTransactionIsolation - * the default "Transaction Isolation" setting for returned {@link Connection}s + * @return The data source JMS ObjectName. + * @since 2.6.0 */ - public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) { - this.defaultTransactionIsolation = defaultTransactionIsolation; + public ObjectName getDataSourceJmxObjectName() { + return dataSourceJmxObjectName; } /** - * Sets the default "catalog" setting for borrowed {@link Connection}s - * - * @param defaultCatalog - * the default "catalog" setting for borrowed {@link Connection}s + * @return Default auto-commit value. + * @since 2.6.0 */ - public void setDefaultCatalog(final String defaultCatalog) { - this.defaultCatalog = defaultCatalog; + public Boolean getDefaultAutoCommit() { + return defaultAutoCommit; } /** - * Sets the default "schema" setting for borrowed {@link Connection}s - * - * @param defaultSchema - * the default "schema" setting for borrowed {@link Connection}s - * @since 2.5.0 + * @return Default catalog. + * @since 2.6.0 */ - public void setDefaultSchema(final String defaultSchema) { - this.defaultSchema = defaultSchema; - } - - public void setCacheState(final boolean cacheState) { - this.cacheState = cacheState; - } - - public void setPoolStatements(final boolean poolStatements) { - this.poolStatements = poolStatements; + public String getDefaultCatalog() { + return defaultCatalog; } /** - * Deprecated due to typo in method name. - * - * @param maxOpenPreparedStatements - * The maximum number of open prepared statements. - * @deprecated Use {@link #setMaxOpenPreparedStatements(int)}. + * @return Default query timeout in seconds. */ - @Deprecated // Due to typo in method name. - public void setMaxOpenPrepatedStatements(final int maxOpenPreparedStatements) { - setMaxOpenPreparedStatements(maxOpenPreparedStatements); + public Integer getDefaultQueryTimeout() { + return defaultQueryTimeoutSeconds; } /** - * Sets the maximum number of open prepared statements. - * - * @param maxOpenPreparedStatements - * The maximum number of open prepared statements. + * @return Default query timeout in seconds. + * @since 2.6.0 */ - public void setMaxOpenPreparedStatements(final int maxOpenPreparedStatements) { - this.maxOpenPreparedStatements = maxOpenPreparedStatements; + public Integer getDefaultQueryTimeoutSeconds() { + return defaultQueryTimeoutSeconds; } /** - * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation, - * passivation and validation. A value of zero or less indicates an infinite lifetime. The default value is -1. - * - * @param maxConnLifetimeMillis - * The maximum lifetime in milliseconds. + * @return Default read-only-value. + * @since 2.6.0 */ - public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) { - this.maxConnLifetimeMillis = maxConnLifetimeMillis; - } - - public boolean isEnableAutoCommitOnReturn() { - return enableAutoCommitOnReturn; - } - - public void setEnableAutoCommitOnReturn(final boolean enableAutoCommitOnReturn) { - this.enableAutoCommitOnReturn = enableAutoCommitOnReturn; - } - - public boolean isRollbackOnReturn() { - return rollbackOnReturn; + public Boolean getDefaultReadOnly() { + return defaultReadOnly; } - public void setRollbackOnReturn(final boolean rollbackOnReturn) { - this.rollbackOnReturn = rollbackOnReturn; - } - - public Integer getDefaultQueryTimeout() { - return defaultQueryTimeoutSeconds; + /** + * @return Default schema. + * @since 2.6.0 + */ + public String getDefaultSchema() { + return defaultSchema; } - public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) { - this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds; + /** + * @return Default transaction isolation. + * @since 2.6.0 + */ + public int getDefaultTransactionIsolation() { + return defaultTransactionIsolation; } /** @@ -254,51 +257,112 @@ public class PoolableConnectionFactory i } /** - * @param disconnectionSqlCodes - * The disconnection SQL codes. - * @see #getDisconnectionSqlCodes() - * @since 2.1 + * @return Maximum connection lifetime in milliseconds. + * @since 2.6.0 */ - public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) { - this.disconnectionSqlCodes = disconnectionSqlCodes; + public long getMaxConnLifetimeMillis() { + return maxConnLifetimeMillis; + } + + protected int getMaxOpenPreparedStatements() { + return maxOpenPreparedStatements; } /** - * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with - * SQL_STATE indicating fatal disconnection errors. + * Returns the {@link ObjectPool} in which {@link Connection}s are pooled. * - * @return true if connections created by this factory will fast fail validation. - * @see #setDisconnectionSqlCodes(Collection) - * @since 2.1 - * @since 2.5.0 Defaults to true, previous versions defaulted to false. + * @return the connection pool */ - public boolean isFastFailValidation() { - return fastFailValidation; + public synchronized ObjectPool<PoolableConnection> getPool() { + return pool; } /** - * @see #isFastFailValidation() - * @param fastFailValidation - * true means connections created by this factory will fast fail validation - * @since 2.1 + * @return Whether to pool statements. + * @since Made public in 2.6.0. */ - public void setFastFailValidation(final boolean fastFailValidation) { - this.fastFailValidation = fastFailValidation; + public boolean getPoolStatements() { + return poolStatements; } - - @Override - public PooledObject<PoolableConnection> makeObject() throws Exception { - Connection conn = connectionFactory.createConnection(); - if (conn == null) { - throw new IllegalStateException("Connection factory returned null from createConnection"); + /** + * @return Validation query. + * @since 2.6.0 + */ + public String getValidationQuery() { + return validationQuery; + } + /** + * @return Validation query timeout in seconds. + * @since 2.6.0 + */ + public int getValidationQueryTimeoutSeconds() { + return validationQueryTimeoutSeconds; + } + protected void initializeConnection(final Connection conn) throws SQLException { + final Collection<String> sqls = connectionInitSqls; + if (conn.isClosed()) { + throw new SQLException("initializeConnection: connection closed"); } - try { - initializeConnection(conn); - } catch (final SQLException sqle) { - // Make sure the connection is closed - try { - conn.close(); - } catch (final SQLException ignore) { + if (null != sqls) { + try (Statement stmt = conn.createStatement()) { + for (final String sql : sqls) { + Objects.requireNonNull(sql, "null connectionInitSqls element"); + stmt.execute(sql); + } + } + } + } + + /** + * @return Whether to auto-commit on return. + * @since 2.6.0 + */ + public boolean isAutoCommitOnReturn() { + return autoCommitOnReturn; + } + + /** + * @return Whether to auto-commit on return. + * @deprecated Use {@link #isAutoCommitOnReturn()}. + */ + @Deprecated + public boolean isEnableAutoCommitOnReturn() { + return autoCommitOnReturn; + } + + /** + * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with + * SQL_STATE indicating fatal disconnection errors. + * + * @return true if connections created by this factory will fast fail validation. + * @see #setDisconnectionSqlCodes(Collection) + * @since 2.1 + * @since 2.5.0 Defaults to true, previous versions defaulted to false. + */ + public boolean isFastFailValidation() { + return fastFailValidation; + } + + /** + * @return Whether to rollback on return. + */ + public boolean isRollbackOnReturn() { + return rollbackOnReturn; + } + + @Override + public PooledObject<PoolableConnection> makeObject() throws Exception { + Connection conn = connectionFactory.createConnection(); + if (conn == null) { + throw new IllegalStateException("Connection factory returned null from createConnection"); + } + try { + initializeConnection(conn); + } catch (final SQLException sqle) { + // Make sure the connection is closed + try { + conn.close(); + } catch (final SQLException ignore) { // ignore } // Rethrow original exception so it is visible to caller @@ -347,48 +411,6 @@ public class PoolableConnectionFactory i return new DefaultPooledObject<>(pc); } - protected void initializeConnection(final Connection conn) throws SQLException { - final Collection<String> sqls = connectionInitSqls; - if (conn.isClosed()) { - throw new SQLException("initializeConnection: connection closed"); - } - if (null != sqls) { - try (Statement stmt = conn.createStatement()) { - for (final String sql : sqls) { - Objects.requireNonNull(sql, "null connectionInitSqls element"); - stmt.execute(sql); - } - } - } - } - - @Override - public void destroyObject(final PooledObject<PoolableConnection> p) throws Exception { - p.getObject().reallyClose(); - } - - @Override - public boolean validateObject(final PooledObject<PoolableConnection> p) { - try { - validateLifetime(p); - - validateConnection(p.getObject()); - return true; - } catch (final Exception e) { - if (log.isDebugEnabled()) { - log.debug(Utils.getMessage("poolableConnectionFactory.validateObject.fail"), e); - } - return false; - } - } - - public void validateConnection(final PoolableConnection conn) throws SQLException { - if (conn.isClosed()) { - throw new SQLException("validateConnection: connection closed"); - } - conn.validate(validationQuery, validationQueryTimeoutSeconds); - } - @Override public void passivateObject(final PooledObject<PoolableConnection> p) throws Exception { @@ -407,7 +429,7 @@ public class PoolableConnectionFactory i // DBCP-97 / DBCP-399 / DBCP-351 Idle connections in the pool should // have autoCommit enabled - if (enableAutoCommitOnReturn) { + if (autoCommitOnReturn) { if (connAutoCommit == null) { connAutoCommit = Boolean.valueOf(conn.getAutoCommit()); } @@ -419,91 +441,217 @@ public class PoolableConnectionFactory i conn.passivate(); } - @Override - public void activateObject(final PooledObject<PoolableConnection> p) throws Exception { + public void setAutoCommitOnReturn(final boolean autoCommitOnReturn) { + this.autoCommitOnReturn = autoCommitOnReturn; + } - validateLifetime(p); + public void setCacheState(final boolean cacheState) { + this.cacheState = cacheState; + } - final PoolableConnection conn = p.getObject(); - conn.activate(); + /** + * Sets the SQL statements I use to initialize newly created {@link Connection}s. Using {@code null} turns off + * connection initialization. + * + * @param connectionInitSqls + * SQL statement to initialize {@link Connection}s. + */ + public void setConnectionInitSql(final Collection<String> connectionInitSqls) { + this.connectionInitSqls = connectionInitSqls; + } - if (defaultAutoCommit != null && conn.getAutoCommit() != defaultAutoCommit.booleanValue()) { - conn.setAutoCommit(defaultAutoCommit.booleanValue()); - } - if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION - && conn.getTransactionIsolation() != defaultTransactionIsolation) { - conn.setTransactionIsolation(defaultTransactionIsolation); - } - if (defaultReadOnly != null && conn.isReadOnly() != defaultReadOnly.booleanValue()) { - conn.setReadOnly(defaultReadOnly.booleanValue()); - } - if (defaultCatalog != null && !defaultCatalog.equals(conn.getCatalog())) { - conn.setCatalog(defaultCatalog); - } - if (defaultSchema != null && !defaultSchema.equals(conn.getSchema())) { - conn.setSchema(defaultSchema); - } - conn.setDefaultQueryTimeout(defaultQueryTimeoutSeconds); + /** + * Sets the default "auto commit" setting for borrowed {@link Connection}s + * + * @param defaultAutoCommit + * the default "auto commit" setting for borrowed {@link Connection}s + */ + public void setDefaultAutoCommit(final Boolean defaultAutoCommit) { + this.defaultAutoCommit = defaultAutoCommit; } - private void validateLifetime(final PooledObject<PoolableConnection> p) throws Exception { - if (maxConnLifetimeMillis > 0) { - final long lifetime = System.currentTimeMillis() - p.getCreateTime(); - if (lifetime > maxConnLifetimeMillis) { - throw new LifetimeExceededException(Utils.getMessage("connectionFactory.lifetimeExceeded", - Long.valueOf(lifetime), Long.valueOf(maxConnLifetimeMillis))); - } - } + /** + * Sets the default "catalog" setting for borrowed {@link Connection}s + * + * @param defaultCatalog + * the default "catalog" setting for borrowed {@link Connection}s + */ + public void setDefaultCatalog(final String defaultCatalog) { + this.defaultCatalog = defaultCatalog; } - protected ConnectionFactory getConnectionFactory() { - return connectionFactory; + public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) { + this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds; + } + /** + * Sets the default "read only" setting for borrowed {@link Connection}s + * + * @param defaultReadOnly + * the default "read only" setting for borrowed {@link Connection}s + */ + public void setDefaultReadOnly(final Boolean defaultReadOnly) { + this.defaultReadOnly = defaultReadOnly; } - protected boolean getPoolStatements() { - return poolStatements; + /** + * Sets the default "schema" setting for borrowed {@link Connection}s + * + * @param defaultSchema + * the default "schema" setting for borrowed {@link Connection}s + * @since 2.5.0 + */ + public void setDefaultSchema(final String defaultSchema) { + this.defaultSchema = defaultSchema; } - protected int getMaxOpenPreparedStatements() { - return maxOpenPreparedStatements; + /** + * Sets the default "Transaction Isolation" setting for borrowed {@link Connection}s + * + * @param defaultTransactionIsolation + * the default "Transaction Isolation" setting for returned {@link Connection}s + */ + public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) { + this.defaultTransactionIsolation = defaultTransactionIsolation; } - protected boolean getCacheState() { - return cacheState; + /** + * @param disconnectionSqlCodes + * The disconnection SQL codes. + * @see #getDisconnectionSqlCodes() + * @since 2.1 + */ + public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) { + this.disconnectionSqlCodes = disconnectionSqlCodes; } - protected ObjectName getDataSourceJmxName() { - return dataSourceJmxObjectName; + /** + * @param autoCommitOnReturn Whether to auto-commit on return. + * @deprecated Use {@link #setAutoCommitOnReturn(boolean)}. + */ + @Deprecated + public void setEnableAutoCommitOnReturn(final boolean autoCommitOnReturn) { + this.autoCommitOnReturn = autoCommitOnReturn; } - protected AtomicLong getConnectionIndex() { - return connectionIndex; + /** + * @see #isFastFailValidation() + * @param fastFailValidation + * true means connections created by this factory will fast fail validation + * @since 2.1 + */ + public void setFastFailValidation(final boolean fastFailValidation) { + this.fastFailValidation = fastFailValidation; } - private final ConnectionFactory connectionFactory; - private final ObjectName dataSourceJmxObjectName; - private volatile String validationQuery; - private volatile int validationQueryTimeoutSeconds = -1; - private Collection<String> connectionInitSqls; - private Collection<String> disconnectionSqlCodes; - private boolean fastFailValidation = true; - private volatile ObjectPool<PoolableConnection> pool; - private Boolean defaultReadOnly; - private Boolean defaultAutoCommit; - private boolean enableAutoCommitOnReturn = true; - private boolean rollbackOnReturn = true; - private int defaultTransactionIsolation = UNKNOWN_TRANSACTIONISOLATION; - private String defaultCatalog; - private String defaultSchema; - private boolean cacheState; - private boolean poolStatements; - private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY; - private long maxConnLifetimeMillis = -1; - private final AtomicLong connectionIndex = new AtomicLong(0); - private Integer defaultQueryTimeoutSeconds; + /** + * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation, + * passivation and validation. A value of zero or less indicates an infinite lifetime. The default value is -1. + * + * @param maxConnLifetimeMillis + * The maximum lifetime in milliseconds. + */ + public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) { + this.maxConnLifetimeMillis = maxConnLifetimeMillis; + } /** - * Internal constant to indicate the level is not set. + * Sets the maximum number of open prepared statements. + * + * @param maxOpenPreparedStatements + * The maximum number of open prepared statements. + */ + public void setMaxOpenPreparedStatements(final int maxOpenPreparedStatements) { + this.maxOpenPreparedStatements = maxOpenPreparedStatements; + } + + /** + * Deprecated due to typo in method name. + * + * @param maxOpenPreparedStatements + * The maximum number of open prepared statements. + * @deprecated Use {@link #setMaxOpenPreparedStatements(int)}. */ - static final int UNKNOWN_TRANSACTIONISOLATION = -1; + @Deprecated // Due to typo in method name. + public void setMaxOpenPrepatedStatements(final int maxOpenPreparedStatements) { + setMaxOpenPreparedStatements(maxOpenPreparedStatements); + } + + /** + * Sets the {@link ObjectPool} in which to pool {@link Connection}s. + * + * @param pool + * the {@link ObjectPool} in which to pool those {@link Connection}s + */ + public synchronized void setPool(final ObjectPool<PoolableConnection> pool) { + if (null != this.pool && pool != this.pool) { + try { + this.pool.close(); + } catch (final Exception e) { + // ignored !?! + } + } + this.pool = pool; + } + + public void setPoolStatements(final boolean poolStatements) { + this.poolStatements = poolStatements; + } + + public void setRollbackOnReturn(final boolean rollbackOnReturn) { + this.rollbackOnReturn = rollbackOnReturn; + } + + /** + * Sets the query I use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. If + * not specified, {@link Connection#isValid(int)} will be used to validate connections. + * + * @param validationQuery + * a query to use to {@link #validateObject validate} {@link Connection}s. + */ + public void setValidationQuery(final String validationQuery) { + this.validationQuery = validationQuery; + } + + /** + * Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a + * response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout. + * + * @param validationQueryTimeoutSeconds + * new validation query timeout value in seconds + */ + public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) { + this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds; + } + + public void validateConnection(final PoolableConnection conn) throws SQLException { + if (conn.isClosed()) { + throw new SQLException("validateConnection: connection closed"); + } + conn.validate(validationQuery, validationQueryTimeoutSeconds); + } + + private void validateLifetime(final PooledObject<PoolableConnection> p) throws Exception { + if (maxConnLifetimeMillis > 0) { + final long lifetime = System.currentTimeMillis() - p.getCreateTime(); + if (lifetime > maxConnLifetimeMillis) { + throw new LifetimeExceededException(Utils.getMessage("connectionFactory.lifetimeExceeded", + Long.valueOf(lifetime), Long.valueOf(maxConnLifetimeMillis))); + } + } + } + + @Override + public boolean validateObject(final PooledObject<PoolableConnection> p) { + try { + validateLifetime(p); + + validateConnection(p.getObject()); + return true; + } catch (final Exception e) { + if (log.isDebugEnabled()) { + log.debug(Utils.getMessage("poolableConnectionFactory.validateObject.fail"), e); + } + return false; + } + } }
Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java Tue Jan 29 15:03:15 2019 @@ -579,7 +579,7 @@ public class PoolingConnection extends D } @Override - public String toString() { + public synchronized String toString() { if (pstmtPool != null) { return "PoolingConnection: " + pstmtPool.toString(); } Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/Utils.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/Utils.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/Utils.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/Utils.java Tue Jan 29 15:03:15 2019 @@ -18,9 +18,6 @@ package org.apache.tomcat.dbcp.dbcp2; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.Statement; import java.text.MessageFormat; import java.util.HashSet; import java.util.ResourceBundle; @@ -47,9 +44,9 @@ public final class Utils { /** * SQL codes of fatal connection errors. * <ul> - * <li>57P01 (ADMIN SHUTDOWN)</li> - * <li>57P02 (CRASH SHUTDOWN)</li> - * <li>57P03 (CANNOT CONNECT NOW)</li> + * <li>57P01 (Admin shutdown)</li> + * <li>57P02 (Crash shutdown)</li> + * <li>57P03 (Cannot connect now)</li> * <li>01002 (SQL92 disconnect error)</li> * <li>JZ0C0 (Sybase disconnect error)</li> * <li>JZ0C1 (Sybase disconnect error)</li> @@ -59,18 +56,14 @@ public final class Utils { static { DISCONNECTION_SQL_CODES = new HashSet<>(); - DISCONNECTION_SQL_CODES.add("57P01"); // ADMIN SHUTDOWN - DISCONNECTION_SQL_CODES.add("57P02"); // CRASH SHUTDOWN - DISCONNECTION_SQL_CODES.add("57P03"); // CANNOT CONNECT NOW + DISCONNECTION_SQL_CODES.add("57P01"); // Admin shutdown + DISCONNECTION_SQL_CODES.add("57P02"); // Crash shutdown + DISCONNECTION_SQL_CODES.add("57P03"); // Cannot connect now DISCONNECTION_SQL_CODES.add("01002"); // SQL92 disconnect error DISCONNECTION_SQL_CODES.add("JZ0C0"); // Sybase disconnect error DISCONNECTION_SQL_CODES.add("JZ0C1"); // Sybase disconnect error } - private Utils() { - // not instantiable - } - /** * Clones the given char[] if not null. * @@ -83,47 +76,16 @@ public final class Utils { } /** - * Closes the ResultSet (which may be null). - * - * @param resultSet - * a ResultSet, may be {@code null} - */ - public static void closeQuietly(final ResultSet resultSet) { - if (resultSet != null) { - try { - resultSet.close(); - } catch (final Exception e) { - // ignored - } - } - } - - /** - * Closes the Connection (which may be null). + * Closes the AutoCloseable (which may be null). * - * @param connection - * a Connection, may be {@code null} + * @param autoCloseable + * an AutoCloseable, may be {@code null} + * @since 2.6.0 */ - public static void closeQuietly(final Connection connection) { - if (connection != null) { + public static void closeQuietly(final AutoCloseable autoCloseable) { + if (autoCloseable != null) { try { - connection.close(); - } catch (final Exception e) { - // ignored - } - } - } - - /** - * Closes the Statement (which may be null). - * - * @param statement - * a Statement, may be {@code null}. - */ - public static void closeQuietly(final Statement statement) { - if (statement != null) { - try { - statement.close(); + autoCloseable.close(); } catch (final Exception e) { // ignored } @@ -181,4 +143,8 @@ public final class Utils { return value == null ? null : String.valueOf(value); } + private Utils() { + // not instantiable + } + } Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java Tue Jan 29 15:03:15 2019 @@ -730,4 +730,49 @@ public class DriverAdapterCPDS implement } } } + + /** + * Does not print the userName and userPassword field nor the 'user' or 'password' in the connectionProperties. + * + * @since 2.6.0 + */ + @Override + public synchronized String toString() { + final StringBuilder builder = new StringBuilder(super.toString()); + builder.append("[description="); + builder.append(description); + builder.append(", url="); + // TODO What if the connection string contains a 'user' or 'password' query parameter but that connection string is not in a legal URL format? + builder.append(url); + builder.append(", driver="); + builder.append(driver); + builder.append(", loginTimeout="); + builder.append(loginTimeout); + builder.append(", poolPreparedStatements="); + builder.append(poolPreparedStatements); + builder.append(", maxIdle="); + builder.append(maxIdle); + builder.append(", timeBetweenEvictionRunsMillis="); + builder.append(timeBetweenEvictionRunsMillis); + builder.append(", numTestsPerEvictionRun="); + builder.append(numTestsPerEvictionRun); + builder.append(", minEvictableIdleTimeMillis="); + builder.append(minEvictableIdleTimeMillis); + builder.append(", maxPreparedStatements="); + builder.append(maxPreparedStatements); + builder.append(", getConnectionCalled="); + builder.append(getConnectionCalled); + builder.append(", connectionProperties="); + Properties tmpProps = connectionProperties; + final String pwdKey = "password"; + if (connectionProperties.contains(pwdKey)) { + tmpProps = (Properties) connectionProperties.clone(); + tmpProps.remove(pwdKey); + } + builder.append(tmpProps); + builder.append(", accessToUnderlyingConnectionAllowed="); + builder.append(accessToUnderlyingConnectionAllowed); + builder.append("]"); + return builder.toString(); + } } Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java Tue Jan 29 15:03:15 2019 @@ -30,6 +30,7 @@ import javax.sql.StatementEventListener; import org.apache.tomcat.dbcp.dbcp2.DelegatingConnection; import org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement; +import org.apache.tomcat.dbcp.dbcp2.Jdbc41Bridge; import org.apache.tomcat.dbcp.dbcp2.PStmtKey; import org.apache.tomcat.dbcp.dbcp2.PoolableCallableStatement; import org.apache.tomcat.dbcp.dbcp2.PoolablePreparedStatement; @@ -295,7 +296,7 @@ class PooledConnectionImpl private String getSchemaOrNull() { try { - return connection == null ? null : connection.getSchema(); + return connection == null ? null : Jdbc41Bridge.getSchema(connection); } catch (final SQLException e) { return null; } @@ -646,4 +647,30 @@ class PooledConnectionImpl public boolean validateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject) { return true; } + + /** + * @since 2.6.0 + */ + @Override + public synchronized String toString() { + final StringBuilder builder = new StringBuilder(super.toString()); + builder.append("[connection="); + builder.append(connection); + builder.append(", delegatingConnection="); + builder.append(delegatingConnection); + builder.append(", logicalConnection="); + builder.append(logicalConnection); + builder.append(", eventListeners="); + builder.append(eventListeners); + builder.append(", statementEventListeners="); + builder.append(statementEventListeners); + builder.append(", closed="); + builder.append(closed); + builder.append(", pStmtPool="); + builder.append(pStmtPool); + builder.append(", accessToUnderlyingConnectionAllowed="); + builder.append(accessToUnderlyingConnectionAllowed); + builder.append("]"); + return builder.toString(); + } } Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java Tue Jan 29 15:03:15 2019 @@ -397,4 +397,30 @@ class CPDSConnectionFactory } } } + + /** + * @since 2.6.0 + */ + @Override + public synchronized String toString() { + final StringBuilder builder = new StringBuilder(super.toString()); + builder.append("[cpds="); + builder.append(cpds); + builder.append(", validationQuery="); + builder.append(validationQuery); + builder.append(", validationQueryTimeoutSeconds="); + builder.append(validationQueryTimeoutSeconds); + builder.append(", rollbackAfterValidation="); + builder.append(rollbackAfterValidation); + builder.append(", pool="); + builder.append(pool); + builder.append(", maxConnLifetimeMillis="); + builder.append(maxConnLifetimeMillis); + builder.append(", validatingSet="); + builder.append(validatingSet); + builder.append(", pcMap="); + builder.append(pcMap); + builder.append("]"); + return builder.toString(); + } } Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java Tue Jan 29 15:03:15 2019 @@ -1053,4 +1053,79 @@ public abstract class InstanceKeyDataSou } return cpds; } + + /** + * @since 2.6.0 + */ + @Override + public synchronized String toString() { + final StringBuilder builder = new StringBuilder(super.toString()); + builder.append("["); + toStringFields(builder); + builder.append("]"); + return builder.toString(); + } + + protected void toStringFields(final StringBuilder builder) { + builder.append("getConnectionCalled="); + builder.append(getConnectionCalled); + builder.append(", dataSource="); + builder.append(dataSource); + builder.append(", dataSourceName="); + builder.append(dataSourceName); + builder.append(", description="); + builder.append(description); + builder.append(", jndiEnvironment="); + builder.append(jndiEnvironment); + builder.append(", loginTimeout="); + builder.append(loginTimeout); + builder.append(", logWriter="); + builder.append(logWriter); + builder.append(", instanceKey="); + builder.append(instanceKey); + builder.append(", defaultBlockWhenExhausted="); + builder.append(defaultBlockWhenExhausted); + builder.append(", defaultEvictionPolicyClassName="); + builder.append(defaultEvictionPolicyClassName); + builder.append(", defaultLifo="); + builder.append(defaultLifo); + builder.append(", defaultMaxIdle="); + builder.append(defaultMaxIdle); + builder.append(", defaultMaxTotal="); + builder.append(defaultMaxTotal); + builder.append(", defaultMaxWaitMillis="); + builder.append(defaultMaxWaitMillis); + builder.append(", defaultMinEvictableIdleTimeMillis="); + builder.append(defaultMinEvictableIdleTimeMillis); + builder.append(", defaultMinIdle="); + builder.append(defaultMinIdle); + builder.append(", defaultNumTestsPerEvictionRun="); + builder.append(defaultNumTestsPerEvictionRun); + builder.append(", defaultSoftMinEvictableIdleTimeMillis="); + builder.append(defaultSoftMinEvictableIdleTimeMillis); + builder.append(", defaultTestOnCreate="); + builder.append(defaultTestOnCreate); + builder.append(", defaultTestOnBorrow="); + builder.append(defaultTestOnBorrow); + builder.append(", defaultTestOnReturn="); + builder.append(defaultTestOnReturn); + builder.append(", defaultTestWhileIdle="); + builder.append(defaultTestWhileIdle); + builder.append(", defaultTimeBetweenEvictionRunsMillis="); + builder.append(defaultTimeBetweenEvictionRunsMillis); + builder.append(", validationQuery="); + builder.append(validationQuery); + builder.append(", validationQueryTimeoutSeconds="); + builder.append(validationQueryTimeoutSeconds); + builder.append(", rollbackAfterValidation="); + builder.append(rollbackAfterValidation); + builder.append(", maxConnLifetimeMillis="); + builder.append(maxConnLifetimeMillis); + builder.append(", defaultAutoCommit="); + builder.append(defaultAutoCommit); + builder.append(", defaultTransactionIsolation="); + builder.append(defaultTransactionIsolation); + builder.append(", defaultReadOnly="); + builder.append(defaultReadOnly); + } } Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java Tue Jan 29 15:03:15 2019 @@ -235,4 +235,11 @@ public class SharedPoolDataSource extend throw new IOException("NamingException: " + e); } } + + @Override + protected void toStringFields(final StringBuilder builder) { + super.toStringFields(builder); + builder.append(", maxTotal="); + builder.append(maxTotal); + } } Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/UserPassKey.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/UserPassKey.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/UserPassKey.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/UserPassKey.java Tue Jan 29 15:03:15 2019 @@ -125,9 +125,10 @@ class UserPassKey implements Serializabl @Override public String toString() { - final StringBuffer sb = new StringBuffer(50); - sb.append("UserPassKey("); - sb.append(userName).append(", ").append(userPassword).append(')'); + final StringBuffer sb = new StringBuffer(super.toString()); + sb.append("["); + sb.append(userName); + sb.append(']'); return sb.toString(); } } Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/BasicManagedDataSource.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/BasicManagedDataSource.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/BasicManagedDataSource.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/BasicManagedDataSource.java Tue Jan 29 15:03:15 2019 @@ -52,7 +52,7 @@ import org.apache.tomcat.dbcp.dbcp2.Util */ public class BasicManagedDataSource extends BasicDataSource { - /** Transaction Registry */ + /** Transaction Synchronization Registry */ private TransactionRegistry transactionRegistry; /** Transaction Manager */ @@ -240,7 +240,7 @@ public class BasicManagedDataSource exte connectionFactory.setMaxOpenPreparedStatements(getMaxOpenPreparedStatements()); connectionFactory.setMaxConnLifetimeMillis(getMaxConnLifetimeMillis()); connectionFactory.setRollbackOnReturn(getRollbackOnReturn()); - connectionFactory.setEnableAutoCommitOnReturn(getEnableAutoCommitOnReturn()); + connectionFactory.setAutoCommitOnReturn(getAutoCommitOnReturn()); connectionFactory.setDefaultQueryTimeout(getDefaultQueryTimeout()); connectionFactory.setFastFailValidation(getFastFailValidation()); connectionFactory.setDisconnectionSqlCodes(getDisconnectionSqlCodes()); Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/DataSourceXAConnectionFactory.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/DataSourceXAConnectionFactory.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/DataSourceXAConnectionFactory.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/DataSourceXAConnectionFactory.java Tue Jan 29 15:03:15 2019 @@ -51,21 +51,6 @@ public class DataSourceXAConnectionFacto * the transaction manager in which connections will be enlisted * @param xaDataSource * the data source from which connections will be retrieved - * @param transactionSynchronizationRegistry - * register with this TransactionSynchronizationRegistry - */ - public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource, final TransactionSynchronizationRegistry transactionSynchronizationRegistry) { - this(transactionManager, xaDataSource, null, (char[]) null, transactionSynchronizationRegistry); - } - - /** - * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections. - * The connections are enlisted into transactions using the specified transaction manager. - * - * @param transactionManager - * the transaction manager in which connections will be enlisted - * @param xaDataSource - * the data source from which connections will be retrieved * @since 2.6.0 */ public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource) { @@ -138,48 +123,18 @@ public class DataSourceXAConnectionFacto } /** - * Gets the user name used to authenticate new connections. - * - * @return the user name or null if unauthenticated connections are used - */ - public String getUsername() { - return userName; - } - - /** - * Sets the user name used to authenticate new connections. - * - * @param userName - * the user name used for authenticating the connection or null for unauthenticated - */ - public void setUsername(final String userName) { - this.userName = userName; - } - - /** - * Sets the password used to authenticate new connections. - * - * @param userPassword - * the password used for authenticating the connection or null for unauthenticated. - * @since 2.4.0 - */ - public void setPassword(final char[] userPassword) { - this.userPassword = userPassword; - } - - /** - * Sets the password used to authenticate new connections. + * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections. + * The connections are enlisted into transactions using the specified transaction manager. * - * @param userPassword - * the password used for authenticating the connection or null for unauthenticated + * @param transactionManager + * the transaction manager in which connections will be enlisted + * @param xaDataSource + * the data source from which connections will be retrieved + * @param transactionSynchronizationRegistry + * register with this TransactionSynchronizationRegistry */ - public void setPassword(final String userPassword) { - this.userPassword = Utils.toCharArray(userPassword); - } - - @Override - public TransactionRegistry getTransactionRegistry() { - return transactionRegistry; + public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource, final TransactionSynchronizationRegistry transactionSynchronizationRegistry) { + this(transactionManager, xaDataSource, null, (char[]) null, transactionSynchronizationRegistry); } @Override @@ -224,4 +179,69 @@ public class DataSourceXAConnectionFacto return connection; } + + @Override + public TransactionRegistry getTransactionRegistry() { + return transactionRegistry; + } + + /** + * Gets the user name used to authenticate new connections. + * + * @return the user name or null if unauthenticated connections are used + * @deprecated Use {@link #getUserName()}. + */ + @Deprecated + public String getUsername() { + return userName; + } + + /** + * Gets the user name used to authenticate new connections. + * + * @return the user name or null if unauthenticated connections are used + * @since 2.6.0 + */ + public String getUserName() { + return userName; + } + + public char[] getUserPassword() { + return userPassword; + } + + public XADataSource getXaDataSource() { + return xaDataSource; + } + + /** + * Sets the password used to authenticate new connections. + * + * @param userPassword + * the password used for authenticating the connection or null for unauthenticated. + * @since 2.4.0 + */ + public void setPassword(final char[] userPassword) { + this.userPassword = userPassword; + } + + /** + * Sets the password used to authenticate new connections. + * + * @param userPassword + * the password used for authenticating the connection or null for unauthenticated + */ + public void setPassword(final String userPassword) { + this.userPassword = Utils.toCharArray(userPassword); + } + + /** + * Sets the user name used to authenticate new connections. + * + * @param userName + * the user name used for authenticating the connection or null for unauthenticated + */ + public void setUsername(final String userName) { + this.userName = userName; + } } Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/LocalXAConnectionFactory.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/LocalXAConnectionFactory.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/LocalXAConnectionFactory.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/LocalXAConnectionFactory.java Tue Jan 29 15:03:15 2019 @@ -36,45 +36,6 @@ import org.apache.tomcat.dbcp.dbcp2.Conn * @since 2.0 */ public class LocalXAConnectionFactory implements XAConnectionFactory { - private final TransactionRegistry transactionRegistry; - private final ConnectionFactory connectionFactory; - - /** - * Creates an LocalXAConnectionFactory which uses the specified connection factory to create database connections. - * The connections are enlisted into transactions using the specified transaction manager. - * - * @param transactionManager - * the transaction manager in which connections will be enlisted - * @param connectionFactory - * the connection factory from which connections will be retrieved - */ - public LocalXAConnectionFactory(final TransactionManager transactionManager, - final ConnectionFactory connectionFactory) { - Objects.requireNonNull(transactionManager, "transactionManager is null"); - Objects.requireNonNull(connectionFactory, "connectionFactory is null"); - this.transactionRegistry = new TransactionRegistry(transactionManager); - this.connectionFactory = connectionFactory; - } - - @Override - public TransactionRegistry getTransactionRegistry() { - return transactionRegistry; - } - - @Override - public Connection createConnection() throws SQLException { - // create a new connection - final Connection connection = connectionFactory.createConnection(); - - // create a XAResource to manage the connection during XA transactions - final XAResource xaResource = new LocalXAResource(connection); - - // register the xa resource for the connection - transactionRegistry.registerConnection(connection, xaResource); - - return connection; - } - /** * LocalXAResource is a fake XAResource for non-XA connections. When a transaction is started the connection * auto-commit is turned off. When the connection is committed or rolled back, the commit or rollback method is @@ -98,61 +59,44 @@ public class LocalXAConnectionFactory im } /** - * Gets the current xid of the transaction branch associated with this XAResource. - * - * @return the current xid of the transaction branch associated with this XAResource. - */ - public synchronized Xid getXid() { - return currentXid; - } - - /** - * Signals that a the connection has been enrolled in a transaction. This method saves off the current auto - * commit flag, and then disables auto commit. The original auto commit setting is restored when the transaction - * completes. + * Commits the transaction and restores the original auto commit setting. * * @param xid * the id of the transaction branch for this connection * @param flag - * either XAResource.TMNOFLAGS or XAResource.TMRESUME + * ignored * @throws XAException - * if the connection is already enlisted in another transaction, or if auto-commit could not be - * disabled + * if connection.commit() throws a SQLException */ @Override - public synchronized void start(final Xid xid, final int flag) throws XAException { - if (flag == XAResource.TMNOFLAGS) { - // first time in this transaction + public synchronized void commit(final Xid xid, final boolean flag) throws XAException { + Objects.requireNonNull(xid, "xid is null"); + if (this.currentXid == null) { + throw new XAException("There is no current transaction"); + } + if (!this.currentXid.equals(xid)) { + throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid); + } - // make sure we aren't already in another tx - if (this.currentXid != null) { - throw new XAException("Already enlisted in another transaction with xid " + xid); + try { + // make sure the connection isn't already closed + if (connection.isClosed()) { + throw new XAException("Connection is closed"); } - // save off the current auto commit flag so it can be restored after the transaction completes - try { - originalAutoCommit = connection.getAutoCommit(); - } catch (final SQLException ignored) { - // no big deal, just assume it was off - originalAutoCommit = true; + // A read only connection should not be committed + if (!connection.isReadOnly()) { + connection.commit(); } - - // update the auto commit flag + } catch (final SQLException e) { + throw (XAException) new XAException().initCause(e); + } finally { try { - connection.setAutoCommit(false); + connection.setAutoCommit(originalAutoCommit); } catch (final SQLException e) { - throw (XAException) new XAException("Count not turn off auto commit for a XA transaction") - .initCause(e); - } - - this.currentXid = xid; - } else if (flag == XAResource.TMRESUME) { - if (!xid.equals(this.currentXid)) { - throw new XAException("Attempting to resume in different transaction: expected " + this.currentXid - + ", but was " + xid); + // ignore } - } else { - throw new XAException("Unknown start flag " + flag); + this.currentXid = null; } } @@ -179,6 +123,50 @@ public class LocalXAConnectionFactory im } /** + * Clears the currently associated transaction if it is the specified xid. + * + * @param xid + * the id of the transaction to forget + */ + @Override + public synchronized void forget(final Xid xid) { + if (xid != null && xid.equals(currentXid)) { + currentXid = null; + } + } + + /** + * Always returns 0 since we have no way to set a transaction timeout on a JDBC connection. + * + * @return always 0 + */ + @Override + public int getTransactionTimeout() { + return 0; + } + + /** + * Gets the current xid of the transaction branch associated with this XAResource. + * + * @return the current xid of the transaction branch associated with this XAResource. + */ + public synchronized Xid getXid() { + return currentXid; + } + + /** + * Returns true if the specified XAResource == this XAResource. + * + * @param xaResource + * the XAResource to test + * @return true if the specified XAResource == this XAResource; false otherwise + */ + @Override + public boolean isSameRM(final XAResource xaResource) { + return this == xaResource; + } + + /** * This method does nothing since the LocalXAConnection does not support two-phase-commit. This method will * return XAResource.XA_RDONLY if the connection isReadOnly(). This assumes that the physical connection is * wrapped with a proxy that prevents an application from changing the read-only flag while enrolled in a @@ -210,45 +198,16 @@ public class LocalXAConnectionFactory im } /** - * Commits the transaction and restores the original auto commit setting. + * Always returns a zero length Xid array. The LocalXAConnectionFactory can not support recovery, so no xids + * will ever be found. * - * @param xid - * the id of the transaction branch for this connection * @param flag - * ignored - * @throws XAException - * if connection.commit() throws a SQLException + * ignored since recovery is not supported + * @return always a zero length Xid array. */ @Override - public synchronized void commit(final Xid xid, final boolean flag) throws XAException { - Objects.requireNonNull(xid, "xid is null"); - if (this.currentXid == null) { - throw new XAException("There is no current transaction"); - } - if (!this.currentXid.equals(xid)) { - throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid); - } - - try { - // make sure the connection isn't already closed - if (connection.isClosed()) { - throw new XAException("Connection is closed"); - } - - // A read only connection should not be committed - if (!connection.isReadOnly()) { - connection.commit(); - } - } catch (final SQLException e) { - throw (XAException) new XAException().initCause(e); - } finally { - try { - connection.setAutoCommit(originalAutoCommit); - } catch (final SQLException e) { - // ignore - } - this.currentXid = null; - } + public Xid[] recover(final int flag) { + return new Xid[0]; } /** @@ -281,64 +240,113 @@ public class LocalXAConnectionFactory im } /** - * Returns true if the specified XAResource == this XAResource. + * Always returns false since we have no way to set a transaction timeout on a JDBC connection. * - * @param xaResource - * the XAResource to test - * @return true if the specified XAResource == this XAResource; false otherwise + * @param transactionTimeout + * ignored since we have no way to set a transaction timeout on a JDBC connection + * @return always false */ @Override - public boolean isSameRM(final XAResource xaResource) { - return this == xaResource; + public boolean setTransactionTimeout(final int transactionTimeout) { + return false; } /** - * Clears the currently associated transaction if it is the specified xid. + * Signals that a the connection has been enrolled in a transaction. This method saves off the current auto + * commit flag, and then disables auto commit. The original auto commit setting is restored when the transaction + * completes. * * @param xid - * the id of the transaction to forget + * the id of the transaction branch for this connection + * @param flag + * either XAResource.TMNOFLAGS or XAResource.TMRESUME + * @throws XAException + * if the connection is already enlisted in another transaction, or if auto-commit could not be + * disabled */ @Override - public synchronized void forget(final Xid xid) { - if (xid != null && xid.equals(currentXid)) { - currentXid = null; + public synchronized void start(final Xid xid, final int flag) throws XAException { + if (flag == XAResource.TMNOFLAGS) { + // first time in this transaction + + // make sure we aren't already in another tx + if (this.currentXid != null) { + throw new XAException("Already enlisted in another transaction with xid " + xid); + } + + // save off the current auto commit flag so it can be restored after the transaction completes + try { + originalAutoCommit = connection.getAutoCommit(); + } catch (final SQLException ignored) { + // no big deal, just assume it was off + originalAutoCommit = true; + } + + // update the auto commit flag + try { + connection.setAutoCommit(false); + } catch (final SQLException e) { + throw (XAException) new XAException("Count not turn off auto commit for a XA transaction") + .initCause(e); + } + + this.currentXid = xid; + } else if (flag == XAResource.TMRESUME) { + if (!xid.equals(this.currentXid)) { + throw new XAException("Attempting to resume in different transaction: expected " + this.currentXid + + ", but was " + xid); + } + } else { + throw new XAException("Unknown start flag " + flag); } } + } + private final TransactionRegistry transactionRegistry; - /** - * Always returns a zero length Xid array. The LocalXAConnectionFactory can not support recovery, so no xids - * will ever be found. - * - * @param flag - * ignored since recovery is not supported - * @return always a zero length Xid array. - */ - @Override - public Xid[] recover(final int flag) { - return new Xid[0]; - } + private final ConnectionFactory connectionFactory; - /** - * Always returns 0 since we have no way to set a transaction timeout on a JDBC connection. - * - * @return always 0 - */ - @Override - public int getTransactionTimeout() { - return 0; - } + /** + * Creates an LocalXAConnectionFactory which uses the specified connection factory to create database connections. + * The connections are enlisted into transactions using the specified transaction manager. + * + * @param transactionManager + * the transaction manager in which connections will be enlisted + * @param connectionFactory + * the connection factory from which connections will be retrieved + */ + public LocalXAConnectionFactory(final TransactionManager transactionManager, + final ConnectionFactory connectionFactory) { + Objects.requireNonNull(transactionManager, "transactionManager is null"); + Objects.requireNonNull(connectionFactory, "connectionFactory is null"); + this.transactionRegistry = new TransactionRegistry(transactionManager); + this.connectionFactory = connectionFactory; + } - /** - * Always returns false since we have no way to set a transaction timeout on a JDBC connection. - * - * @param transactionTimeout - * ignored since we have no way to set a transaction timeout on a JDBC connection - * @return always false - */ - @Override - public boolean setTransactionTimeout(final int transactionTimeout) { - return false; - } + @Override + public Connection createConnection() throws SQLException { + // create a new connection + final Connection connection = connectionFactory.createConnection(); + + // create a XAResource to manage the connection during XA transactions + final XAResource xaResource = new LocalXAResource(connection); + + // register the xa resource for the connection + transactionRegistry.registerConnection(connection, xaResource); + + return connection; + } + + /** + * @return The connection factory. + * @since 2.6.0 + */ + public ConnectionFactory getConnectionFactory() { + return connectionFactory; + } + + @Override + public TransactionRegistry getTransactionRegistry() { + return transactionRegistry; } } Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/ManagedConnection.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/ManagedConnection.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/ManagedConnection.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/ManagedConnection.java Tue Jan 29 15:03:15 2019 @@ -46,11 +46,25 @@ import org.apache.tomcat.dbcp.pool2.Obje */ public class ManagedConnection<C extends Connection> extends DelegatingConnection<C> { + /** + * Delegates to {@link ManagedConnection#transactionComplete()} for transaction completion events. + * + * @since 2.0 + */ + protected class CompletionListener implements TransactionContextListener { + @Override + public void afterCompletion(final TransactionContext completedContext, final boolean committed) { + if (completedContext == transactionContext) { + transactionComplete(); + } + } + } private final ObjectPool<C> pool; private final TransactionRegistry transactionRegistry; private final boolean accessToUnderlyingConnectionAllowed; private TransactionContext transactionContext; private boolean isSharedConnection; + private final Lock lock; /** @@ -81,6 +95,145 @@ public class ManagedConnection<C extends updateTransactionStatus(); } + @Override + public void close() throws SQLException { + if (!isClosedInternal()) { + // Don't actually close the connection if in a transaction. The + // connection will be closed by the transactionComplete method. + // + // DBCP-484 we need to make sure setClosedInternal(true) being + // invoked if transactionContext is not null as this value will + // be modified by the transactionComplete method which could run + // in the different thread with the transaction calling back. + lock.lock(); + try { + if (transactionContext == null || transactionContext.isTransactionComplete()) { + super.close(); + } + } finally { + try { + setClosedInternal(true); + } finally { + lock.unlock(); + } + } + } + } + + @Override + public void commit() throws SQLException { + if (transactionContext != null) { + throw new SQLException("Commit can not be set while enrolled in a transaction"); + } + super.commit(); + } + + @Override + public C getDelegate() { + if (isAccessToUnderlyingConnectionAllowed()) { + return getDelegateInternal(); + } + return null; + } + + // + // The following methods can't be used while enlisted in a transaction + // + + @Override + public Connection getInnermostDelegate() { + if (isAccessToUnderlyingConnectionAllowed()) { + return super.getInnermostDelegateInternal(); + } + return null; + } + + /** + * @return The transaction context. + * @since 2.6.0 + */ + public TransactionContext getTransactionContext() { + return transactionContext; + } + + /** + * @return The transaction registry. + * @since 2.6.0 + */ + public TransactionRegistry getTransactionRegistry() { + return transactionRegistry; + } + + /** + * If false, getDelegate() and getInnermostDelegate() will return null. + * + * @return if false, getDelegate() and getInnermostDelegate() will return null + */ + public boolean isAccessToUnderlyingConnectionAllowed() { + return accessToUnderlyingConnectionAllowed; + } + + // + // Methods for accessing the delegate connection + // + + @Override + public void rollback() throws SQLException { + if (transactionContext != null) { + throw new SQLException("Commit can not be set while enrolled in a transaction"); + } + super.rollback(); + } + + @Override + public void setAutoCommit(final boolean autoCommit) throws SQLException { + if (transactionContext != null) { + throw new SQLException("Auto-commit can not be set while enrolled in a transaction"); + } + super.setAutoCommit(autoCommit); + } + + @Override + public void setReadOnly(final boolean readOnly) throws SQLException { + if (transactionContext != null) { + throw new SQLException("Read-only can not be set while enrolled in a transaction"); + } + super.setReadOnly(readOnly); + } + + protected void transactionComplete() { + lock.lock(); + try { + transactionContext.completeTransaction(); + } finally { + lock.unlock(); + } + + // If we were using a shared connection, clear the reference now that + // the transaction has completed + if (isSharedConnection) { + setDelegate(null); + isSharedConnection = false; + } + + // If this connection was closed during the transaction and there is + // still a delegate present close it + final Connection delegate = getDelegateInternal(); + if (isClosedInternal() && delegate != null) { + try { + setDelegate(null); + + if (!delegate.isClosed()) { + delegate.close(); + } + } catch (final SQLException ignored) { + // Not a whole lot we can do here as connection is closed + // and this is a transaction callback so there is no + // way to report the error. + } + } + } + private void updateTransactionStatus() throws SQLException { // if there is a is an active transaction context, assure the transaction context hasn't changed if (transactionContext != null && !transactionContext.isTransactionComplete()) { @@ -171,141 +324,4 @@ public class ManagedConnection<C extends // connection clearCachedState(); } - - @Override - public void close() throws SQLException { - if (!isClosedInternal()) { - // Don't actually close the connection if in a transaction. The - // connection will be closed by the transactionComplete method. - // - // DBCP-484 we need to make sure setClosedInternal(true) being - // invoked if transactionContext is not null as this value will - // be modified by the transactionComplete method which could run - // in the different thread with the transaction calling back. - lock.lock(); - try { - if (transactionContext == null || transactionContext.isTransactionComplete()) { - super.close(); - } - } finally { - try { - setClosedInternal(true); - } finally { - lock.unlock(); - } - } - } - } - - /** - * Delegates to {@link ManagedConnection#transactionComplete()} for transaction completion events. - * - * @since 2.0 - */ - protected class CompletionListener implements TransactionContextListener { - @Override - public void afterCompletion(final TransactionContext completedContext, final boolean committed) { - if (completedContext == transactionContext) { - transactionComplete(); - } - } - } - - protected void transactionComplete() { - lock.lock(); - try { - transactionContext.completeTransaction(); - } finally { - lock.unlock(); - } - - // If we were using a shared connection, clear the reference now that - // the transaction has completed - if (isSharedConnection) { - setDelegate(null); - isSharedConnection = false; - } - - // If this connection was closed during the transaction and there is - // still a delegate present close it - final Connection delegate = getDelegateInternal(); - if (isClosedInternal() && delegate != null) { - try { - setDelegate(null); - - if (!delegate.isClosed()) { - delegate.close(); - } - } catch (final SQLException ignored) { - // Not a whole lot we can do here as connection is closed - // and this is a transaction callback so there is no - // way to report the error. - } - } - } - - // - // The following methods can't be used while enlisted in a transaction - // - - @Override - public void setAutoCommit(final boolean autoCommit) throws SQLException { - if (transactionContext != null) { - throw new SQLException("Auto-commit can not be set while enrolled in a transaction"); - } - super.setAutoCommit(autoCommit); - } - - @Override - public void commit() throws SQLException { - if (transactionContext != null) { - throw new SQLException("Commit can not be set while enrolled in a transaction"); - } - super.commit(); - } - - @Override - public void rollback() throws SQLException { - if (transactionContext != null) { - throw new SQLException("Commit can not be set while enrolled in a transaction"); - } - super.rollback(); - } - - @Override - public void setReadOnly(final boolean readOnly) throws SQLException { - if (transactionContext != null) { - throw new SQLException("Read-only can not be set while enrolled in a transaction"); - } - super.setReadOnly(readOnly); - } - - // - // Methods for accessing the delegate connection - // - - /** - * If false, getDelegate() and getInnermostDelegate() will return null. - * - * @return if false, getDelegate() and getInnermostDelegate() will return null - */ - public boolean isAccessToUnderlyingConnectionAllowed() { - return accessToUnderlyingConnectionAllowed; - } - - @Override - public C getDelegate() { - if (isAccessToUnderlyingConnectionAllowed()) { - return getDelegateInternal(); - } - return null; - } - - @Override - public Connection getInnermostDelegate() { - if (isAccessToUnderlyingConnectionAllowed()) { - return super.getInnermostDelegateInternal(); - } - return null; - } } Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/ManagedDataSource.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/ManagedDataSource.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/ManagedDataSource.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/ManagedDataSource.java Tue Jan 29 15:03:15 2019 @@ -52,6 +52,27 @@ public class ManagedDataSource<C extends this.transactionRegistry = transactionRegistry; } + @Override + public Connection getConnection() throws SQLException { + if (getPool() == null) { + throw new IllegalStateException("Pool has not been set"); + } + if (transactionRegistry == null) { + throw new IllegalStateException("TransactionRegistry has not been set"); + } + + return new ManagedConnection<>(getPool(), transactionRegistry, isAccessToUnderlyingConnectionAllowed()); + } + + /** + * @return The transaction registry + * + * @since 2.6.0 + */ + public TransactionRegistry getTransactionRegistry() { + return transactionRegistry; + } + /** * Sets the transaction registry from the XAConnectionFactory used to create the pool. The transaction registry can * only be set once using either a connector or this setter method. @@ -67,16 +88,4 @@ public class ManagedDataSource<C extends this.transactionRegistry = transactionRegistry; } - - @Override - public Connection getConnection() throws SQLException { - if (getPool() == null) { - throw new IllegalStateException("Pool has not been set"); - } - if (transactionRegistry == null) { - throw new IllegalStateException("TransactionRegistry has not been set"); - } - - return new ManagedConnection<>(getPool(), transactionRegistry, isAccessToUnderlyingConnectionAllowed()); - } } Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/PoolableManagedConnection.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/PoolableManagedConnection.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/PoolableManagedConnection.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/PoolableManagedConnection.java Tue Jan 29 15:03:15 2019 @@ -71,6 +71,14 @@ public class PoolableManagedConnection e } /** + * @return The transaction registry. + * @since 2.6.0 + */ + public TransactionRegistry getTransactionRegistry() { + return transactionRegistry; + } + + /** * Actually close the underlying connection. */ @Override Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/PoolableManagedConnectionFactory.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/PoolableManagedConnectionFactory.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/PoolableManagedConnectionFactory.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/PoolableManagedConnectionFactory.java Tue Jan 29 15:03:15 2019 @@ -57,6 +57,14 @@ public class PoolableManagedConnectionFa } /** + * @return The transaction registry. + * @since 2.6.0 + */ + public TransactionRegistry getTransactionRegistry() { + return transactionRegistry; + } + + /** * Uses the configured XAConnectionFactory to create a {@link PoolableManagedConnection}. Throws * <code>IllegalStateException</code> if the connection factory returns null. Also initializes the connection using * configured initialization SQL (if provided) and sets up a prepared statement pool associated with the Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/TransactionContext.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/TransactionContext.java?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/TransactionContext.java (original) +++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/TransactionContext.java Tue Jan 29 15:03:15 2019 @@ -132,7 +132,7 @@ public class TransactionContext { public void addTransactionContextListener(final TransactionContextListener listener) throws SQLException { try { if (!isActive()) { - Transaction transaction = this.transactionRef.get(); + final Transaction transaction = this.transactionRef.get(); listener.afterCompletion(TransactionContext.this, transaction == null ? false : transaction.getStatus() == Status.STATUS_COMMITTED); return; Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1852459&r1=1852458&r2=1852459&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Tue Jan 29 15:03:15 2019 @@ -280,6 +280,10 @@ Update the internal fork of Apache Commons FileUpload to pick up the changes in the Apache Commons FileUpload 1.4 release. (markt) </add> + <update> + Update the internal fork of Apache Commons DBCP 2 to de20b77 + (2019-01-29) to pick up some bug fixes and enhancements. (markt) + </update> </changelog> </subsection> </section> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
