You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2018/06/19 09:04:10 UTC
svn commit: r1833794 [16/17] - in /tomcat/trunk: ./
java/org/apache/tomcat/dbcp/dbcp2/
java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/
java/org/apache/tomcat/dbcp/dbcp2/datasources/
java/org/apache/tomcat/dbcp/dbcp2/managed/ webapps/docs/
Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionManager.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionManager.java?rev=1833794&r1=1833793&r2=1833794&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionManager.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionManager.java Tue Jun 19 09:04:08 2018
@@ -27,29 +27,41 @@ import javax.sql.PooledConnection;
* @since 2.0
*/
interface PooledConnectionManager {
+
/**
- * Close the PooledConnection and remove it from the connection pool
- * to which it belongs, adjusting pool counters.
+ * Closes the PooledConnection and remove it from the connection pool to which it belongs, adjusting pool counters.
*
- * @param pc PooledConnection to be invalidated
- * @throws SQLException if an SQL error occurs closing the connection
+ * @param pc
+ * PooledConnection to be invalidated
+ * @throws SQLException
+ * if an SQL error occurs closing the connection
*/
void invalidate(PooledConnection pc) throws SQLException;
+ // /**
+ // * Sets the database password used when creating connections.
+ // *
+ // * @param password password used when authenticating to the database
+ // * @since 3.0.0
+ // */
+ // void setPassword(char[] password);
+
/**
* Sets the database password used when creating connections.
*
- * @param password password used when authenticating to the database
+ * @param password
+ * password used when authenticating to the database
*/
void setPassword(String password);
-
/**
* Closes the connection pool associated with the given user.
*
- * @param username user name
- * @throws SQLException if an error occurs closing idle connections in the pool
+ * @param userName
+ * user name
+ * @throws SQLException
+ * if an error occurs closing idle connections in the pool
*/
- void closePool(String username) throws SQLException;
+ void closePool(String userName) throws SQLException;
}
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=1833794&r1=1833793&r2=1833794&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 Jun 19 09:04:08 2018
@@ -32,20 +32,20 @@ import org.apache.tomcat.dbcp.pool2.impl
import org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPoolConfig;
/**
- * <p>A pooling <code>DataSource</code> appropriate for deployment within
- * J2EE environment. There are many configuration options, most of which are
- * defined in the parent class. All users (based on username) share a single
- * maximum number of Connections in this datasource.</p>
+ * <p>
+ * A pooling <code>DataSource</code> appropriate for deployment within J2EE environment. There are many configuration
+ * options, most of which are defined in the parent class. All users (based on user name) share a single maximum number
+ * of Connections in this data source.
+ * </p>
*
- * <p>User passwords can be changed without re-initializing the datasource.
- * When a <code>getConnection(username, password)</code> request is processed
- * with a password that is different from those used to create connections in the
- * pool associated with <code>username</code>, an attempt is made to create a
- * new connection using the supplied password and if this succeeds, idle connections
- * created using the old password are destroyed and new connections are created
- * using the new password.</p>
+ * <p>
+ * User passwords can be changed without re-initializing the data source. When a
+ * <code>getConnection(user name, password)</code> request is processed with a password that is different from those
+ * used to create connections in the pool associated with <code>user name</code>, an attempt is made to create a new
+ * connection using the supplied password and if this succeeds, idle connections created using the old password are
+ * destroyed and new connections are created using the new password.
+ * </p>
*
- * @author John D. McNally
* @since 2.0
*/
public class SharedPoolDataSource extends InstanceKeyDataSource {
@@ -55,18 +55,18 @@ public class SharedPoolDataSource extend
// Pool properties
private int maxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
-
- private transient KeyedObjectPool<UserPassKey,PooledConnectionAndInfo> pool = null;
- private transient KeyedCPDSConnectionFactory factory = null;
+ private transient KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> pool;
+ private transient KeyedCPDSConnectionFactory factory;
/**
- * Default no-arg constructor for Serialization
+ * Default no-argument constructor for Serialization
*/
public SharedPoolDataSource() {
+ // empty.
}
/**
- * Close pool being maintained by this datasource.
+ * Closes pool being maintained by this data source.
*/
@Override
public void close() throws Exception {
@@ -76,11 +76,12 @@ public class SharedPoolDataSource extend
InstanceKeyDataSourceFactory.removeInstance(getInstanceKey());
}
-
// -------------------------------------------------------------------
// Properties
/**
+ * Gets {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
+ *
* @return {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
*/
public int getMaxTotal() {
@@ -88,27 +89,32 @@ public class SharedPoolDataSource extend
}
/**
- * Set {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
- * @param maxTotal The max total value
+ * Sets {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
+ *
+ * @param maxTotal
+ * {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
*/
public void setMaxTotal(final int maxTotal) {
assertInitializationAllowed();
this.maxTotal = maxTotal;
}
-
// ----------------------------------------------------------------------
// Instrumentation Methods
/**
- * @return the number of active connections in the pool.
+ * Gets the number of active connections in the pool.
+ *
+ * @return The number of active connections in the pool.
*/
public int getNumActive() {
return pool == null ? 0 : pool.getNumActive();
}
/**
- * @return the number of idle connections in the pool.
+ * Gets the number of idle connections in the pool.
+ *
+ * @return The number of idle connections in the pool.
*/
public int getNumIdle() {
return pool == null ? 0 : pool.getNumIdle();
@@ -118,14 +124,13 @@ public class SharedPoolDataSource extend
// Inherited abstract methods
@Override
- protected PooledConnectionAndInfo
- getPooledConnectionAndInfo(final String username, final String password)
- throws SQLException {
+ protected PooledConnectionAndInfo getPooledConnectionAndInfo(final String userName, final String userPassword)
+ throws SQLException {
- synchronized(this) {
+ synchronized (this) {
if (pool == null) {
try {
- registerPool(username, password);
+ registerPool(userName, userPassword);
} catch (final NamingException e) {
throw new SQLException("RegisterPool failed", e);
}
@@ -134,47 +139,41 @@ public class SharedPoolDataSource extend
PooledConnectionAndInfo info = null;
- final UserPassKey key = new UserPassKey(username, password);
+ final UserPassKey key = new UserPassKey(userName, userPassword);
try {
info = pool.borrowObject(key);
- }
- catch (final Exception e) {
- throw new SQLException(
- "Could not retrieve connection info from pool", e);
+ } catch (final Exception e) {
+ throw new SQLException("Could not retrieve connection info from pool", e);
}
return info;
}
@Override
- protected PooledConnectionManager getConnectionManager(final UserPassKey upkey) {
+ protected PooledConnectionManager getConnectionManager(final UserPassKey upkey) {
return factory;
}
/**
- * @return a <code>SharedPoolDataSource</code> {@link Reference}.
- * @throws NamingException Should not occur
+ * Returns a <code>SharedPoolDataSource</code> {@link Reference}.
*/
@Override
public Reference getReference() throws NamingException {
- final Reference ref = new Reference(getClass().getName(),
- SharedPoolDataSourceFactory.class.getName(), null);
+ final Reference ref = new Reference(getClass().getName(), SharedPoolDataSourceFactory.class.getName(), null);
ref.add(new StringRefAddr("instanceKey", getInstanceKey()));
return ref;
}
- private void registerPool(final String username, final String password)
- throws NamingException, SQLException {
+ private void registerPool(final String userName, final String password) throws NamingException, SQLException {
- final ConnectionPoolDataSource cpds = testCPDS(username, password);
+ final ConnectionPoolDataSource cpds = testCPDS(userName, password);
// Create an object pool to contain our PooledConnections
- factory = new KeyedCPDSConnectionFactory(cpds, getValidationQuery(),
- getValidationQueryTimeout(), isRollbackAfterValidation());
+ factory = new KeyedCPDSConnectionFactory(cpds, getValidationQuery(), getValidationQueryTimeout(),
+ isRollbackAfterValidation());
factory.setMaxConnLifetimeMillis(getMaxConnLifetimeMillis());
- final GenericKeyedObjectPoolConfig<PooledConnectionAndInfo> config =
- new GenericKeyedObjectPoolConfig<>();
+ final GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig();
config.setBlockWhenExhausted(getDefaultBlockWhenExhausted());
config.setEvictionPolicyClassName(getDefaultEvictionPolicyClassName());
config.setLifo(getDefaultLifo());
@@ -182,66 +181,58 @@ public class SharedPoolDataSource extend
config.setMaxTotal(getMaxTotal());
config.setMaxTotalPerKey(getDefaultMaxTotal());
config.setMaxWaitMillis(getDefaultMaxWaitMillis());
- config.setMinEvictableIdleTimeMillis(
- getDefaultMinEvictableIdleTimeMillis());
+ config.setMinEvictableIdleTimeMillis(getDefaultMinEvictableIdleTimeMillis());
config.setMinIdlePerKey(getDefaultMinIdle());
config.setNumTestsPerEvictionRun(getDefaultNumTestsPerEvictionRun());
- config.setSoftMinEvictableIdleTimeMillis(
- getDefaultSoftMinEvictableIdleTimeMillis());
+ config.setSoftMinEvictableIdleTimeMillis(getDefaultSoftMinEvictableIdleTimeMillis());
config.setTestOnCreate(getDefaultTestOnCreate());
config.setTestOnBorrow(getDefaultTestOnBorrow());
config.setTestOnReturn(getDefaultTestOnReturn());
config.setTestWhileIdle(getDefaultTestWhileIdle());
- config.setTimeBetweenEvictionRunsMillis(
- getDefaultTimeBetweenEvictionRunsMillis());
+ config.setTimeBetweenEvictionRunsMillis(getDefaultTimeBetweenEvictionRunsMillis());
- final KeyedObjectPool<UserPassKey,PooledConnectionAndInfo> tmpPool =
- new GenericKeyedObjectPool<>(factory, config);
+ final KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> tmpPool = new GenericKeyedObjectPool<>(factory,
+ config);
factory.setPool(tmpPool);
pool = tmpPool;
}
@Override
- protected void setupDefaults(final Connection con, final String username) throws SQLException {
+ protected void setupDefaults(final Connection connection, final String userName) throws SQLException {
final Boolean defaultAutoCommit = isDefaultAutoCommit();
- if (defaultAutoCommit != null &&
- con.getAutoCommit() != defaultAutoCommit.booleanValue()) {
- con.setAutoCommit(defaultAutoCommit.booleanValue());
+ if (defaultAutoCommit != null && connection.getAutoCommit() != defaultAutoCommit.booleanValue()) {
+ connection.setAutoCommit(defaultAutoCommit.booleanValue());
}
final int defaultTransactionIsolation = getDefaultTransactionIsolation();
if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION) {
- con.setTransactionIsolation(defaultTransactionIsolation);
+ connection.setTransactionIsolation(defaultTransactionIsolation);
}
final Boolean defaultReadOnly = isDefaultReadOnly();
- if (defaultReadOnly != null &&
- con.isReadOnly() != defaultReadOnly.booleanValue()) {
- con.setReadOnly(defaultReadOnly.booleanValue());
+ if (defaultReadOnly != null && connection.isReadOnly() != defaultReadOnly.booleanValue()) {
+ connection.setReadOnly(defaultReadOnly.booleanValue());
}
}
/**
* Supports Serialization interface.
*
- * @param in a <code>java.io.ObjectInputStream</code> value
- * @throws IOException if an error occurs
- * @throws ClassNotFoundException if an error occurs
- */
- private void readObject(final ObjectInputStream in)
- throws IOException, ClassNotFoundException {
- try
- {
+ * @param in
+ * a <code>java.io.ObjectInputStream</code> value
+ * @throws IOException
+ * if an error occurs
+ * @throws ClassNotFoundException
+ * if an error occurs
+ */
+ private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
+ try {
in.defaultReadObject();
- final SharedPoolDataSource oldDS = (SharedPoolDataSource)
- new SharedPoolDataSourceFactory()
+ final SharedPoolDataSource oldDS = (SharedPoolDataSource) new SharedPoolDataSourceFactory()
.getObjectInstance(getReference(), null, null, null);
this.pool = oldDS.pool;
- }
- catch (final NamingException e)
- {
+ } catch (final NamingException e) {
throw new IOException("NamingException: " + e);
}
}
}
-
Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSourceFactory.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSourceFactory.java?rev=1833794&r1=1833793&r2=1833794&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSourceFactory.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSourceFactory.java Tue Jun 19 09:04:08 2018
@@ -22,13 +22,11 @@ import javax.naming.Reference;
/**
* A JNDI ObjectFactory which creates <code>SharedPoolDataSource</code>s
+ *
* @since 2.0
*/
-public class SharedPoolDataSourceFactory
- extends InstanceKeyDataSourceFactory
-{
- private static final String SHARED_POOL_CLASSNAME =
- SharedPoolDataSource.class.getName();
+public class SharedPoolDataSourceFactory extends InstanceKeyDataSourceFactory {
+ private static final String SHARED_POOL_CLASSNAME = SharedPoolDataSource.class.getName();
@Override
protected boolean isCorrectClass(final String className) {
@@ -40,10 +38,8 @@ public class SharedPoolDataSourceFactory
final SharedPoolDataSource spds = new SharedPoolDataSource();
final RefAddr ra = ref.get("maxTotal");
if (ra != null && ra.getContent() != null) {
- spds.setMaxTotal(
- Integer.parseInt(ra.getContent().toString()));
+ spds.setMaxTotal(Integer.parseInt(ra.getContent().toString()));
}
return spds;
}
}
-
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=1833794&r1=1833793&r2=1833794&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 Jun 19 09:04:08 2018
@@ -19,85 +19,115 @@ package org.apache.tomcat.dbcp.dbcp2.dat
import java.io.Serializable;
+import org.apache.tomcat.dbcp.dbcp2.Utils;
+
/**
- * <p>Holds a username, password pair. Serves as a poolable object key for the KeyedObjectPool
- * backing a SharedPoolDataSource. Two instances with the same username are considered equal.
- * This ensures that there will be only one keyed pool for each user in the pool. The password
- * is used (along with the username) by the KeyedCPDSConnectionFactory when creating new connections.</p>
+ * <p>
+ * Holds a user name and password pair. Serves as a poolable object key for the KeyedObjectPool backing a
+ * SharedPoolDataSource. Two instances with the same user name are considered equal. This ensures that there will be
+ * only one keyed pool for each user in the pool. The password is used (along with the user name) by the
+ * KeyedCPDSConnectionFactory when creating new connections.
+ * </p>
*
- * <p>{@link InstanceKeyDataSource#getConnection(String, String)} validates that the password used to create
- * a connection matches the password provided by the client.</p>
+ * <p>
+ * {@link InstanceKeyDataSource#getConnection(String, String)} validates that the password used to create a connection
+ * matches the password provided by the client.
+ * </p>
*
* @since 2.0
*/
class UserPassKey implements Serializable {
private static final long serialVersionUID = 5142970911626584817L;
- private final String password;
- private final String username;
-
- UserPassKey(final String username, final String password) {
- this.username = username;
- this.password = password;
- }
+ private final String userName;
+ private final char[] userPassword;
/**
- * Get the value of password.
- * @return value of password.
+ * @since 2.4.0
*/
- public String getPassword() {
- return password;
+ UserPassKey(final String userName) {
+ this(userName, (char[]) null);
}
/**
- * Get the value of username.
- * @return value of username.
+ * @since 2.4.0
*/
- public String getUsername() {
- return username;
+ UserPassKey(final String userName, final char[] password) {
+ this.userName = userName;
+ this.userPassword = password;
+ }
+
+ UserPassKey(final String userName, final String userPassword) {
+ this(userName, Utils.toCharArray(userPassword));
}
/**
- * @return <code>true</code> if the username fields for both
- * objects are equal. Two instances with the same username
- * but different passwords are considered equal.
- *
- * @see java.lang.Object#equals(java.lang.Object)
+ * Only takes the user name into account.
*/
@Override
public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
if (obj == null) {
return false;
}
-
- if (obj == this) {
- return true;
+ if (getClass() != obj.getClass()) {
+ return false;
}
-
- if (!(obj instanceof UserPassKey)) {
+ final UserPassKey other = (UserPassKey) obj;
+ if (userName == null) {
+ if (other.userName != null) {
+ return false;
+ }
+ } else if (!userName.equals(other.userName)) {
return false;
}
+ return true;
+ }
- final UserPassKey key = (UserPassKey) obj;
+ /**
+ * Gets the value of password.
+ *
+ * @return value of password.
+ */
+ public String getPassword() {
+ return Utils.toString(userPassword);
+ }
+
+ /**
+ * Gets the value of password.
+ *
+ * @return value of password.
+ */
+ public char[] getPasswordCharArray() {
+ return userPassword;
+ }
- return this.username == null ?
- key.username == null :
- this.username.equals(key.username);
+ /**
+ * Gets the value of user name.
+ *
+ * @return value of user name.
+ */
+ public String getUsername() {
+ return userName;
}
/**
- * Returns the hash of the username.
+ * Only takes the user name into account.
*/
@Override
public int hashCode() {
- return this.username != null ?
- this.username.hashCode() : 0;
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((userName == null) ? 0 : userName.hashCode());
+ return result;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer(50);
sb.append("UserPassKey(");
- sb.append(username).append(", ").append(password).append(')');
+ sb.append(userName).append(", ").append(userPassword).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=1833794&r1=1833793&r2=1833794&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 Jun 19 09:04:08 2018
@@ -30,22 +30,18 @@ import org.apache.tomcat.dbcp.dbcp2.Pool
import org.apache.tomcat.dbcp.dbcp2.PoolingDataSource;
/**
- * <p>BasicManagedDataSource is an extension of BasicDataSource which
- * creates ManagedConnections. This data source can create either
- * full two-phase-commit XA connections or one-phase-commit
- * local connections. Both types of connections are committed or
- * rolled back as part of the global transaction (a.k.a. XA
- * transaction or JTA Transaction), but only XA connections can be
- * recovered in the case of a system crash.
+ * <p>
+ * BasicManagedDataSource is an extension of BasicDataSource which creates ManagedConnections. This data source can
+ * create either full two-phase-commit XA connections or one-phase-commit local connections. Both types of connections
+ * are committed or rolled back as part of the global transaction (a.k.a. XA transaction or JTA Transaction), but only
+ * XA connections can be recovered in the case of a system crash.
* </p>
- * <p>BasicManagedDataSource adds the TransactionManager and XADataSource
- * properties. The TransactionManager property is required and is
- * used to enlist connections in global transactions. The XADataSource
- * is optional and if set is the class name of the XADataSource class
- * for a two-phase-commit JDBC driver. If the XADataSource property
- * is set, the driverClassName is ignored and a DataSourceXAConnectionFactory
- * is created. Otherwise, a standard DriverConnectionFactory is created
- * and wrapped with a LocalXAConnectionFactory.
+ * <p>
+ * BasicManagedDataSource adds the TransactionManager and XADataSource properties. The TransactionManager property is
+ * required and is used to enlist connections in global transactions. The XADataSource is optional and if set is the
+ * class name of the XADataSource class for a two-phase-commit JDBC driver. If the XADataSource property is set, the
+ * driverClassName is ignored and a DataSourceXAConnectionFactory is created. Otherwise, a standard
+ * DriverConnectionFactory is created and wrapped with a LocalXAConnectionFactory.
* </p>
*
* @see BasicDataSource
@@ -53,13 +49,17 @@ import org.apache.tomcat.dbcp.dbcp2.Pool
* @since 2.0
*/
public class BasicManagedDataSource extends BasicDataSource {
+
/** Transaction Registry */
private TransactionRegistry transactionRegistry;
+
/** Transaction Manager */
private transient TransactionManager transactionManager;
- /** XA datasource class name */
+
+ /** XA data source class name */
private String xaDataSource;
- /** XA datasource instance */
+
+ /** XA data source instance */
private XADataSource xaDataSourceInstance;
/**
@@ -72,14 +72,17 @@ public class BasicManagedDataSource exte
}
/**
- * <p>Sets the XADataSource instance used by the XAConnectionFactory.</p>
* <p>
- * Note: this method currently has no effect once the pool has been
- * initialized. The pool is initialized the first time one of the
- * following methods is invoked: <code>getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+ * Sets the XADataSource instance used by the XAConnectionFactory.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
*
- * @param xaDataSourceInstance XADataSource instance
+ * @param xaDataSourceInstance
+ * XADataSource instance
*/
public synchronized void setXaDataSourceInstance(final XADataSource xaDataSourceInstance) {
this.xaDataSourceInstance = xaDataSourceInstance;
@@ -88,6 +91,7 @@ public class BasicManagedDataSource exte
/**
* Gets the required transaction manager property.
+ *
* @return the transaction manager used to enlist connections
*/
public TransactionManager getTransactionManager() {
@@ -96,6 +100,7 @@ public class BasicManagedDataSource exte
/**
* Gets the transaction registry.
+ *
* @return the transaction registry associating XAResources with managed connections
*/
protected synchronized TransactionRegistry getTransactionRegistry() {
@@ -104,7 +109,9 @@ public class BasicManagedDataSource exte
/**
* Sets the required transaction manager property.
- * @param transactionManager the transaction manager used to enlist connections
+ *
+ * @param transactionManager
+ * the transaction manager used to enlist connections
*/
public void setTransactionManager(final TransactionManager transactionManager) {
this.transactionManager = transactionManager;
@@ -112,6 +119,7 @@ public class BasicManagedDataSource exte
/**
* Gets the optional XADataSource class name.
+ *
* @return the optional XADataSource class name
*/
public synchronized String getXADataSource() {
@@ -120,7 +128,9 @@ public class BasicManagedDataSource exte
/**
* Sets the optional XADataSource class name.
- * @param xaDataSource the optional XADataSource class name
+ *
+ * @param xaDataSource
+ * the optional XADataSource class name
*/
public synchronized void setXADataSource(final String xaDataSource) {
this.xaDataSource = xaDataSource;
@@ -132,10 +142,12 @@ public class BasicManagedDataSource exte
throw new SQLException("Transaction manager must be set before a connection can be created");
}
- // If xa data source is not specified a DriverConnectionFactory is created and wrapped with a LocalXAConnectionFactory
+ // If xa data source is not specified a DriverConnectionFactory is created and wrapped with a
+ // LocalXAConnectionFactory
if (xaDataSource == null) {
final ConnectionFactory connectionFactory = super.createConnectionFactory();
- final XAConnectionFactory xaConnectionFactory = new LocalXAConnectionFactory(getTransactionManager(), connectionFactory);
+ final XAConnectionFactory xaConnectionFactory = new LocalXAConnectionFactory(getTransactionManager(),
+ connectionFactory);
transactionRegistry = xaConnectionFactory.getTransactionRegistry();
return xaConnectionFactory;
}
@@ -159,15 +171,16 @@ public class BasicManagedDataSource exte
}
// finally, create the XAConnectionFactory using the XA data source
- final XAConnectionFactory xaConnectionFactory = new DataSourceXAConnectionFactory(getTransactionManager(), xaDataSourceInstance, getUsername(), getPassword());
+ final XAConnectionFactory xaConnectionFactory = new DataSourceXAConnectionFactory(getTransactionManager(),
+ xaDataSourceInstance, getUsername(), getPassword());
transactionRegistry = xaConnectionFactory.getTransactionRegistry();
return xaConnectionFactory;
}
@Override
protected DataSource createDataSourceInstance() throws SQLException {
- final PoolingDataSource<PoolableConnection> pds =
- new ManagedDataSource<>(getConnectionPool(), transactionRegistry);
+ final PoolingDataSource<PoolableConnection> pds = new ManagedDataSource<>(getConnectionPool(),
+ transactionRegistry);
pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
return pds;
}
@@ -175,16 +188,18 @@ public class BasicManagedDataSource exte
/**
* Creates the PoolableConnectionFactory and attaches it to the connection pool.
*
- * @param driverConnectionFactory JDBC connection factory created by {@link #createConnectionFactory()}
- * @throws SQLException if an error occurs creating the PoolableConnectionFactory
+ * @param driverConnectionFactory
+ * JDBC connection factory created by {@link #createConnectionFactory()}
+ * @throws SQLException
+ * if an error occurs creating the PoolableConnectionFactory
*/
@Override
- protected PoolableConnectionFactory createPoolableConnectionFactory(
- final ConnectionFactory driverConnectionFactory) throws SQLException {
+ protected PoolableConnectionFactory createPoolableConnectionFactory(final ConnectionFactory driverConnectionFactory)
+ throws SQLException {
PoolableConnectionFactory connectionFactory = null;
try {
- connectionFactory = new PoolableManagedConnectionFactory(
- (XAConnectionFactory) driverConnectionFactory, getRegisteredJmxName());
+ connectionFactory = new PoolableManagedConnectionFactory((XAConnectionFactory) driverConnectionFactory,
+ getRegisteredJmxName());
connectionFactory.setValidationQuery(getValidationQuery());
connectionFactory.setValidationQueryTimeout(getValidationQueryTimeout());
connectionFactory.setConnectionInitSql(getConnectionInitSqls());
@@ -194,8 +209,7 @@ public class BasicManagedDataSource exte
connectionFactory.setDefaultCatalog(getDefaultCatalog());
connectionFactory.setCacheState(getCacheState());
connectionFactory.setPoolStatements(isPoolPreparedStatements());
- connectionFactory.setMaxOpenPreparedStatements(
- getMaxOpenPreparedStatements());
+ connectionFactory.setMaxOpenPreparedStatements(getMaxOpenPreparedStatements());
connectionFactory.setMaxConnLifetimeMillis(getMaxConnLifetimeMillis());
connectionFactory.setRollbackOnReturn(getRollbackOnReturn());
connectionFactory.setEnableAutoCommitOnReturn(getEnableAutoCommitOnReturn());
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=1833794&r1=1833793&r2=1833794&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 Jun 19 09:04:08 2018
@@ -19,6 +19,7 @@ package org.apache.tomcat.dbcp.dbcp2.man
import java.sql.Connection;
import java.sql.SQLException;
+import java.util.Objects;
import javax.sql.ConnectionEvent;
import javax.sql.ConnectionEventListener;
@@ -28,74 +29,111 @@ import javax.sql.XADataSource;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAResource;
+import org.apache.tomcat.dbcp.dbcp2.Utils;
+
/**
* An implementation of XAConnectionFactory which uses a real XADataSource to obtain connections and XAResources.
*
- * @author Dain Sundstrom
* @since 2.0
*/
public class DataSourceXAConnectionFactory implements XAConnectionFactory {
private final TransactionRegistry transactionRegistry;
private final XADataSource xaDataSource;
- private String username;
- private String password;
+ private String userName;
+ private char[] userPassword;
/**
- * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database
- * connections. The connections are enlisted into transactions using the specified transaction manager.
+ * 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
+ * @param transactionManager
+ * the transaction manager in which connections will be enlisted
+ * @param xaDataSource
+ * the data source from which connections will be retrieved
*/
public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource) {
- this(transactionManager, xaDataSource, null, null);
+ this(transactionManager, xaDataSource, null, (char[]) null);
}
/**
- * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database
- * connections. The connections are enlisted into transactions using the specified transaction manager.
+ * 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
- * @param username the username used for authenticating new connections or null for unauthenticated
- * @param password the password used for authenticating new connections
+ * @param transactionManager
+ * the transaction manager in which connections will be enlisted
+ * @param xaDataSource
+ * the data source from which connections will be retrieved
+ * @param userName
+ * the user name used for authenticating new connections or null for unauthenticated
+ * @param userPassword
+ * the password used for authenticating new connections
*/
- public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource, final String username, final String password) {
- if (transactionManager == null) {
- throw new NullPointerException("transactionManager is null");
- }
- if (xaDataSource == null) {
- throw new NullPointerException("xaDataSource is null");
- }
-
+ public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource,
+ final String userName, final char[] userPassword) {
+ Objects.requireNonNull(transactionManager, "transactionManager is null");
+ Objects.requireNonNull(xaDataSource, "xaDataSource is null");
this.transactionRegistry = new TransactionRegistry(transactionManager);
this.xaDataSource = xaDataSource;
- this.username = username;
- this.password = password;
+ this.userName = userName;
+ this.userPassword = userPassword;
+ }
+
+ /**
+ * 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
+ * @param userName
+ * the user name used for authenticating new connections or null for unauthenticated
+ * @param userPassword
+ * the password used for authenticating new connections
+ */
+ public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource,
+ final String userName, final String userPassword) {
+ this(transactionManager, xaDataSource, userName, Utils.toCharArray(userPassword));
}
/**
- * Gets the username used to authenticate new connections.
+ * 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;
+ return userName;
}
/**
- * Sets the username used to authenticate new connections.
- * @param username the username used for authenticating the connection or null for unauthenticated
+ * 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;
+ public void setUsername(final String userName) {
+ this.userName = userName;
}
/**
* Sets the password used to authenticate new connections.
- * @param password the password used for authenticating the connection or null for unauthenticated
+ *
+ * @param userPassword
+ * the password used for authenticating the connection or null for unauthenticated.
+ * @since 2.4.0
*/
- public void setPassword(final String password) {
- this.password = password;
+ 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);
}
@Override
@@ -107,10 +145,10 @@ public class DataSourceXAConnectionFacto
public Connection createConnection() throws SQLException {
// create a new XAConnection
XAConnection xaConnection;
- if (username == null) {
+ if (userName == null) {
xaConnection = xaDataSource.getXAConnection();
} else {
- xaConnection = xaDataSource.getXAConnection(username, password);
+ xaConnection = xaDataSource.getXAConnection(userName, Utils.toString(userPassword));
}
// get the real connection and XAResource from the connection
@@ -143,7 +181,6 @@ public class DataSourceXAConnectionFacto
}
});
-
return connection;
}
}
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=1833794&r1=1833793&r2=1833794&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 Jun 19 09:04:08 2018
@@ -19,6 +19,7 @@ package org.apache.tomcat.dbcp.dbcp2.man
import java.sql.Connection;
import java.sql.SQLException;
+import java.util.Objects;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAException;
@@ -28,11 +29,10 @@ import javax.transaction.xa.Xid;
import org.apache.tomcat.dbcp.dbcp2.ConnectionFactory;
/**
- * An implementation of XAConnectionFactory which manages non-XA connections in XA transactions. A non-XA connection
+ * An implementation of XAConnectionFactory which manages non-XA connections in XA transactions. A non-XA connection
* commits and rolls back as part of the XA transaction, but is not recoverable since the connection does not implement
* the 2-phase protocol.
*
- * @author Dain Sundstrom
* @since 2.0
*/
public class LocalXAConnectionFactory implements XAConnectionFactory {
@@ -40,20 +40,18 @@ public class LocalXAConnectionFactory im
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.
+ * 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
+ * @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) {
- if (transactionManager == null) {
- throw new NullPointerException("transactionManager is null");
- }
- if (connectionFactory == null) {
- throw new NullPointerException("connectionFactory is null");
- }
-
+ 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;
}
@@ -78,16 +76,16 @@ public class LocalXAConnectionFactory im
}
/**
- * 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 called on the connection and then the original auto-commit
- * value is restored.
+ * 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
+ * called on the connection and then the original auto-commit value is restored.
* <p>
- * The LocalXAResource also respects the connection read-only setting. If the connection is
- * read-only the commit method will not be called, and the prepare method returns the XA_RDONLY.
+ * The LocalXAResource also respects the connection read-only setting. If the connection is read-only the commit
+ * method will not be called, and the prepare method returns the XA_RDONLY.
* </p>
- * It is assumed that the wrapper around a managed connection disables the setAutoCommit(),
- * commit(), rollback() and setReadOnly() methods while a transaction is in progress.
+ * It is assumed that the wrapper around a managed connection disables the setAutoCommit(), commit(), rollback() and
+ * setReadOnly() methods while a transaction is in progress.
+ *
* @since 2.0
*/
protected static class LocalXAResource implements XAResource {
@@ -109,14 +107,17 @@ public class LocalXAConnectionFactory im
}
/**
- * 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 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
+ * 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 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 start(final Xid xid, final int flag) throws XAException {
@@ -140,13 +141,15 @@ public class LocalXAConnectionFactory im
try {
connection.setAutoCommit(false);
} catch (final SQLException e) {
- throw (XAException) new XAException("Count not turn off auto commit for a XA transaction").initCause(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);
+ throw new XAException("Attempting to resume in different transaction: expected " + this.currentXid
+ + ", but was " + xid);
}
} else {
throw new XAException("Unknown start flag " + flag);
@@ -156,31 +159,33 @@ public class LocalXAConnectionFactory im
/**
* This method does nothing.
*
- * @param xid the id of the transaction branch for this connection
- * @param flag ignored
- * @throws XAException if the connection is already enlisted in another transaction
+ * @param xid
+ * the id of the transaction branch for this connection
+ * @param flag
+ * ignored
+ * @throws XAException
+ * if the connection is already enlisted in another transaction
*/
@Override
public synchronized void end(final Xid xid, final int flag) throws XAException {
- if (xid == null) {
- throw new NullPointerException("xid is null");
- }
+ Objects.requireNonNull(xid, "xid is null");
if (!this.currentXid.equals(xid)) {
throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid);
}
// This notification tells us that the application server is done using this
- // connection for the time being. The connection is still associated with an
+ // connection for the time being. The connection is still associated with an
// open transaction, so we must still wait for the commit or rollback method
}
/**
- * 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 transaction.
+ * 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
+ * transaction.
*
- * @param xid the id of the transaction branch for this connection
+ * @param xid
+ * the id of the transaction branch for this connection
* @return XAResource.XA_RDONLY if the connection.isReadOnly(); XAResource.XA_OK otherwise
*/
@Override
@@ -207,21 +212,21 @@ public class LocalXAConnectionFactory im
/**
* Commits the transaction and restores the original auto commit setting.
*
- * @param xid the id of the transaction branch for this connection
- * @param flag ignored
- * @throws XAException if connection.commit() throws a SQLException
+ * @param xid
+ * the id of the transaction branch for this connection
+ * @param flag
+ * ignored
+ * @throws XAException
+ * if connection.commit() throws a SQLException
*/
@Override
public synchronized void commit(final Xid xid, final boolean flag) throws XAException {
- if (xid == null) {
- throw new NullPointerException("xid is null");
- }
+ 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);
+ throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid);
}
try {
@@ -240,6 +245,7 @@ public class LocalXAConnectionFactory im
try {
connection.setAutoCommit(originalAutoCommit);
} catch (final SQLException e) {
+ // ignore
}
this.currentXid = null;
}
@@ -248,14 +254,14 @@ public class LocalXAConnectionFactory im
/**
* Rolls back the transaction and restores the original auto commit setting.
*
- * @param xid the id of the transaction branch for this connection
- * @throws XAException if connection.rollback() throws a SQLException
+ * @param xid
+ * the id of the transaction branch for this connection
+ * @throws XAException
+ * if connection.rollback() throws a SQLException
*/
@Override
public synchronized void rollback(final Xid xid) throws XAException {
- if (xid == null) {
- throw new NullPointerException("xid is null");
- }
+ Objects.requireNonNull(xid, "xid is null");
if (!this.currentXid.equals(xid)) {
throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid);
}
@@ -268,6 +274,7 @@ public class LocalXAConnectionFactory im
try {
connection.setAutoCommit(originalAutoCommit);
} catch (final SQLException e) {
+ // Ignore.
}
this.currentXid = null;
}
@@ -276,7 +283,8 @@ public class LocalXAConnectionFactory im
/**
* Returns true if the specified XAResource == this XAResource.
*
- * @param xaResource the XAResource to test
+ * @param xaResource
+ * the XAResource to test
* @return true if the specified XAResource == this XAResource; false otherwise
*/
@Override
@@ -287,7 +295,8 @@ public class LocalXAConnectionFactory im
/**
* Clears the currently associated transaction if it is the specified xid.
*
- * @param xid the id of the transaction to forget
+ * @param xid
+ * the id of the transaction to forget
*/
@Override
public synchronized void forget(final Xid xid) {
@@ -297,9 +306,11 @@ public class LocalXAConnectionFactory im
}
/**
- * Always returns a zero length Xid array. The LocalXAConnectionFactory can not support recovery, so no xids will ever be found.
+ * 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
+ * @param flag
+ * ignored since recovery is not supported
* @return always a zero length Xid array.
*/
@Override
@@ -320,7 +331,8 @@ public class LocalXAConnectionFactory im
/**
* 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
+ * @param transactionTimeout
+ * ignored since we have no way to set a transaction timeout on a JDBC connection
* @return always false
*/
@Override
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=1833794&r1=1833793&r2=1833794&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 Jun 19 09:04:08 2018
@@ -19,43 +19,59 @@ package org.apache.tomcat.dbcp.dbcp2.man
import java.sql.Connection;
import java.sql.SQLException;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
import org.apache.tomcat.dbcp.dbcp2.DelegatingConnection;
import org.apache.tomcat.dbcp.pool2.ObjectPool;
/**
- * ManagedConnection is responsible for managing a database connection in a transactional environment
- * (typically called "Container Managed"). A managed connection operates like any other connection
- * when no global transaction (a.k.a. XA transaction or JTA Transaction) is in progress. When a
- * global transaction is active a single physical connection to the database is used by all
- * ManagedConnections accessed in the scope of the transaction. Connection sharing means that all
- * data access during a transaction has a consistent view of the database. When the global transaction
- * is committed or rolled back the enlisted connections are committed or rolled back. Typically upon
- * transaction completion, a connection returns to the auto commit setting in effect before being
- * enlisted in the transaction, but some vendors do not properly implement this.
+ * ManagedConnection is responsible for managing a database connection in a transactional environment (typically called
+ * "Container Managed"). A managed connection operates like any other connection when no global transaction (a.k.a. XA
+ * transaction or JTA Transaction) is in progress. When a global transaction is active a single physical connection to
+ * the database is used by all ManagedConnections accessed in the scope of the transaction. Connection sharing means
+ * that all data access during a transaction has a consistent view of the database. When the global transaction is
+ * committed or rolled back the enlisted connections are committed or rolled back. Typically upon transaction
+ * completion, a connection returns to the auto commit setting in effect before being enlisted in the transaction, but
+ * some vendors do not properly implement this.
+ * <p>
+ * When enlisted in a transaction the setAutoCommit(), commit(), rollback(), and setReadOnly() methods throw a
+ * SQLException. This is necessary to assure that the transaction completes as a single unit.
+ * </p>
*
- * When enlisted in a transaction the setAutoCommit(), commit(), rollback(), and setReadOnly() methods
- * throw a SQLException. This is necessary to assure that the transaction completes as a single unit.
+ * @param <C>
+ * the Connection type
*
- * @param <C> the Connection type
- *
- * @author Dain Sundstrom
* @since 2.0
*/
public class ManagedConnection<C extends Connection> extends DelegatingConnection<C> {
+
private final ObjectPool<C> pool;
private final TransactionRegistry transactionRegistry;
private final boolean accessToUnderlyingConnectionAllowed;
private TransactionContext transactionContext;
private boolean isSharedConnection;
+ private final Lock lock;
- public ManagedConnection(final ObjectPool<C> pool,
- final TransactionRegistry transactionRegistry,
+ /**
+ * Constructs a new instance responsible for managing a database connection in a transactional environment.
+ *
+ * @param pool
+ * The connection pool.
+ * @param transactionRegistry
+ * The transaction registry.
+ * @param accessToUnderlyingConnectionAllowed
+ * Whether or not to allow access to the underlying Connection.
+ * @throws SQLException
+ * Thrown when there is problem managing transactions.
+ */
+ public ManagedConnection(final ObjectPool<C> pool, final TransactionRegistry transactionRegistry,
final boolean accessToUnderlyingConnectionAllowed) throws SQLException {
super(null);
this.pool = pool;
this.transactionRegistry = transactionRegistry;
this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed;
+ this.lock = new ReentrantLock();
updateTransactionStatus();
}
@@ -67,7 +83,7 @@ public class ManagedConnection<C extends
private void updateTransactionStatus() throws SQLException {
// if there is a is an active transaction context, assure the transaction context hasn't changed
- if (transactionContext != null) {
+ if (transactionContext != null && !transactionContext.isTransactionComplete()) {
if (transactionContext.isActive()) {
if (transactionContext != transactionRegistry.getActiveTransactionContext()) {
throw new SQLException("Connection can not be used while enlisted in another transaction");
@@ -76,7 +92,7 @@ public class ManagedConnection<C extends
}
// transaction should have been cleared up by TransactionContextListener, but in
// rare cases another lister could have registered which uses the connection before
- // our listener is called. In that rare case, trigger the transaction complete call now
+ // our listener is called. In that rare case, trigger the transaction complete call now
transactionComplete();
}
@@ -111,8 +127,7 @@ public class ManagedConnection<C extends
// always be of type C since it has been shared by another
// connection from the same pool.
@SuppressWarnings("unchecked")
- final
- C shared = (C) transactionContext.getSharedConnection();
+ final C shared = (C) transactionContext.getSharedConnection();
setDelegate(shared);
// remember that we are using a shared connection so it can be cleared after the
@@ -162,18 +177,25 @@ public class ManagedConnection<C extends
try {
// Don't actually close the connection if in a transaction. The
// connection will be closed by the transactionComplete method.
- if (transactionContext == null) {
+ //
+ // 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();
+ if (transactionContext == null || transactionContext.isTransactionComplete()) {
super.close();
}
} finally {
setClosedInternal(true);
+ lock.unlock();
}
}
}
/**
- * Delegates to {@link ManagedConnection#transactionComplete()}
- * for transaction completion events.
+ * Delegates to {@link ManagedConnection#transactionComplete()} for transaction completion events.
+ *
* @since 2.0
*/
protected class CompletionListener implements TransactionContextListener {
@@ -186,7 +208,9 @@ public class ManagedConnection<C extends
}
protected void transactionComplete() {
- transactionContext = null;
+ lock.lock();
+ transactionContext.completeTransaction();
+ lock.unlock();
// If we were using a shared connection, clear the reference now that
// the transaction has completed
@@ -225,7 +249,6 @@ public class ManagedConnection<C extends
super.setAutoCommit(autoCommit);
}
-
@Override
public void commit() throws SQLException {
if (transactionContext != null) {
@@ -242,7 +265,6 @@ public class ManagedConnection<C extends
super.rollback();
}
-
@Override
public void setReadOnly(final boolean readOnly) throws SQLException {
if (transactionContext != null) {
@@ -257,6 +279,7 @@ public class ManagedConnection<C extends
/**
* If false, getDelegate() and getInnermostDelegate() will return null.
+ *
* @return if false, getDelegate() and getInnermostDelegate() will return null
*/
public boolean isAccessToUnderlyingConnectionAllowed() {
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=1833794&r1=1833793&r2=1833794&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 Jun 19 09:04:08 2018
@@ -19,6 +19,7 @@ package org.apache.tomcat.dbcp.dbcp2.man
import java.sql.Connection;
import java.sql.SQLException;
+import java.util.Objects;
import org.apache.tomcat.dbcp.dbcp2.PoolingDataSource;
import org.apache.tomcat.dbcp.pool2.ObjectPool;
@@ -26,45 +27,43 @@ import org.apache.tomcat.dbcp.pool2.Obje
/**
* The ManagedDataSource is a PoolingDataSource that creates ManagedConnections.
*
- * @author Dain Sundstrom
- * @param <C> The kind of {@link Connection} to manage.
+ * @param <C>
+ * The kind of {@link Connection} to manage.
* @since 2.0
*/
public class ManagedDataSource<C extends Connection> extends PoolingDataSource<C> {
private TransactionRegistry transactionRegistry;
/**
- * Creates a ManagedDataSource which obtains connections from the specified pool and
- * manages them using the specified transaction registry. The TransactionRegistry must
- * be the transaction registry obtained from the XAConnectionFactory used to create
- * the connection pool. If not, an error will occur when attempting to use the connection
- * in a global transaction because the XAResource object associated with the connection
- * will be unavailable.
+ * Creates a ManagedDataSource which obtains connections from the specified pool and manages them using the
+ * specified transaction registry. The TransactionRegistry must be the transaction registry obtained from the
+ * XAConnectionFactory used to create the connection pool. If not, an error will occur when attempting to use the
+ * connection in a global transaction because the XAResource object associated with the connection will be
+ * unavailable.
*
- * @param pool the connection pool
- * @param transactionRegistry the transaction registry obtained from the
- * XAConnectionFactory used to create the connection pool object factory
+ * @param pool
+ * the connection pool
+ * @param transactionRegistry
+ * the transaction registry obtained from the XAConnectionFactory used to create the connection pool
+ * object factory
*/
- public ManagedDataSource(final ObjectPool<C> pool,
- final TransactionRegistry transactionRegistry) {
+ public ManagedDataSource(final ObjectPool<C> pool, final TransactionRegistry transactionRegistry) {
super(pool);
this.transactionRegistry = 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.
- * @param transactionRegistry the transaction registry acquired from the XAConnectionFactory
- * used to create the pool
+ * 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.
+ *
+ * @param transactionRegistry
+ * the transaction registry acquired from the XAConnectionFactory used to create the pool
*/
public void setTransactionRegistry(final TransactionRegistry transactionRegistry) {
- if(this.transactionRegistry != null) {
+ if (this.transactionRegistry != null) {
throw new IllegalStateException("TransactionRegistry already set");
}
- if(transactionRegistry == null) {
- throw new NullPointerException("TransactionRegistry is null");
- }
+ Objects.requireNonNull(transactionRegistry, "transactionRegistry is null");
this.transactionRegistry = transactionRegistry;
}
@@ -78,7 +77,6 @@ public class ManagedDataSource<C extends
throw new IllegalStateException("TransactionRegistry has not been set");
}
- final Connection connection = new ManagedConnection<>(getPool(), transactionRegistry, isAccessToUnderlyingConnectionAllowed());
- return connection;
+ 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=1833794&r1=1833793&r2=1833794&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 Jun 19 09:04:08 2018
@@ -33,39 +33,43 @@ import org.apache.tomcat.dbcp.pool2.Obje
public class PoolableManagedConnection extends PoolableConnection {
private final TransactionRegistry transactionRegistry;
-
/**
* Create a PoolableManagedConnection.
*
- * @param transactionRegistry transaction registry
- * @param conn underlying connection
- * @param pool connection pool
+ * @param transactionRegistry
+ * transaction registry
+ * @param conn
+ * underlying connection
+ * @param pool
+ * connection pool
*/
- public PoolableManagedConnection(final TransactionRegistry transactionRegistry,
- final Connection conn, final ObjectPool<PoolableConnection> pool) {
+ public PoolableManagedConnection(final TransactionRegistry transactionRegistry, final Connection conn,
+ final ObjectPool<PoolableConnection> pool) {
this(transactionRegistry, conn, pool, null, false);
}
-
/**
* Create a PoolableManagedConnection.
*
- * @param transactionRegistry transaction registry
- * @param conn underlying connection
- * @param pool connection pool
- * @param disconnectSqlCodes SQL_STATE codes considered fatal disconnection errors
- * @param fastFailValidation true means fatal disconnection errors cause subsequent
- * validations to fail immediately (no attempt to run query or isValid)
+ * @param transactionRegistry
+ * transaction registry
+ * @param conn
+ * underlying connection
+ * @param pool
+ * connection pool
+ * @param disconnectSqlCodes
+ * SQL_STATE codes considered fatal disconnection errors
+ * @param fastFailValidation
+ * true means fatal disconnection errors cause subsequent validations to fail immediately (no attempt to
+ * run query or isValid)
*/
- public PoolableManagedConnection(final TransactionRegistry transactionRegistry,
- final Connection conn, final ObjectPool<PoolableConnection> pool,
- final Collection<String> disconnectSqlCodes,
+ public PoolableManagedConnection(final TransactionRegistry transactionRegistry, final Connection conn,
+ final ObjectPool<PoolableConnection> pool, final Collection<String> disconnectSqlCodes,
final boolean fastFailValidation) {
super(conn, pool, null, disconnectSqlCodes, fastFailValidation);
this.transactionRegistry = transactionRegistry;
}
-
/**
* Actually close the underlying connection.
*/
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=1833794&r1=1833793&r2=1833794&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 Jun 19 09:04:08 2018
@@ -44,26 +44,26 @@ public class PoolableManagedConnectionFa
private final TransactionRegistry transactionRegistry;
/**
- * Create a PoolableManagedConnectionFactory and attach it to a connection pool.
+ * Creates a PoolableManagedConnectionFactory and attach it to a connection pool.
*
- * @param connFactory XAConnectionFactory
- * @param dataSourceJmxName JMX name of the datasource
+ * @param connFactory
+ * XAConnectionFactory
+ * @param dataSourceJmxName
+ * The data source name.
*/
- public PoolableManagedConnectionFactory(final XAConnectionFactory connFactory,
- final ObjectName dataSourceJmxName) {
+ public PoolableManagedConnectionFactory(final XAConnectionFactory connFactory, final ObjectName dataSourceJmxName) {
super(connFactory, dataSourceJmxName);
this.transactionRegistry = connFactory.getTransactionRegistry();
}
/**
- * 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 PoolableManagedConnection
- * if statement pooling is enabled.
+ * 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
+ * PoolableManagedConnection if statement pooling is enabled.
*/
@Override
- public synchronized PooledObject<PoolableConnection> makeObject() throws Exception {
+ synchronized public PooledObject<PoolableConnection> makeObject() throws Exception {
Connection conn = getConnectionFactory().createConnection();
if (conn == null) {
throw new IllegalStateException("Connection factory returned null from createConnection");
@@ -71,7 +71,7 @@ public class PoolableManagedConnectionFa
initializeConnection(conn);
if (getPoolStatements()) {
conn = new PoolingConnection(conn);
- final GenericKeyedObjectPoolConfig<DelegatingPreparedStatement> config = new GenericKeyedObjectPoolConfig<>();
+ final GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig();
config.setMaxTotalPerKey(-1);
config.setBlockWhenExhausted(false);
config.setMaxWaitMillis(0);
@@ -88,15 +88,14 @@ public class PoolableManagedConnectionFa
} else {
config.setJmxEnabled(false);
}
- final KeyedObjectPool<PStmtKey,DelegatingPreparedStatement> stmtPool =
- new GenericKeyedObjectPool<>((PoolingConnection)conn, config);
- ((PoolingConnection)conn).setStatementPool(stmtPool);
+ final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> stmtPool = new GenericKeyedObjectPool<>(
+ (PoolingConnection) conn, config);
+ ((PoolingConnection) conn).setStatementPool(stmtPool);
((PoolingConnection) conn).setCacheState(getCacheState());
}
- final PoolableManagedConnection pmc =
- new PoolableManagedConnection(transactionRegistry, conn, getPool(),
- getDisconnectionSqlCodes(), isFastFailValidation());
+ final PoolableManagedConnection pmc = new PoolableManagedConnection(transactionRegistry, conn, getPool(),
+ getDisconnectionSqlCodes(), isFastFailValidation());
pmc.setCacheState(getCacheState());
- return new DefaultPooledObject<>(pmc);
+ return new DefaultPooledObject<PoolableConnection>(pmc);
}
}
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=1833794&r1=1833793&r2=1833794&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 Jun 19 09:04:08 2018
@@ -20,6 +20,7 @@ package org.apache.tomcat.dbcp.dbcp2.man
import java.lang.ref.WeakReference;
import java.sql.Connection;
import java.sql.SQLException;
+import java.util.Objects;
import javax.transaction.RollbackException;
import javax.transaction.Status;
@@ -29,43 +30,39 @@ import javax.transaction.Transaction;
import javax.transaction.xa.XAResource;
/**
- * TransactionContext represents the association between a single XAConnectionFactory and a Transaction.
- * This context contains a single shared connection which should be used by all ManagedConnections for
- * the XAConnectionFactory, the ability to listen for the transaction completion event, and a method
- * to check the status of the transaction.
+ * TransactionContext represents the association between a single XAConnectionFactory and a Transaction. This context
+ * contains a single shared connection which should be used by all ManagedConnections for the XAConnectionFactory, the
+ * ability to listen for the transaction completion event, and a method to check the status of the transaction.
*
- * @author Dain Sundstrom
* @since 2.0
*/
public class TransactionContext {
private final TransactionRegistry transactionRegistry;
private final WeakReference<Transaction> transactionRef;
private Connection sharedConnection;
+ private boolean transactionComplete;
/**
- * Creates a TransactionContext for the specified Transaction and TransactionRegistry. The
- * TransactionRegistry is used to obtain the XAResource for the shared connection when it is
- * enlisted in the transaction.
- *
- * @param transactionRegistry the TransactionRegistry used to obtain the XAResource for the
- * shared connection
- * @param transaction the transaction
+ * Creates a TransactionContext for the specified Transaction and TransactionRegistry. The TransactionRegistry is
+ * used to obtain the XAResource for the shared connection when it is enlisted in the transaction.
+ *
+ * @param transactionRegistry
+ * the TransactionRegistry used to obtain the XAResource for the shared connection
+ * @param transaction
+ * the transaction
*/
public TransactionContext(final TransactionRegistry transactionRegistry, final Transaction transaction) {
- if (transactionRegistry == null) {
- throw new NullPointerException("transactionRegistry is null");
- }
- if (transaction == null) {
- throw new NullPointerException("transaction is null");
- }
+ Objects.requireNonNull(transactionRegistry, "transactionRegistry is null");
+ Objects.requireNonNull(transaction, "transaction is null");
this.transactionRegistry = transactionRegistry;
this.transactionRef = new WeakReference<>(transaction);
+ this.transactionComplete = false;
}
/**
- * Gets the connection shared by all ManagedConnections in the transaction. Specifically,
- * connection using the same XAConnectionFactory from which the TransactionRegistry was
- * obtained.
+ * Gets the connection shared by all ManagedConnections in the transaction. Specifically, connection using the same
+ * XAConnectionFactory from which the TransactionRegistry was obtained.
+ *
* @return the shared connection for this transaction
*/
public Connection getSharedConnection() {
@@ -73,13 +70,13 @@ public class TransactionContext {
}
/**
- * Sets the shared connection for this transaction. The shared connection is enlisted
- * in the transaction.
+ * Sets the shared connection for this transaction. The shared connection is enlisted in the transaction.
*
- * @param sharedConnection the shared connection
- * @throws SQLException if a shared connection is already set, if XAResource for the connection
- * could not be found in the transaction registry, or if there was a problem enlisting the
- * connection in the transaction
+ * @param sharedConnection
+ * the shared connection
+ * @throws SQLException
+ * if a shared connection is already set, if XAResource for the connection could not be found in the
+ * transaction registry, or if there was a problem enlisting the connection in the transaction
*/
public void setSharedConnection(final Connection sharedConnection) throws SQLException {
if (this.sharedConnection != null) {
@@ -91,9 +88,12 @@ public class TransactionContext {
final Transaction transaction = getTransaction();
try {
final XAResource xaResource = transactionRegistry.getXAResource(sharedConnection);
- if ( !transaction.enlistResource(xaResource) ) {
+ if (!transaction.enlistResource(xaResource)) {
throw new SQLException("Unable to enlist connection in transaction: enlistResource returns 'false'.");
}
+ } catch (final IllegalStateException e) {
+ // This can happen if the transaction is already timed out
+ throw new SQLException("Unable to enlist connection in the transaction", e);
} catch (final RollbackException e) {
// transaction was rolled back... proceed as if there never was a transaction
} catch (final SystemException e) {
@@ -106,14 +106,17 @@ public class TransactionContext {
/**
* Adds a listener for transaction completion events.
*
- * @param listener the listener to add
- * @throws SQLException if a problem occurs adding the listener to the transaction
+ * @param listener
+ * the listener to add
+ * @throws SQLException
+ * if a problem occurs adding the listener to the transaction
*/
public void addTransactionContextListener(final TransactionContextListener listener) throws SQLException {
try {
getTransaction().registerSynchronization(new Synchronization() {
@Override
public void beforeCompletion() {
+ // empty
}
@Override
@@ -131,8 +134,10 @@ public class TransactionContext {
/**
* True if the transaction is active or marked for rollback only.
+ *
* @return true if the transaction is active or marked for rollback only; false otherwise
- * @throws SQLException if a problem occurs obtaining the transaction status
+ * @throws SQLException
+ * if a problem occurs obtaining the transaction status
*/
public boolean isActive() throws SQLException {
try {
@@ -154,4 +159,24 @@ public class TransactionContext {
}
return transaction;
}
+
+ /**
+ * Sets the transaction complete flag to true.
+ *
+ * @since 2.4.0
+ */
+ public void completeTransaction() {
+ this.transactionComplete = true;
+ }
+
+ /**
+ * Gets the transaction complete flag to true.
+ *
+ * @return The transaction complete flag.
+ *
+ * @since 2.4.0
+ */
+ public boolean isTransactionComplete() {
+ return this.transactionComplete;
+ }
}
Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/TransactionContextListener.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/TransactionContextListener.java?rev=1833794&r1=1833793&r2=1833794&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/TransactionContextListener.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/dbcp/dbcp2/managed/TransactionContextListener.java Tue Jun 19 09:04:08 2018
@@ -20,14 +20,16 @@ package org.apache.tomcat.dbcp.dbcp2.man
/**
* A listener for transaction completion events.
*
- * @author Dain Sundstrom
* @since 2.0
*/
public interface TransactionContextListener {
/**
* Occurs after the transaction commits or rolls back.
- * @param transactionContext the transaction context that completed
- * @param commited true if the transaction committed; false otherwise
+ *
+ * @param transactionContext
+ * the transaction context that completed
+ * @param commited
+ * true if the transaction committed; false otherwise
*/
void afterCompletion(TransactionContext transactionContext, boolean commited);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org