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 <garydgreg...@gmail.com> Authored: Tue Nov 13 11:53:00 2018 -0700 Committer: Gary Gregory <garydgreg...@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