This is an automated email from the ASF dual-hosted git repository. rzo1 pushed a commit to branch TOMEE-3800 in repository https://gitbox.apache.org/repos/asf/tomee.git
commit 9d4b163acbe57f10f653617d3ee99dd95b37b631 Author: Richard Zowalla <[email protected]> AuthorDate: Thu Jun 23 11:15:48 2022 +0200 TOMEE-3800 - DBCP 2.9.0 --- boms/tomee-microprofile/pom.xml | 2 +- boms/tomee-plume/pom.xml | 2 +- boms/tomee-plus/pom.xml | 2 +- boms/tomee-webprofile/pom.xml | 2 +- .../resource/jdbc/dbcp/BasicManagedDataSource.java | 63 ++++++++++++++++++++- .../resource/jdbc/dbcp/DbcpManagedDataSource.java | 12 ++++ .../jdbc/dbcp/DbcpTransactionRegistry.java | 66 ++++++++++++++++++++++ .../apache/openejb/resource/jdbc/XAPoolTest.java | 2 +- pom.xml | 2 +- 9 files changed, 146 insertions(+), 7 deletions(-) diff --git a/boms/tomee-microprofile/pom.xml b/boms/tomee-microprofile/pom.xml index 9758baf2bc..7b52639dbe 100644 --- a/boms/tomee-microprofile/pom.xml +++ b/boms/tomee-microprofile/pom.xml @@ -279,7 +279,7 @@ <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> - <version>2.3.0</version> + <version>2.9.0</version> <exclusions> <exclusion> <artifactId>*</artifactId> diff --git a/boms/tomee-plume/pom.xml b/boms/tomee-plume/pom.xml index 57febeeb94..c7e5f94486 100644 --- a/boms/tomee-plume/pom.xml +++ b/boms/tomee-plume/pom.xml @@ -356,7 +356,7 @@ <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> - <version>2.3.0</version> + <version>2.9.0</version> <exclusions> <exclusion> <artifactId>*</artifactId> diff --git a/boms/tomee-plus/pom.xml b/boms/tomee-plus/pom.xml index 3ebcbfd824..1fd23afca0 100644 --- a/boms/tomee-plus/pom.xml +++ b/boms/tomee-plus/pom.xml @@ -367,7 +367,7 @@ <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> - <version>2.3.0</version> + <version>2.9.0</version> <exclusions> <exclusion> <artifactId>*</artifactId> diff --git a/boms/tomee-webprofile/pom.xml b/boms/tomee-webprofile/pom.xml index 8ad8690d90..4839cc3ff9 100644 --- a/boms/tomee-webprofile/pom.xml +++ b/boms/tomee-webprofile/pom.xml @@ -180,7 +180,7 @@ <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> - <version>2.3.0</version> + <version>2.9.0</version> <exclusions> <exclusion> <artifactId>*</artifactId> diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/BasicManagedDataSource.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/BasicManagedDataSource.java index f2ff9ffde6..bc8469e0c8 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/BasicManagedDataSource.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/BasicManagedDataSource.java @@ -20,9 +20,13 @@ package org.apache.openejb.resource.jdbc.dbcp; import org.apache.commons.dbcp2.ConnectionFactory; import org.apache.commons.dbcp2.PoolableConnection; import org.apache.commons.dbcp2.PoolingDataSource; +import org.apache.commons.dbcp2.Utils; +import org.apache.commons.dbcp2.managed.DataSourceXAConnectionFactory; +import org.apache.commons.dbcp2.managed.LocalXAConnectionFactory; import org.apache.commons.dbcp2.managed.ManagedConnection; import org.apache.commons.dbcp2.managed.ManagedDataSource; import org.apache.commons.dbcp2.managed.TransactionRegistry; +import org.apache.commons.dbcp2.managed.XAConnectionFactory; import org.apache.openejb.OpenEJB; import org.apache.openejb.cipher.PasswordCipher; import org.apache.openejb.cipher.PasswordCipherFactory; @@ -37,9 +41,11 @@ import org.apache.openejb.util.reflection.Reflections; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.sql.DataSource; +import javax.sql.XADataSource; import java.io.File; import java.io.ObjectStreamException; import java.io.Serializable; +import java.lang.reflect.Field; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; @@ -130,9 +136,64 @@ public class BasicManagedDataSource extends org.apache.commons.dbcp2.managed.Bas // no-op } } - return super.createConnectionFactory(); + + if (getTransactionManager() == null) { + throw new SQLException("Transaction manager must be set before a connection can be created"); + } else if (getXADataSource() == null) { + ConnectionFactory connectionFactory = super.createConnectionFactory(); + XAConnectionFactory xaConnectionFactory = new LocalXAConnectionFactory(this.getTransactionManager(), this.getTransactionSynchronizationRegistry(), connectionFactory); + setTransactionRegistry(xaConnectionFactory, new DbcpTransactionRegistry(getTransactionManager())); + setTransactionRegistry(xaConnectionFactory.getTransactionRegistry()); + return xaConnectionFactory; + } else { + XADataSource xaDataSourceInstance = getXaDataSourceInstance(); + if (xaDataSourceInstance == null) { + Class xaDataSourceClass; + + String message; + try { + xaDataSourceClass = Class.forName(xaDataSource); + } catch (Exception var5) { + message = "Cannot load XA data source class '" + xaDataSource + "'"; + throw new SQLException(message, var5); + } + + try { + setXaDataSourceInstance((XADataSource) xaDataSourceClass.getConstructor().newInstance()); + } catch (Exception var4) { + message = "Cannot create XA data source of class '" + xaDataSource + "'"; + throw new SQLException(message, var4); + } + } + + XAConnectionFactory xaConnectionFactory = new DataSourceXAConnectionFactory(this.getTransactionManager(), getXaDataSourceInstance(), this.getUsername(), Utils.toCharArray(this.getPassword()), this.getTransactionSynchronizationRegistry()); + setTransactionRegistry(xaConnectionFactory, new DbcpTransactionRegistry(getTransactionManager())); + setTransactionRegistry(xaConnectionFactory.getTransactionRegistry()); + return xaConnectionFactory; + } } + private void setTransactionRegistry(final TransactionRegistry registry) { + try { + final Field field = org.apache.commons.dbcp2.managed.BasicManagedDataSource.class.getDeclaredField("transactionRegistry"); + field.setAccessible(true); + field.set(this, registry); + } catch (final Throwable e) { + throw new IllegalStateException(e); + } + } + + private void setTransactionRegistry(XAConnectionFactory xaConnectionFactory, final TransactionRegistry registry) { + try { + final Field field = xaConnectionFactory.getClass().getDeclaredField("transactionRegistry"); + field.setAccessible(true); + field.set(xaConnectionFactory, registry); + } catch (final Throwable e) { + throw new IllegalStateException(e); + } + } + + private void setJndiXaDataSource(final String xaDataSource) { setXaDataSourceInstance( // proxy cause we don't know if this datasource was created before or not the delegate XADataSourceResource.proxy(getDriverClassLoader() != null ? getDriverClassLoader() : Thread.currentThread().getContextClassLoader(), xaDataSource)); diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/DbcpManagedDataSource.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/DbcpManagedDataSource.java index 5d6025c833..afd671481a 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/DbcpManagedDataSource.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/DbcpManagedDataSource.java @@ -59,6 +59,7 @@ public class DbcpManagedDataSource extends BasicManagedDataSource { // Create the XAConectionFactory using the XA data source final XADataSource xaDataSourceInstance = (XADataSource) ds; final XAConnectionFactory xaConnectionFactory = new DataSourceXAConnectionFactory(getTransactionManager(), xaDataSourceInstance, getUsername(), getPassword()); + setTransactionRegistry(xaConnectionFactory, new DbcpTransactionRegistry(getTransactionManager())); setTransactionRegistry(xaConnectionFactory.getTransactionRegistry()); return xaConnectionFactory; @@ -67,6 +68,7 @@ public class DbcpManagedDataSource extends BasicManagedDataSource { // If xa data source is not specified a DriverConnectionFactory is created and wrapped with a LocalXAConnectionFactory final ConnectionFactory connectionFactory = new DataSourceConnectionFactory(DataSource.class.cast(ds), getUsername(), getPassword()); final XAConnectionFactory xaConnectionFactory = new LocalXAConnectionFactory(getTransactionManager(), connectionFactory); + setTransactionRegistry(xaConnectionFactory, new DbcpTransactionRegistry(getTransactionManager())); setTransactionRegistry(xaConnectionFactory.getTransactionRegistry()); return xaConnectionFactory; } @@ -80,4 +82,14 @@ public class DbcpManagedDataSource extends BasicManagedDataSource { throw new IllegalStateException(e); } } + + private void setTransactionRegistry(XAConnectionFactory xaConnectionFactory, final TransactionRegistry registry) { + try { + final Field field = xaConnectionFactory.getClass().getDeclaredField("transactionRegistry"); + field.setAccessible(true); + field.set(xaConnectionFactory, registry); + } catch (final Throwable e) { + throw new IllegalStateException(e); + } + } } diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/DbcpTransactionRegistry.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/DbcpTransactionRegistry.java new file mode 100644 index 0000000000..d298acd628 --- /dev/null +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/DbcpTransactionRegistry.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.openejb.resource.jdbc.dbcp; + +import org.apache.commons.dbcp2.managed.TransactionContext; + +import javax.transaction.Status; +import javax.transaction.SystemException; +import javax.transaction.Transaction; +import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; +import java.sql.SQLException; +public class DbcpTransactionRegistry extends org.apache.commons.dbcp2.managed.TransactionRegistry { + + private TransactionManager transactionManager; + public DbcpTransactionRegistry(TransactionManager transactionManager) { + this(transactionManager, null); + } + public DbcpTransactionRegistry(TransactionManager transactionManager, TransactionSynchronizationRegistry transactionSynchronizationRegistry) { + super(transactionManager, transactionSynchronizationRegistry); + this.transactionManager = transactionManager; + } + + /** + * Gets the active TransactionContext or null if not Transaction is active. + * + * @return The active TransactionContext or null if no Transaction is active. + * @throws SQLException + * Thrown when an error occurs while fetching the transaction. + */ + public TransactionContext getActiveTransactionContext() throws SQLException { + Transaction transaction; + try { + transaction = transactionManager.getTransaction(); + + // was there a transaction? + if (transaction == null) { + return null; + } + + // is it active + final int status = transaction.getStatus(); + if (status != Status.STATUS_ACTIVE && status != Status.STATUS_MARKED_ROLLBACK) { + return null; + } + } catch (final SystemException e) { + throw new SQLException("Unable to determine current transaction ", e); + } + + return super.getActiveTransactionContext(); + } +} diff --git a/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/XAPoolTest.java b/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/XAPoolTest.java index 6de512878c..c457f631ce 100644 --- a/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/XAPoolTest.java +++ b/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/XAPoolTest.java @@ -94,7 +94,7 @@ public class XAPoolTest { final Connection connection = c.getMetaData().getConnection(); // just to do something and force the connection init assertThat(connection, instanceOf(ManagedConnection.class)); - assertTrue(connection.toString().contains("URL=jdbc:hsqldb:mem:dbcpxa, UserName=SA, HSQL Database Engine Driver")); + assertTrue(connection.toString().contains("URL=jdbc:hsqldb:mem:dbcpxa, HSQL Database Engine Driver")); } // here we close the connection so we are back in the initial state assertEquals(0, tds.getNumActive()); diff --git a/pom.xml b/pom.xml index 55117ad8ec..634a86062f 100644 --- a/pom.xml +++ b/pom.xml @@ -182,7 +182,7 @@ 'QuartzPersistenceForEJBTimersTest' is unable to obtain DB connection with commons-dbcp.version > 2.3.0 --> - <commons-dbcp.version>2.3.0</commons-dbcp.version> + <commons-dbcp.version>2.9.0</commons-dbcp.version> <commons-pool.version>2.11.1</commons-pool.version> <commons-collections.version>3.2.2</commons-collections.version> <commons-codec.version>1.15</commons-codec.version>
