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 c3187a4498c3128c28d6bf57da0f36e24c176eb6 Author: Richard Zowalla <[email protected]> AuthorDate: Thu Jun 23 11:15:48 2022 +0200 TOMEE-3800 - DBCP 2.9.0 --- .../resource/jdbc/dbcp/BasicManagedDataSource.java | 63 +++++++++++++++++++- .../resource/jdbc/dbcp/DbcpManagedDataSource.java | 12 ++++ .../jdbc/dbcp/DbcpTransactionRegistry.java | 69 ++++++++++++++++++++++ pom.xml | 2 +- 4 files changed, 144 insertions(+), 2 deletions(-) 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..09369d3333 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); + } + } + + public 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..9b23c231fd 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); } } + + public 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..011176e716 --- /dev/null +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/DbcpTransactionRegistry.java @@ -0,0 +1,69 @@ +/* + * 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/pom.xml b/pom.xml index 672f384bb9..c52b25a3e4 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>
