You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2018/11/13 18:53:03 UTC

commons-dbcp git commit: [DBCP-527 ]Add getters to some classes.

Repository: commons-dbcp
Updated Branches:
  refs/heads/master afc2d3ddd -> 34cd3da6f


[DBCP-527 ]Add getters to some classes.

Project: http://git-wip-us.apache.org/repos/asf/commons-dbcp/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-dbcp/commit/34cd3da6
Tree: http://git-wip-us.apache.org/repos/asf/commons-dbcp/tree/34cd3da6
Diff: http://git-wip-us.apache.org/repos/asf/commons-dbcp/diff/34cd3da6

Branch: refs/heads/master
Commit: 34cd3da6f240bdd9a0e0844923715ad1fb7a6cc4
Parents: afc2d3d
Author: Gary Gregory <ga...@gmail.com>
Authored: Tue Nov 13 11:53:00 2018 -0700
Committer: Gary Gregory <ga...@gmail.com>
Committed: Tue Nov 13 11:53:00 2018 -0700

----------------------------------------------------------------------
 src/changes/changes.xml                         |   3 +
 .../dbcp2/DataSourceConnectionFactory.java      |  21 ++
 .../commons/dbcp2/DriverConnectionFactory.java  |  21 ++
 .../dbcp2/DriverManagerConnectionFactory.java   |  37 ++-
 .../commons/dbcp2/PoolableConnection.java       |  21 ++
 .../dbcp2/PoolableConnectionFactory.java        |  82 ++++-
 .../managed/DataSourceXAConnectionFactory.java  | 130 ++++----
 .../dbcp2/managed/LocalXAConnectionFactory.java | 323 ++++++++++---------
 .../dbcp2/managed/ManagedConnection.java        | 288 +++++++++--------
 .../dbcp2/managed/ManagedDataSource.java        |  31 +-
 .../managed/PoolableManagedConnection.java      |   7 +
 .../PoolableManagedConnectionFactory.java       |   7 +
 12 files changed, 604 insertions(+), 367 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/34cd3da6/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index c0b2c3c..98f341c 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -82,6 +82,9 @@ The <action> type attribute can be add,update,fix,remove.
       <action dev="ggregory" type="update" issue="DBCP-520" due-to="Zheng Feng">
         BasicManagedDataSource needs to pass the TSR with creating DataSourceXAConnectionFactory.
       </action>
+      <action dev="ggregory" type="add" issue="DBCP-527" due-to="Gary Gregory">
+        Add getters to some classes.
+      </action>
     </release>
     <release version="2.5.0" date="2018-07-15" description="This is a minor release, including bug fixes and enhancements.">
       <action dev="ggregory" type="update" issue="DBCP-505" due-to="Gary Gregory">

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/34cd3da6/src/main/java/org/apache/commons/dbcp2/DataSourceConnectionFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbcp2/DataSourceConnectionFactory.java b/src/main/java/org/apache/commons/dbcp2/DataSourceConnectionFactory.java
index 61ea019..050c3bb 100644
--- a/src/main/java/org/apache/commons/dbcp2/DataSourceConnectionFactory.java
+++ b/src/main/java/org/apache/commons/dbcp2/DataSourceConnectionFactory.java
@@ -84,4 +84,25 @@ public class DataSourceConnectionFactory implements ConnectionFactory {
         }
         return dataSource.getConnection(userName, Utils.toString(userPassword));
     }
