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