+
+    /**
+     * @since 2.6.0
+     */
+    public DataSource getDataSource() {
+        return dataSource;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public String getUserName() {
+        return userName;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public char[] getUserPassword() {
+        return userPassword;
+    }
 }

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/34cd3da6/src/main/java/org/apache/commons/dbcp2/DriverConnectionFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbcp2/DriverConnectionFactory.java b/src/main/java/org/apache/commons/dbcp2/DriverConnectionFactory.java
index 42de432..ba88b76 100644
--- a/src/main/java/org/apache/commons/dbcp2/DriverConnectionFactory.java
+++ b/src/main/java/org/apache/commons/dbcp2/DriverConnectionFactory.java
@@ -53,6 +53,27 @@ public class DriverConnectionFactory implements ConnectionFactory {
         return driver.connect(connectionString, properties);
     }
 
+    /**
+     * @since 2.6.0
+     */
+    public String getConnectionString() {
+        return connectionString;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public Driver getDriver() {
+        return driver;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public Properties getProperties() {
+        return properties;
+    }
+
     @Override
     public String toString() {
         return this.getClass().getName() + " [" + String.valueOf(driver) + ";" + String.valueOf(connectionString) + ";"

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/34cd3da6/src/main/java/org/apache/commons/dbcp2/DriverManagerConnectionFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbcp2/DriverManagerConnectionFactory.java b/src/main/java/org/apache/commons/dbcp2/DriverManagerConnectionFactory.java
index c320b2a..24c506c 100644
--- a/src/main/java/org/apache/commons/dbcp2/DriverManagerConnectionFactory.java
+++ b/src/main/java/org/apache/commons/dbcp2/DriverManagerConnectionFactory.java
@@ -38,6 +38,14 @@ public class DriverManagerConnectionFactory implements ConnectionFactory {
         DriverManager.getDrivers();
     }
 
+    private final String connectionUri;
+
+    private final String userName;
+
+    private final String userPassword;
+
+    private final Properties properties;
+
     /**
      * Constructor for DriverManagerConnectionFactory.
      *
@@ -48,6 +56,8 @@ public class DriverManagerConnectionFactory implements ConnectionFactory {
     public DriverManagerConnectionFactory(final String connectionUri) {
         this.connectionUri = connectionUri;
         this.properties = new Properties();
+        this.userName = null;
+        this.userPassword = null;
     }
 
     /**
@@ -62,6 +72,8 @@ public class DriverManagerConnectionFactory implements ConnectionFactory {
     public DriverManagerConnectionFactory(final String connectionUri, final Properties properties) {
         this.connectionUri = connectionUri;
         this.properties = properties;
+        this.userName = null;
+        this.userPassword = null;
     }
 
     /**
@@ -79,6 +91,7 @@ public class DriverManagerConnectionFactory implements ConnectionFactory {
         this.connectionUri = connectionUri;
         this.userName = userName;
         this.userPassword = userPassword;
+        this.properties = null;
     }
 
     @Override
@@ -92,8 +105,24 @@ public class DriverManagerConnectionFactory implements ConnectionFactory {
         return DriverManager.getConnection(connectionUri, properties);
     }
 
-    private final String connectionUri;
-    private String userName;
-    private String userPassword;
-    private Properties properties;
+    /**
+     * @since 2.6.0
+     */
+    public String getConnectionUri() {
+        return connectionUri;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public Properties getProperties() {
+        return properties;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public String getUserName() {
+        return userName;
+    }
 }

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/34cd3da6/src/main/java/org/apache/commons/dbcp2/PoolableConnection.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbcp2/PoolableConnection.java b/src/main/java/org/apache/commons/dbcp2/PoolableConnection.java
index 046e3ab..e9924ae 100644
--- a/src/main/java/org/apache/commons/dbcp2/PoolableConnection.java
+++ b/src/main/java/org/apache/commons/dbcp2/PoolableConnection.java
@@ -329,4 +329,25 @@ public class PoolableConnection extends DelegatingConnection<Connection> impleme
         fatalSqlExceptionThrown |= isDisconnectionSqlException(e);
         super.handleException(e);
     }
+
+    /**
+     * @since 2.6.0
+     */
+    public ObjectNameWrapper getJmxObjectName() {
+        return jmxObjectName;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public Collection<String> getDisconnectionSqlCodes() {
+        return disconnectionSqlCodes;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public boolean isFastFailValidation() {
+        return fastFailValidation;
+    }
 }

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/34cd3da6/src/main/java/org/apache/commons/dbcp2/PoolableConnectionFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbcp2/PoolableConnectionFactory.java b/src/main/java/org/apache/commons/dbcp2/PoolableConnectionFactory.java
index 8b4bfaa..2aff632 100644
--- a/src/main/java/org/apache/commons/dbcp2/PoolableConnectionFactory.java
+++ b/src/main/java/org/apache/commons/dbcp2/PoolableConnectionFactory.java
@@ -468,7 +468,10 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
         return maxOpenPreparedStatements;
     }
 
-    protected boolean getCacheState() {
+    /**
+     * @since Made public in 2.6.0.
+     */
+    public boolean getCacheState() {
         return cacheState;
     }
 
@@ -506,4 +509,81 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
      * Internal constant to indicate the level is not set.
      */
     static final int UNKNOWN_TRANSACTIONISOLATION = -1;
+
+    /**
+     * @since 2.6.0
+     */
+    public ObjectName getDataSourceJmxObjectName() {
+        return dataSourceJmxObjectName;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public String getValidationQuery() {
+        return validationQuery;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public int getValidationQueryTimeoutSeconds() {
+        return validationQueryTimeoutSeconds;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public Collection<String> getConnectionInitSqls() {
+        return connectionInitSqls;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public Boolean getDefaultReadOnly() {
+        return defaultReadOnly;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public Boolean getDefaultAutoCommit() {
+        return defaultAutoCommit;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public int getDefaultTransactionIsolation() {
+        return defaultTransactionIsolation;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public String getDefaultCatalog() {
+        return defaultCatalog;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public String getDefaultSchema() {
+        return defaultSchema;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public long getMaxConnLifetimeMillis() {
+        return maxConnLifetimeMillis;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public Integer getDefaultQueryTimeoutSeconds() {
+        return defaultQueryTimeoutSeconds;
+    }
 }

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/34cd3da6/src/main/java/org/apache/commons/dbcp2/managed/DataSourceXAConnectionFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbcp2/managed/DataSourceXAConnectionFactory.java b/src/main/java/org/apache/commons/dbcp2/managed/DataSourceXAConnectionFactory.java
index a23fe0e..b89ca63 100644
--- a/src/main/java/org/apache/commons/dbcp2/managed/DataSourceXAConnectionFactory.java
+++ b/src/main/java/org/apache/commons/dbcp2/managed/DataSourceXAConnectionFactory.java
@@ -51,21 +51,6 @@ public class DataSourceXAConnectionFactory implements XAConnectionFactory {
      *            the transaction manager in which connections will be enlisted
      * @param xaDataSource
      *            the data source from which connections will be retrieved
-     * @param transactionSynchronizationRegistry
-     *            register with this TransactionSynchronizationRegistry
-     */
-    public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource, final TransactionSynchronizationRegistry transactionSynchronizationRegistry) {
-        this(transactionManager, xaDataSource, null, (char[]) null, transactionSynchronizationRegistry);
-    }
-
-    /**
-     * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections.
-     * The connections are enlisted into transactions using the specified transaction manager.
-     *
-     * @param transactionManager
-     *            the transaction manager in which connections will be enlisted
-     * @param xaDataSource
-     *            the data source from which connections will be retrieved
      * @since 2.6.0
      */
     public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource) {
@@ -138,48 +123,18 @@ public class DataSourceXAConnectionFactory implements XAConnectionFactory {
     }
 
     /**
-     * Gets the user name used to authenticate new connections.
-     *
-     * @return the user name or null if unauthenticated connections are used
-     */
-    public String getUsername() {
-        return userName;
-    }
-
-    /**
-     * Sets the user name used to authenticate new connections.
-     *
-     * @param userName
-     *            the user name used for authenticating the connection or null for unauthenticated
-     */
-    public void setUsername(final String userName) {
-        this.userName = userName;
-    }
-
-    /**
-     * Sets the password used to authenticate new connections.
-     *
-     * @param userPassword
-     *            the password used for authenticating the connection or null for unauthenticated.
-     * @since 2.4.0
-     */
-    public void setPassword(final char[] userPassword) {
-        this.userPassword = userPassword;
-    }
-
-    /**
-     * Sets the password used to authenticate new connections.
+     * Creates an DataSourceXAConnectionFactory which uses the specified XADataSource to create database connections.
+     * The connections are enlisted into transactions using the specified transaction manager.
      *
-     * @param userPassword
-     *            the password used for authenticating the connection or null for unauthenticated
+     * @param transactionManager
+     *            the transaction manager in which connections will be enlisted
+     * @param xaDataSource
+     *            the data source from which connections will be retrieved
+     * @param transactionSynchronizationRegistry
+     *            register with this TransactionSynchronizationRegistry
      */
-    public void setPassword(final String userPassword) {
-        this.userPassword = Utils.toCharArray(userPassword);
-    }
-
-    @Override
-    public TransactionRegistry getTransactionRegistry() {
-        return transactionRegistry;
+    public DataSourceXAConnectionFactory(final TransactionManager transactionManager, final XADataSource xaDataSource, final TransactionSynchronizationRegistry transactionSynchronizationRegistry) {
+        this(transactionManager, xaDataSource, null, (char[]) null, transactionSynchronizationRegistry);
     }
 
     @Override
@@ -224,4 +179,69 @@ public class DataSourceXAConnectionFactory implements XAConnectionFactory {
 
         return connection;
     }
+
+    @Override
+    public TransactionRegistry getTransactionRegistry() {
+        return transactionRegistry;
+    }
+
+    /**
+     * Gets the user name used to authenticate new connections.
+     *
+     * @return the user name or null if unauthenticated connections are used
+     * @deprecated Use {@link #getUserName()}.
+     */
+    @Deprecated
+    public String getUsername() {
+        return userName;
+    }
+
+    /**
+     * Gets the user name used to authenticate new connections.
+     *
+     * @return the user name or null if unauthenticated connections are used
+     * @since 2.6.0
+     */
+    public String getUserName() {
+        return userName;
+    }
+
+    public char[] getUserPassword() {
+        return userPassword;
+    }
+
+    public XADataSource getXaDataSource() {
+        return xaDataSource;
+    }
+
+    /**
+     * Sets the password used to authenticate new connections.
+     *
+     * @param userPassword
+     *            the password used for authenticating the connection or null for unauthenticated.
+     * @since 2.4.0
+     */
+    public void setPassword(final char[] userPassword) {
+        this.userPassword = userPassword;
+    }
+
+    /**
+     * Sets the password used to authenticate new connections.
+     *
+     * @param userPassword
+     *            the password used for authenticating the connection or null for unauthenticated
+     */
+    public void setPassword(final String userPassword) {
+        this.userPassword = Utils.toCharArray(userPassword);
+    }
+
+    /**
+     * Sets the user name used to authenticate new connections.
+     *
+     * @param userName
+     *            the user name used for authenticating the connection or null for unauthenticated
+     */
+    public void setUsername(final String userName) {
+        this.userName = userName;
+    }
 }

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/34cd3da6/src/main/java/org/apache/commons/dbcp2/managed/LocalXAConnectionFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbcp2/managed/LocalXAConnectionFactory.java b/src/main/java/org/apache/commons/dbcp2/managed/LocalXAConnectionFactory.java
index 1eb3c0e..990aab1 100644
--- a/src/main/java/org/apache/commons/dbcp2/managed/LocalXAConnectionFactory.java
+++ b/src/main/java/org/apache/commons/dbcp2/managed/LocalXAConnectionFactory.java
@@ -35,45 +35,6 @@ import java.util.Objects;
  * @since 2.0
  */
 public class LocalXAConnectionFactory implements XAConnectionFactory {
-    private final TransactionRegistry transactionRegistry;
-    private final ConnectionFactory connectionFactory;
-
-    /**
-     * Creates an LocalXAConnectionFactory which uses the specified connection factory to create database connections.
-     * The connections are enlisted into transactions using the specified transaction manager.
-     *
-     * @param transactionManager
-     *            the transaction manager in which connections will be enlisted
-     * @param connectionFactory
-     *            the connection factory from which connections will be retrieved
-     */
-    public LocalXAConnectionFactory(final TransactionManager transactionManager,
-            final ConnectionFactory connectionFactory) {
-        Objects.requireNonNull(transactionManager, "transactionManager is null");
-        Objects.requireNonNull(connectionFactory, "connectionFactory is null");
-        this.transactionRegistry = new TransactionRegistry(transactionManager);
-        this.connectionFactory = connectionFactory;
-    }
-
-    @Override
-    public TransactionRegistry getTransactionRegistry() {
-        return transactionRegistry;
-    }
-
-    @Override
-    public Connection createConnection() throws SQLException {
-        // create a new connection
-        final Connection connection = connectionFactory.createConnection();
-
-        // create a XAResource to manage the connection during XA transactions
-        final XAResource xaResource = new LocalXAResource(connection);
-
-        // register the xa resource for the connection
-        transactionRegistry.registerConnection(connection, xaResource);
-
-        return connection;
-    }
-
     /**
      * LocalXAResource is a fake XAResource for non-XA connections. When a transaction is started the connection
      * auto-commit is turned off. When the connection is committed or rolled back, the commit or rollback method is
@@ -97,61 +58,44 @@ public class LocalXAConnectionFactory implements XAConnectionFactory {
         }
 
         /**
-         * Gets the current xid of the transaction branch associated with this XAResource.
-         *
-         * @return the current xid of the transaction branch associated with this XAResource.
-         */
-        public synchronized Xid getXid() {
-            return currentXid;
-        }
-
-        /**
-         * Signals that a the connection has been enrolled in a transaction. This method saves off the current auto
-         * commit flag, and then disables auto commit. The original auto commit setting is restored when the transaction
-         * completes.
+         * Commits the transaction and restores the original auto commit setting.
          *
          * @param xid
          *            the id of the transaction branch for this connection
          * @param flag
-         *            either XAResource.TMNOFLAGS or XAResource.TMRESUME
+         *            ignored
          * @throws XAException
-         *             if the connection is already enlisted in another transaction, or if auto-commit could not be
-         *             disabled
+         *             if connection.commit() throws a SQLException
          */
         @Override
-        public synchronized void start(final Xid xid, final int flag) throws XAException {
-            if (flag == XAResource.TMNOFLAGS) {
-                // first time in this transaction
+        public synchronized void commit(final Xid xid, final boolean flag) throws XAException {
+            Objects.requireNonNull(xid, "xid is null");
+            if (this.currentXid == null) {
+                throw new XAException("There is no current transaction");
+            }
+            if (!this.currentXid.equals(xid)) {
+                throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid);
+            }
 
-                // make sure we aren't already in another tx
-                if (this.currentXid != null) {
-                    throw new XAException("Already enlisted in another transaction with xid " + xid);
+            try {
+                // make sure the connection isn't already closed
+                if (connection.isClosed()) {
+                    throw new XAException("Connection is closed");
                 }
 
-                // save off the current auto commit flag so it can be restored after the transaction completes
-                try {
-                    originalAutoCommit = connection.getAutoCommit();
-                } catch (final SQLException ignored) {
-                    // no big deal, just assume it was off
-                    originalAutoCommit = true;
+                // A read only connection should not be committed
+                if (!connection.isReadOnly()) {
+                    connection.commit();
                 }
-
-                // update the auto commit flag
+            } catch (final SQLException e) {
+                throw (XAException) new XAException().initCause(e);
+            } finally {
                 try {
-                    connection.setAutoCommit(false);
+                    connection.setAutoCommit(originalAutoCommit);
                 } catch (final SQLException e) {
-                    throw (XAException) new XAException("Count not turn off auto commit for a XA transaction")
-                            .initCause(e);
-                }
-
-                this.currentXid = xid;
-            } else if (flag == XAResource.TMRESUME) {
-                if (!xid.equals(this.currentXid)) {
-                    throw new XAException("Attempting to resume in different transaction: expected " + this.currentXid
-                            + ", but was " + xid);
+                    // ignore
                 }
-            } else {
-                throw new XAException("Unknown start flag " + flag);
+                this.currentXid = null;
             }
         }
 
@@ -178,6 +122,50 @@ public class LocalXAConnectionFactory implements XAConnectionFactory {
         }
 
         /**
+         * Clears the currently associated transaction if it is the specified xid.
+         *
+         * @param xid
+         *            the id of the transaction to forget
+         */
+        @Override
+        public synchronized void forget(final Xid xid) {
+            if (xid != null && xid.equals(currentXid)) {
+                currentXid = null;
+            }
+        }
+
+        /**
+         * Always returns 0 since we have no way to set a transaction timeout on a JDBC connection.
+         *
+         * @return always 0
+         */
+        @Override
+        public int getTransactionTimeout() {
+            return 0;
+        }
+
+        /**
+         * Gets the current xid of the transaction branch associated with this XAResource.
+         *
+         * @return the current xid of the transaction branch associated with this XAResource.
+         */
+        public synchronized Xid getXid() {
+            return currentXid;
+        }
+
+        /**
+         * Returns true if the specified XAResource == this XAResource.
+         *
+         * @param xaResource
+         *            the XAResource to test
+         * @return true if the specified XAResource == this XAResource; false otherwise
+         */
+        @Override
+        public boolean isSameRM(final XAResource xaResource) {
+            return this == xaResource;
+        }
+
+        /**
          * This method does nothing since the LocalXAConnection does not support two-phase-commit. This method will
          * return XAResource.XA_RDONLY if the connection isReadOnly(). This assumes that the physical connection is
          * wrapped with a proxy that prevents an application from changing the read-only flag while enrolled in a
@@ -209,45 +197,16 @@ public class LocalXAConnectionFactory implements XAConnectionFactory {
         }
 
         /**
-         * Commits the transaction and restores the original auto commit setting.
+         * Always returns a zero length Xid array. The LocalXAConnectionFactory can not support recovery, so no xids
+         * will ever be found.
          *
-         * @param xid
-         *            the id of the transaction branch for this connection
          * @param flag
-         *            ignored
-         * @throws XAException
-         *             if connection.commit() throws a SQLException
+         *            ignored since recovery is not supported
+         * @return always a zero length Xid array.
          */
         @Override
-        public synchronized void commit(final Xid xid, final boolean flag) throws XAException {
-            Objects.requireNonNull(xid, "xid is null");
-            if (this.currentXid == null) {
-                throw new XAException("There is no current transaction");
-            }
-            if (!this.currentXid.equals(xid)) {
-                throw new XAException("Invalid Xid: expected " + this.currentXid + ", but was " + xid);
-            }
-
-            try {
-                // make sure the connection isn't already closed
-                if (connection.isClosed()) {
-                    throw new XAException("Connection is closed");
-                }
-
-                // A read only connection should not be committed
-                if (!connection.isReadOnly()) {
-                    connection.commit();
-                }
-            } catch (final SQLException e) {
-                throw (XAException) new XAException().initCause(e);
-            } finally {
-                try {
-                    connection.setAutoCommit(originalAutoCommit);
-                } catch (final SQLException e) {
-                    // ignore
-                }
-                this.currentXid = null;
-            }
+        public Xid[] recover(final int flag) {
+            return new Xid[0];
         }
 
         /**
@@ -280,64 +239,112 @@ public class LocalXAConnectionFactory implements XAConnectionFactory {
         }
 
         /**
-         * Returns true if the specified XAResource == this XAResource.
+         * Always returns false since we have no way to set a transaction timeout on a JDBC connection.
          *
-         * @param xaResource
-         *            the XAResource to test
-         * @return true if the specified XAResource == this XAResource; false otherwise
+         * @param transactionTimeout
+         *            ignored since we have no way to set a transaction timeout on a JDBC connection
+         * @return always false
          */
         @Override
-        public boolean isSameRM(final XAResource xaResource) {
-            return this == xaResource;
+        public boolean setTransactionTimeout(final int transactionTimeout) {
+            return false;
         }
 
         /**
-         * Clears the currently associated transaction if it is the specified xid.
+         * Signals that a the connection has been enrolled in a transaction. This method saves off the current auto
+         * commit flag, and then disables auto commit. The original auto commit setting is restored when the transaction
+         * completes.
          *
          * @param xid
-         *            the id of the transaction to forget
+         *            the id of the transaction branch for this connection
+         * @param flag
+         *            either XAResource.TMNOFLAGS or XAResource.TMRESUME
+         * @throws XAException
+         *             if the connection is already enlisted in another transaction, or if auto-commit could not be
+         *             disabled
          */
         @Override
-        public synchronized void forget(final Xid xid) {
-            if (xid != null && xid.equals(currentXid)) {
-                currentXid = null;
+        public synchronized void start(final Xid xid, final int flag) throws XAException {
+            if (flag == XAResource.TMNOFLAGS) {
+                // first time in this transaction
+
+                // make sure we aren't already in another tx
+                if (this.currentXid != null) {
+                    throw new XAException("Already enlisted in another transaction with xid " + xid);
+                }
+
+                // save off the current auto commit flag so it can be restored after the transaction completes
+                try {
+                    originalAutoCommit = connection.getAutoCommit();
+                } catch (final SQLException ignored) {
+                    // no big deal, just assume it was off
+                    originalAutoCommit = true;
+                }
+
+                // update the auto commit flag
+                try {
+                    connection.setAutoCommit(false);
+                } catch (final SQLException e) {
+                    throw (XAException) new XAException("Count not turn off auto commit for a XA transaction")
+                            .initCause(e);
+                }
+
+                this.currentXid = xid;
+            } else if (flag == XAResource.TMRESUME) {
+                if (!xid.equals(this.currentXid)) {
+                    throw new XAException("Attempting to resume in different transaction: expected " + this.currentXid
+                            + ", but was " + xid);
+                }
+            } else {
+                throw new XAException("Unknown start flag " + flag);
             }
         }
+    }
+    private final TransactionRegistry transactionRegistry;
 
-        /**
-         * Always returns a zero length Xid array. The LocalXAConnectionFactory can not support recovery, so no xids
-         * will ever be found.
-         *
-         * @param flag
-         *            ignored since recovery is not supported
-         * @return always a zero length Xid array.
-         */
-        @Override
-        public Xid[] recover(final int flag) {
-            return new Xid[0];
-        }
+    private final ConnectionFactory connectionFactory;
 
-        /**
-         * Always returns 0 since we have no way to set a transaction timeout on a JDBC connection.
-         *
-         * @return always 0
-         */
-        @Override
-        public int getTransactionTimeout() {
-            return 0;
-        }
+    /**
+     * Creates an LocalXAConnectionFactory which uses the specified connection factory to create database connections.
+     * The connections are enlisted into transactions using the specified transaction manager.
+     *
+     * @param transactionManager
+     *            the transaction manager in which connections will be enlisted
+     * @param connectionFactory
+     *            the connection factory from which connections will be retrieved
+     */
+    public LocalXAConnectionFactory(final TransactionManager transactionManager,
+            final ConnectionFactory connectionFactory) {
+        Objects.requireNonNull(transactionManager, "transactionManager is null");
+        Objects.requireNonNull(connectionFactory, "connectionFactory is null");
+        this.transactionRegistry = new TransactionRegistry(transactionManager);
+        this.connectionFactory = connectionFactory;
+    }
 
-        /**
-         * Always returns false since we have no way to set a transaction timeout on a JDBC connection.
-         *
-         * @param transactionTimeout
-         *            ignored since we have no way to set a transaction timeout on a JDBC connection
-         * @return always false
-         */
-        @Override
-        public boolean setTransactionTimeout(final int transactionTimeout) {
-            return false;
-        }
+    @Override
+    public Connection createConnection() throws SQLException {
+        // create a new connection
+        final Connection connection = connectionFactory.createConnection();
+
+        // create a XAResource to manage the connection during XA transactions
+        final XAResource xaResource = new LocalXAResource(connection);
+
+        // register the xa resource for the connection
+        transactionRegistry.registerConnection(connection, xaResource);
+
+        return connection;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public ConnectionFactory getConnectionFactory() {
+        return connectionFactory;
+    }
+
+    @Override
+    public TransactionRegistry getTransactionRegistry() {
+        return transactionRegistry;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/34cd3da6/src/main/java/org/apache/commons/dbcp2/managed/ManagedConnection.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbcp2/managed/ManagedConnection.java b/src/main/java/org/apache/commons/dbcp2/managed/ManagedConnection.java
index 111fc58..7c074e6 100644
--- a/src/main/java/org/apache/commons/dbcp2/managed/ManagedConnection.java
+++ b/src/main/java/org/apache/commons/dbcp2/managed/ManagedConnection.java
@@ -46,11 +46,25 @@ import java.util.concurrent.locks.ReentrantLock;
  */
 public class ManagedConnection<C extends Connection> extends DelegatingConnection<C> {
 
+    /**
+     * Delegates to {@link ManagedConnection#transactionComplete()} for transaction completion events.
+     *
+     * @since 2.0
+     */
+    protected class CompletionListener implements TransactionContextListener {
+        @Override
+        public void afterCompletion(final TransactionContext completedContext, final boolean committed) {
+            if (completedContext == transactionContext) {
+                transactionComplete();
+            }
+        }
+    }
     private final ObjectPool<C> pool;
     private final TransactionRegistry transactionRegistry;
     private final boolean accessToUnderlyingConnectionAllowed;
     private TransactionContext transactionContext;
     private boolean isSharedConnection;
+
     private final Lock lock;
 
     /**
@@ -81,6 +95,143 @@ public class ManagedConnection<C extends Connection> extends DelegatingConnectio
         updateTransactionStatus();
     }
 
+    @Override
+    public void close() throws SQLException {
+        if (!isClosedInternal()) {
+            // Don't actually close the connection if in a transaction. The
+            // connection will be closed by the transactionComplete method.
+            //
+            // DBCP-484 we need to make sure setClosedInternal(true) being
+            // invoked if transactionContext is not null as this value will
+            // be modified by the transactionComplete method which could run
+            // in the different thread with the transaction calling back.
+            lock.lock();
+            try {
+                if (transactionContext == null || transactionContext.isTransactionComplete()) {
+                    super.close();
+                }
+            } finally {
+                try {
+                    setClosedInternal(true);
+                } finally {
+                    lock.unlock();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void commit() throws SQLException {
+        if (transactionContext != null) {
+            throw new SQLException("Commit can not be set while enrolled in a transaction");
+        }
+        super.commit();
+    }
+
+    @Override
+    public C getDelegate() {
+        if (isAccessToUnderlyingConnectionAllowed()) {
+            return getDelegateInternal();
+        }
+        return null;
+    }
+
+    //
+    // The following methods can't be used while enlisted in a transaction
+    //
+
+    @Override
+    public Connection getInnermostDelegate() {
+        if (isAccessToUnderlyingConnectionAllowed()) {
+            return super.getInnermostDelegateInternal();
+        }
+        return null;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public TransactionContext getTransactionContext() {
+        return transactionContext;
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public TransactionRegistry getTransactionRegistry() {
+        return transactionRegistry;
+    }
+
+    /**
+     * If false, getDelegate() and getInnermostDelegate() will return null.
+     *
+     * @return if false, getDelegate() and getInnermostDelegate() will return null
+     */
+    public boolean isAccessToUnderlyingConnectionAllowed() {
+        return accessToUnderlyingConnectionAllowed;
+    }
+
+    //
+    // Methods for accessing the delegate connection
+    //
+
+    @Override
+    public void rollback() throws SQLException {
+        if (transactionContext != null) {
+            throw new SQLException("Commit can not be set while enrolled in a transaction");
+        }
+        super.rollback();
+    }
+
+    @Override
+    public void setAutoCommit(final boolean autoCommit) throws SQLException {
+        if (transactionContext != null) {
+            throw new SQLException("Auto-commit can not be set while enrolled in a transaction");
+        }
+        super.setAutoCommit(autoCommit);
+    }
+
+    @Override
+    public void setReadOnly(final boolean readOnly) throws SQLException {
+        if (transactionContext != null) {
+            throw new SQLException("Read-only can not be set while enrolled in a transaction");
+        }
+        super.setReadOnly(readOnly);
+    }
+
+    protected void transactionComplete() {
+        lock.lock();
+        try {
+            transactionContext.completeTransaction();
+        } finally {
+            lock.unlock();
+        }
+
+        // If we were using a shared connection, clear the reference now that
+        // the transaction has completed
+        if (isSharedConnection) {
+            setDelegate(null);
+            isSharedConnection = false;
+        }
+
+        // If this connection was closed during the transaction and there is
+        // still a delegate present close it
+        final Connection delegate = getDelegateInternal();
+        if (isClosedInternal() && delegate != null) {
+            try {
+                setDelegate(null);
+
+                if (!delegate.isClosed()) {
+                    delegate.close();
+                }
+            } catch (final SQLException ignored) {
+                // Not a whole lot we can do here as connection is closed
+                // and this is a transaction callback so there is no
+                // way to report the error.
+            }
+        }
+    }
+
     private void updateTransactionStatus() throws SQLException {
         // if there is a is an active transaction context, assure the transaction context hasn't changed
         if (transactionContext != null && !transactionContext.isTransactionComplete()) {
@@ -171,141 +322,4 @@ public class ManagedConnection<C extends Connection> extends DelegatingConnectio
         // connection
         clearCachedState();
     }
-
-    @Override
-    public void close() throws SQLException {
-        if (!isClosedInternal()) {
-            // Don't actually close the connection if in a transaction. The
-            // connection will be closed by the transactionComplete method.
-            //
-            // DBCP-484 we need to make sure setClosedInternal(true) being
-            // invoked if transactionContext is not null as this value will
-            // be modified by the transactionComplete method which could run
-            // in the different thread with the transaction calling back.
-            lock.lock();
-            try {
-                if (transactionContext == null || transactionContext.isTransactionComplete()) {
-                    super.close();
-                }
-            } finally {
-                try {
-                    setClosedInternal(true);
-                } finally {
-                    lock.unlock();
-                }
-            }
-        }
-    }
-
-    /**
-     * Delegates to {@link ManagedConnection#transactionComplete()} for transaction completion events.
-     *
-     * @since 2.0
-     */
-    protected class CompletionListener implements TransactionContextListener {
-        @Override
-        public void afterCompletion(final TransactionContext completedContext, final boolean committed) {
-            if (completedContext == transactionContext) {
-                transactionComplete();
-            }
-        }
-    }
-
-    protected void transactionComplete() {
-        lock.lock();
-        try {
-            transactionContext.completeTransaction();
-        } finally {
-            lock.unlock();
-        }
-
-        // If we were using a shared connection, clear the reference now that
-        // the transaction has completed
-        if (isSharedConnection) {
-            setDelegate(null);
-            isSharedConnection = false;
-        }
-
-        // If this connection was closed during the transaction and there is
-        // still a delegate present close it
-        final Connection delegate = getDelegateInternal();
-        if (isClosedInternal() && delegate != null) {
-            try {
-                setDelegate(null);
-
-                if (!delegate.isClosed()) {
-                    delegate.close();
-                }
-            } catch (final SQLException ignored) {
-                // Not a whole lot we can do here as connection is closed
-                // and this is a transaction callback so there is no
-                // way to report the error.
-            }
-        }
-    }
-
-    //
-    // The following methods can't be used while enlisted in a transaction
-    //
-
-    @Override
-    public void setAutoCommit(final boolean autoCommit) throws SQLException {
-        if (transactionContext != null) {
-            throw new SQLException("Auto-commit can not be set while enrolled in a transaction");
-        }
-        super.setAutoCommit(autoCommit);
-    }
-
-    @Override
-    public void commit() throws SQLException {
-        if (transactionContext != null) {
-            throw new SQLException("Commit can not be set while enrolled in a transaction");
-        }
-        super.commit();
-    }
-
-    @Override
-    public void rollback() throws SQLException {
-        if (transactionContext != null) {
-            throw new SQLException("Commit can not be set while enrolled in a transaction");
-        }
-        super.rollback();
-    }
-
-    @Override
-    public void setReadOnly(final boolean readOnly) throws SQLException {
-        if (transactionContext != null) {
-            throw new SQLException("Read-only can not be set while enrolled in a transaction");
-        }
-        super.setReadOnly(readOnly);
-    }
-
-    //
-    // Methods for accessing the delegate connection
-    //
-
-    /**
-     * If false, getDelegate() and getInnermostDelegate() will return null.
-     *
-     * @return if false, getDelegate() and getInnermostDelegate() will return null
-     */
-    public boolean isAccessToUnderlyingConnectionAllowed() {
-        return accessToUnderlyingConnectionAllowed;
-    }
-
-    @Override
-    public C getDelegate() {
-        if (isAccessToUnderlyingConnectionAllowed()) {
-            return getDelegateInternal();
-        }
-        return null;
-    }
-
-    @Override
-    public Connection getInnermostDelegate() {
-        if (isAccessToUnderlyingConnectionAllowed()) {
-            return super.getInnermostDelegateInternal();
-        }
-        return null;
-    }
 }

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/34cd3da6/src/main/java/org/apache/commons/dbcp2/managed/ManagedDataSource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbcp2/managed/ManagedDataSource.java b/src/main/java/org/apache/commons/dbcp2/managed/ManagedDataSource.java
index edd9ae7..e19464d 100644
--- a/src/main/java/org/apache/commons/dbcp2/managed/ManagedDataSource.java
+++ b/src/main/java/org/apache/commons/dbcp2/managed/ManagedDataSource.java
@@ -52,6 +52,25 @@ public class ManagedDataSource<C extends Connection> extends PoolingDataSource<C
         this.transactionRegistry = transactionRegistry;
     }
 
+    @Override
+    public Connection getConnection() throws SQLException {
+        if (getPool() == null) {
+            throw new IllegalStateException("Pool has not been set");
+        }
+        if (transactionRegistry == null) {
+            throw new IllegalStateException("TransactionRegistry has not been set");
+        }
+
+        return new ManagedConnection<>(getPool(), transactionRegistry, isAccessToUnderlyingConnectionAllowed());
+    }
+
+    /**
+     * @since 2.6.0
+     */
+    public TransactionRegistry getTransactionRegistry() {
+        return transactionRegistry;
+    }
+
     /**
      * Sets the transaction registry from the XAConnectionFactory used to create the pool. The transaction registry can
      * only be set once using either a connector or this setter method.
@@ -67,16 +86,4 @@ public class ManagedDataSource<C extends Connection> extends PoolingDataSource<C
 
         this.transactionRegistry = transactionRegistry;
     }
-
-    @Override
-    public Connection getConnection() throws SQLException {
-        if (getPool() == null) {
-            throw new IllegalStateException("Pool has not been set");
-        }
-        if (transactionRegistry == null) {
-            throw new IllegalStateException("TransactionRegistry has not been set");
-        }
-
-        return new ManagedConnection<>(getPool(), transactionRegistry, isAccessToUnderlyingConnectionAllowed());
-    }
 }

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/34cd3da6/src/main/java/org/apache/commons/dbcp2/managed/PoolableManagedConnection.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbcp2/managed/PoolableManagedConnection.java b/src/main/java/org/apache/commons/dbcp2/managed/PoolableManagedConnection.java
index cee7090..5055e61 100644
--- a/src/main/java/org/apache/commons/dbcp2/managed/PoolableManagedConnection.java
+++ b/src/main/java/org/apache/commons/dbcp2/managed/PoolableManagedConnection.java
@@ -71,6 +71,13 @@ public class PoolableManagedConnection extends PoolableConnection {
     }
 
     /**
+     * @since 2.6.0
+     */
+    public TransactionRegistry getTransactionRegistry() {
+        return transactionRegistry;
+    }
+
+    /**
      * Actually close the underlying connection.
      */
     @Override

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/34cd3da6/src/main/java/org/apache/commons/dbcp2/managed/PoolableManagedConnectionFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbcp2/managed/PoolableManagedConnectionFactory.java b/src/main/java/org/apache/commons/dbcp2/managed/PoolableManagedConnectionFactory.java
index 5eb8b94..e62b65d 100644
--- a/src/main/java/org/apache/commons/dbcp2/managed/PoolableManagedConnectionFactory.java
+++ b/src/main/java/org/apache/commons/dbcp2/managed/PoolableManagedConnectionFactory.java
@@ -57,6 +57,13 @@ public class PoolableManagedConnectionFactory extends PoolableConnectionFactory
     }
 
     /**
+     * @since 2.6.0
+     */
+    public TransactionRegistry getTransactionRegistry() {
+        return transactionRegistry;
+    }
+
+    /**
      * Uses the configured XAConnectionFactory to create a {@link PoolableManagedConnection}. Throws
      * <code>IllegalStateException</code> if the connection factory returns null. Also initializes the connection using
      * configured initialization SQL (if provided) and sets up a prepared statement pool associated with the