Repository: commons-dbcp
Updated Branches:
  refs/heads/master ace3b46bf -> 70822f11d


[DBCP-514] Allow DBCP to register with a
TransactionSynchronizationRegistry for XA cases. Apply modified patch
that does not break binary compatibility. Bump up version from
2.5.1-SNAPSHOT to 2.6.0-SNAPSHOT since this patch adds new public APIs.

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

Branch: refs/heads/master
Commit: 70822f11d1a290a74f91fa688d73cf76650e3b4b
Parents: ace3b46
Author: Gary Gregory <ggreg...@apache.org>
Authored: Tue Jul 24 16:15:08 2018 -0600
Committer: Gary Gregory <ggreg...@apache.org>
Committed: Tue Jul 24 16:15:08 2018 -0600

----------------------------------------------------------------------
 pom.xml                                         |   2 +-
 src/changes/changes.xml                         |   7 +-
 .../dbcp2/managed/BasicManagedDataSource.java   |  26 ++
 .../managed/DataSourceXAConnectionFactory.java  |  47 ++-
 .../dbcp2/managed/TransactionContext.java       |  29 +-
 .../dbcp2/managed/TransactionRegistry.java      |  18 +-
 .../dbcp2/managed/TestSynchronizationOrder.java | 305 +++++++++++++++++++
 7 files changed, 424 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/70822f11/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index a36abbb..e6655e4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,7 +26,7 @@
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>commons-dbcp2</artifactId>
-  <version>2.5.1-SNAPSHOT</version>
+  <version>2.6.0-SNAPSHOT</version>
   <name>Apache Commons DBCP</name>
 
   <inceptionYear>2001</inceptionYear>

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/70822f11/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index dbe133b..c924411 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -60,7 +60,12 @@ The <action> type attribute can be add,update,fix,remove.
      -->
 
   <body>
-    <release version="2.5.0" date="2018-MM-DD" description="This is a minor 
release, including bug fixes and enhancements.">
+    <release version="2.6.0" date="2018-MM-DD" description="This is a minor 
release, including bug fixes and enhancements.">
+      <action dev="ggregory" type="add" issue="DBCP-514" due-to="Gary Gregory">
+        Allow DBCP to register with a TransactionSynchronizationRegistry for 
XA cases.
+      </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">
         Update Java requirement from version 7 to 8.
       </action>

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/70822f11/src/main/java/org/apache/commons/dbcp2/managed/BasicManagedDataSource.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/dbcp2/managed/BasicManagedDataSource.java 
b/src/main/java/org/apache/commons/dbcp2/managed/BasicManagedDataSource.java
index 723c621..769fe5d 100644
--- a/src/main/java/org/apache/commons/dbcp2/managed/BasicManagedDataSource.java
+++ b/src/main/java/org/apache/commons/dbcp2/managed/BasicManagedDataSource.java
@@ -26,6 +26,7 @@ import org.apache.commons.dbcp2.PoolingDataSource;
 import javax.sql.DataSource;
 import javax.sql.XADataSource;
 import javax.transaction.TransactionManager;
+import javax.transaction.TransactionSynchronizationRegistry;
 
 import java.sql.SQLException;
 
@@ -62,6 +63,9 @@ public class BasicManagedDataSource extends BasicDataSource {
     /** XA data source instance */
     private XADataSource xaDataSourceInstance;
 
+    /** Transaction Manager */
+    private transient TransactionSynchronizationRegistry 
transactionSynchronizationRegistry;
+
     /**
      * Gets the XADataSource instance used by the XAConnectionFactory.
      *
@@ -99,6 +103,16 @@ public class BasicManagedDataSource extends BasicDataSource 
{
     }
 
     /**
+     * Gets the optional TransactionSynchronizationRegistry.
+     *
+     * @return the TSR that can be used to register synchronizations.
+     * @since 2.6.0
+     */
+    public TransactionSynchronizationRegistry 
getTransactionSynchronizationRegistry() {
+        return transactionSynchronizationRegistry;
+    }
+
+    /**
      * Gets the transaction registry.
      *
      * @return the transaction registry associating XAResources with managed 
connections
@@ -118,6 +132,18 @@ public class BasicManagedDataSource extends 
BasicDataSource {
     }
 
     /**
+     * Sets the optional TransactionSynchronizationRegistry property.
+     *
+     * @param transactionSynchronizationRegistry
+     *            the TSR used to register synchronizations
+     * @since 2.6.0
+     */
+    public void setTransactionSynchronizationRegistry(
+            final TransactionSynchronizationRegistry 
transactionSynchronizationRegistry) {
+        this.transactionSynchronizationRegistry = 
transactionSynchronizationRegistry;
+    }
+
+    /**
      * Gets the optional XADataSource class name.
      *
      * @return the optional XADataSource class name

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/70822f11/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 661ea62..a23fe0e 100644
--- 
a/src/main/java/org/apache/commons/dbcp2/managed/DataSourceXAConnectionFactory.java
+++ 
b/src/main/java/org/apache/commons/dbcp2/managed/DataSourceXAConnectionFactory.java
@@ -23,6 +23,7 @@ import javax.sql.PooledConnection;
 import javax.sql.XAConnection;
 import javax.sql.XADataSource;
 import javax.transaction.TransactionManager;
+import javax.transaction.TransactionSynchronizationRegistry;
 import javax.transaction.xa.XAResource;
 
 import org.apache.commons.dbcp2.Utils;
@@ -50,9 +51,25 @@ 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) {
-        this(transactionManager, xaDataSource, null, (char[]) null);
+        this(transactionManager, xaDataSource, null, (char[]) null, null);
     }
 
     /**
@@ -70,9 +87,33 @@ public class DataSourceXAConnectionFactory implements 
XAConnectionFactory {
      */
     public DataSourceXAConnectionFactory(final TransactionManager 
transactionManager, final XADataSource xaDataSource,
             final String userName, final char[] userPassword) {
+        this(transactionManager, xaDataSource, userName, userPassword, null);
+    }
+
+    /**
+     * Creates an DataSourceXAConnectionFactory which uses the specified 
XADataSource to create database connections.
+     * The connections are enlisted into transactions using the specified 
transaction manager.
+     *
+     * @param transactionManager
+     *            the transaction manager in which connections will be enlisted
+     * @param xaDataSource
+     *            the data source from which connections will be retrieved
+     * @param userName
+     *            the user name used for authenticating new connections or 
null for unauthenticated
+     * @param userPassword
+     *            the password used for authenticating new connections
+     * @param transactionSynchronizationRegistry
+     *            register with this TransactionSynchronizationRegistry
+     * @since 2.6.0
+     */
+    public DataSourceXAConnectionFactory(final TransactionManager 
transactionManager, final XADataSource xaDataSource,
+            final String userName, final char[] userPassword, final 
TransactionSynchronizationRegistry transactionSynchronizationRegistry) {
         Objects.requireNonNull(transactionManager, "transactionManager is 
null");
         Objects.requireNonNull(xaDataSource, "xaDataSource is null");
-        this.transactionRegistry = new TransactionRegistry(transactionManager);
+
+        // We do allow the transactionSynchronizationRegistry to be null for 
non-app server environments
+
+        this.transactionRegistry = new TransactionRegistry(transactionManager, 
transactionSynchronizationRegistry);
         this.xaDataSource = xaDataSource;
         this.userName = userName;
         this.userPassword = userPassword;
@@ -93,7 +134,7 @@ public class DataSourceXAConnectionFactory implements 
XAConnectionFactory {
      */
     public DataSourceXAConnectionFactory(final TransactionManager 
transactionManager, final XADataSource xaDataSource,
             final String userName, final String userPassword) {
-        this(transactionManager, xaDataSource, userName, 
Utils.toCharArray(userPassword));
+        this(transactionManager, xaDataSource, userName, 
Utils.toCharArray(userPassword), null);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/70822f11/src/main/java/org/apache/commons/dbcp2/managed/TransactionContext.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/dbcp2/managed/TransactionContext.java 
b/src/main/java/org/apache/commons/dbcp2/managed/TransactionContext.java
index f4065d6..486ffcd 100644
--- a/src/main/java/org/apache/commons/dbcp2/managed/TransactionContext.java
+++ b/src/main/java/org/apache/commons/dbcp2/managed/TransactionContext.java
@@ -22,6 +22,7 @@ import javax.transaction.Status;
 import javax.transaction.Synchronization;
 import javax.transaction.SystemException;
 import javax.transaction.Transaction;
+import javax.transaction.TransactionSynchronizationRegistry;
 import javax.transaction.xa.XAResource;
 import java.sql.Connection;
 import java.sql.SQLException;
@@ -38,6 +39,7 @@ import java.lang.ref.WeakReference;
 public class TransactionContext {
     private final TransactionRegistry transactionRegistry;
     private final WeakReference<Transaction> transactionRef;
+    private final TransactionSynchronizationRegistry 
transactionSynchronizationRegistry;
     private Connection sharedConnection;
     private boolean transactionComplete;
 
@@ -49,13 +51,29 @@ public class TransactionContext {
      *            the TransactionRegistry used to obtain the XAResource for 
the shared connection
      * @param transaction
      *            the transaction
+     * @param transactionSynchronizationRegistry
+     *              The optional TSR to register synchronizations with
+     * @since 2.6.0
      */
-    public TransactionContext(final TransactionRegistry transactionRegistry, 
final Transaction transaction) {
+    public TransactionContext(final TransactionRegistry transactionRegistry, 
final Transaction transaction,
+                              final TransactionSynchronizationRegistry 
transactionSynchronizationRegistry) {
         Objects.requireNonNull(transactionRegistry, "transactionRegistry is 
null");
         Objects.requireNonNull(transaction, "transaction is null");
         this.transactionRegistry = transactionRegistry;
         this.transactionRef = new WeakReference<>(transaction);
         this.transactionComplete = false;
+        this.transactionSynchronizationRegistry = 
transactionSynchronizationRegistry;
+    }
+
+    /**
+     * Provided for backwards compatability
+     *
+     * @param transactionRegistry the TransactionRegistry used to obtain the 
XAResource for the
+     * shared connection
+     * @param transaction the transaction
+     */
+    public TransactionContext(final TransactionRegistry transactionRegistry, 
final Transaction transaction) {
+        this (transactionRegistry, transaction, null);
     }
 
     /**
@@ -112,7 +130,7 @@ public class TransactionContext {
      */
     public void addTransactionContextListener(final TransactionContextListener 
listener) throws SQLException {
         try {
-            getTransaction().registerSynchronization(new Synchronization() {
+            final Synchronization s = new Synchronization() {
                 @Override
                 public void beforeCompletion() {
                     // empty
@@ -122,7 +140,12 @@ public class TransactionContext {
                 public void afterCompletion(final int status) {
                     listener.afterCompletion(TransactionContext.this, status 
== Status.STATUS_COMMITTED);
                 }
-            });
+            };
+            if (transactionSynchronizationRegistry != null) {
+                
transactionSynchronizationRegistry.registerInterposedSynchronization(s);
+            } else {
+                getTransaction().registerSynchronization(s);
+            }
         } catch (final RollbackException e) {
             // JTA spec doesn't let us register with a transaction marked 
rollback only
             // just ignore this and the tx state will be cleared another way.

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/70822f11/src/main/java/org/apache/commons/dbcp2/managed/TransactionRegistry.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/dbcp2/managed/TransactionRegistry.java 
b/src/main/java/org/apache/commons/dbcp2/managed/TransactionRegistry.java
index 250d6dc..794752d 100644
--- a/src/main/java/org/apache/commons/dbcp2/managed/TransactionRegistry.java
+++ b/src/main/java/org/apache/commons/dbcp2/managed/TransactionRegistry.java
@@ -26,6 +26,7 @@ import java.util.WeakHashMap;
 import javax.transaction.SystemException;
 import javax.transaction.Transaction;
 import javax.transaction.TransactionManager;
+import javax.transaction.TransactionSynchronizationRegistry;
 import javax.transaction.xa.XAResource;
 
 import org.apache.commons.dbcp2.DelegatingConnection;
@@ -43,15 +44,28 @@ public class TransactionRegistry {
     private final TransactionManager transactionManager;
     private final Map<Transaction, TransactionContext> caches = new 
WeakHashMap<>();
     private final Map<Connection, XAResource> xaResources = new 
WeakHashMap<>();
+    private final TransactionSynchronizationRegistry 
transactionSynchronizationRegistry;
 
     /**
      * Creates a TransactionRegistry for the specified transaction manager.
      *
      * @param transactionManager
      *            the transaction manager used to enlist connections.
+     * @param transactionSynchronizationRegistry
+     *              The optional TSR to register synchronizations with
+     * @since 2.6.0
      */
-    public TransactionRegistry(final TransactionManager transactionManager) {
+    public TransactionRegistry(final TransactionManager transactionManager, 
final TransactionSynchronizationRegistry transactionSynchronizationRegistry) {
         this.transactionManager = transactionManager;
+        this.transactionSynchronizationRegistry = 
transactionSynchronizationRegistry;
+    }
+
+    /**
+     * Provided for backwards compatability
+     * @param transactionManager the transaction manager used to enlist 
connections
+     */
+    public TransactionRegistry(final TransactionManager transactionManager) {
+        this (transactionManager, null);
     }
 
     /**
@@ -115,7 +129,7 @@ public class TransactionRegistry {
         synchronized (this) {
             TransactionContext cache = caches.get(transaction);
             if (cache == null) {
-                cache = new TransactionContext(this, transaction);
+                cache = new TransactionContext(this, transaction, 
transactionSynchronizationRegistry);
                 caches.put(transaction, cache);
             }
             return cache;

http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/70822f11/src/test/java/org/apache/commons/dbcp2/managed/TestSynchronizationOrder.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/commons/dbcp2/managed/TestSynchronizationOrder.java 
b/src/test/java/org/apache/commons/dbcp2/managed/TestSynchronizationOrder.java
new file mode 100644
index 0000000..ae582f5
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/dbcp2/managed/TestSynchronizationOrder.java
@@ -0,0 +1,305 @@
+/**
+ *
+ * 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.commons.dbcp2.managed;
+
+import org.apache.commons.dbcp2.BasicDataSource;
+import org.apache.commons.dbcp2.DelegatingConnection;
+import org.apache.commons.dbcp2.PoolableConnectionFactory;
+import org.apache.commons.dbcp2.TesterClassLoader;
+import org.apache.commons.pool2.impl.GenericObjectPool;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.sql.XAConnection;
+import javax.sql.XADataSource;
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.InvalidTransactionException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.TransactionSynchronizationRegistry;
+import javax.transaction.xa.XAResource;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+public class TestSynchronizationOrder {
+
+    private boolean transactionManagerRegistered;
+    private boolean transactionSynchronizationRegistryRegistered;
+    private TransactionManager transactionManager;
+    private TransactionSynchronizationRegistry 
transactionSynchronizationRegistry;
+    private XADataSource xads;
+    private BasicManagedDataSource bmds;
+    private BasicDataSource bds;
+
+    @Test
+    public void testSessionSynchronization() throws Exception {
+        final DataSourceXAConnectionFactory xaConnectionFactory = new 
DataSourceXAConnectionFactory(transactionManager, xads);
+
+        final PoolableConnectionFactory factory =
+                new PoolableConnectionFactory(xaConnectionFactory, null);
+        factory.setValidationQuery("SELECT DUMMY FROM DUAL");
+        factory.setDefaultReadOnly(Boolean.TRUE);
+        factory.setDefaultAutoCommit(Boolean.TRUE);
+
+        // create the pool
+        final GenericObjectPool pool = new GenericObjectPool<>(factory);
+        factory.setPool(pool);
+        pool.setMaxTotal(10);
+        pool.setMaxWaitMillis(1000);
+
+        // finally create the datasource
+        final ManagedDataSource ds = new ManagedDataSource<>(pool, 
xaConnectionFactory.getTransactionRegistry());
+        ds.setAccessToUnderlyingConnectionAllowed(true);
+
+
+        transactionManager.begin();
+        final DelegatingConnection<?> connectionA = (DelegatingConnection<?>) 
ds.getConnection();
+        connectionA.close();
+        transactionManager.commit();
+        assertTrue(transactionManagerRegistered);
+        assertFalse(transactionSynchronizationRegistryRegistered);
+    }
+
+    @Test
+    public void testInterposedSynchronization() throws Exception {
+        final DataSourceXAConnectionFactory xaConnectionFactory = new 
DataSourceXAConnectionFactory(transactionManager, xads, 
transactionSynchronizationRegistry);
+
+        final PoolableConnectionFactory factory =
+                new PoolableConnectionFactory(xaConnectionFactory, null);
+        factory.setValidationQuery("SELECT DUMMY FROM DUAL");
+        factory.setDefaultReadOnly(Boolean.TRUE);
+        factory.setDefaultAutoCommit(Boolean.TRUE);
+
+        // create the pool
+        final GenericObjectPool pool = new GenericObjectPool<>(factory);
+        factory.setPool(pool);
+        pool.setMaxTotal(10);
+        pool.setMaxWaitMillis(1000);
+
+        // finally create the datasource
+        final ManagedDataSource ds = new ManagedDataSource<>(pool, 
xaConnectionFactory.getTransactionRegistry());
+        ds.setAccessToUnderlyingConnectionAllowed(true);
+
+
+        transactionManager.begin();
+        final DelegatingConnection<?> connectionA = (DelegatingConnection<?>) 
ds.getConnection();
+        connectionA.close();
+        transactionManager.commit();
+        assertFalse(transactionManagerRegistered);
+        assertTrue(transactionSynchronizationRegistryRegistered);
+    }
+
+    @After
+    public void tearDown() throws SQLException {
+        bds.close();
+        bmds.close();
+    }
+
+    @Before
+    public void setup() {
+        transactionManager = new TransactionManager() {
+
+            @Override
+            public void begin() throws NotSupportedException, SystemException {
+
+            }
+
+            @Override
+            public void commit() throws HeuristicMixedException, 
HeuristicRollbackException, IllegalStateException, RollbackException, 
SecurityException, SystemException {
+
+            }
+
+            @Override
+            public int getStatus() throws SystemException {
+                return 0;
+            }
+
+            @Override
+            public Transaction getTransaction() throws SystemException {
+                return new Transaction() {
+
+                    @Override
+                    public void commit() throws HeuristicMixedException, 
HeuristicRollbackException, RollbackException, SecurityException, 
SystemException {
+
+                    }
+
+                    @Override
+                    public boolean delistResource(final XAResource xaResource, 
final int i) throws IllegalStateException, SystemException {
+                        return false;
+                    }
+
+                    @Override
+                    public boolean enlistResource(final XAResource xaResource) 
throws IllegalStateException, RollbackException, SystemException {
+                        // Called and used
+                        return true;
+                    }
+
+                    @Override
+                    public int getStatus() throws SystemException {
+                        return 0;
+                    }
+
+                    @Override
+                    public void registerSynchronization(final Synchronization 
synchronization) throws IllegalStateException, RollbackException, 
SystemException {
+                        transactionManagerRegistered = true;
+                    }
+
+                    @Override
+                    public void rollback() throws IllegalStateException, 
SystemException {
+
+                    }
+
+                    @Override
+                    public void setRollbackOnly() throws 
IllegalStateException, SystemException {
+
+                    }
+                };
+            }
+
+            @Override
+            public void resume(final Transaction transaction) throws 
IllegalStateException, InvalidTransactionException, SystemException {
+
+            }
+
+            @Override
+            public void rollback() throws IllegalStateException, 
SecurityException, SystemException {
+
+            }
+
+            @Override
+            public void setRollbackOnly() throws IllegalStateException, 
SystemException {
+
+            }
+
+            @Override
+            public void setTransactionTimeout(final int i) throws 
SystemException {
+
+            }
+
+            @Override
+            public Transaction suspend() throws SystemException {
+                return null;
+            }
+        };
+
+        transactionSynchronizationRegistry = new 
TransactionSynchronizationRegistry() {
+
+            @Override
+            public Object getResource(final Object o) {
+                return null;
+            }
+
+            @Override
+            public boolean getRollbackOnly() {
+                return false;
+            }
+
+            @Override
+            public Object getTransactionKey() {
+                return null;
+            }
+
+            @Override
+            public int getTransactionStatus() {
+                return 0;
+            }
+
+            @Override
+            public void putResource(final Object o, final Object o1) {
+
+            }
+
+            @Override
+            public void registerInterposedSynchronization(final 
Synchronization synchronization) {
+                transactionSynchronizationRegistryRegistered = true;
+            }
+
+            @Override
+            public void setRollbackOnly() {
+
+            }
+        };
+
+        bmds = new BasicManagedDataSource();
+        bmds.setTransactionManager(transactionManager);
+        
bmds.setTransactionSynchronizationRegistry(transactionSynchronizationRegistry);
+        bmds.setXADataSource("notnull");
+        bds = new BasicDataSource();
+        bds.setDriverClassName("org.apache.commons.dbcp2.TesterDriver");
+        bds.setUrl("jdbc:apache:commons:testdriver");
+        bds.setMaxTotal(10);
+        bds.setMaxWaitMillis(100L);
+        bds.setDefaultAutoCommit(Boolean.TRUE);
+        bds.setDefaultReadOnly(Boolean.FALSE);
+        
bds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
+        bds.setDefaultCatalog("test catalog");
+        bds.setUsername("userName");
+        bds.setPassword("password");
+        bds.setValidationQuery("SELECT DUMMY FROM DUAL");
+        bds.setConnectionInitSqls(Arrays.asList(new String[]{"SELECT 1", 
"SELECT 2"}));
+        bds.setDriverClassLoader(new TesterClassLoader());
+        bds.setJmxName("org.apache.commons.dbcp2:name=test");
+        final AtomicInteger closeCounter = new AtomicInteger();
+        final InvocationHandler handle = new InvocationHandler() {
+            @Override
+            public Object invoke(final Object proxy, final Method method, 
final Object[] args)
+                    throws Throwable {
+                final String methodName = method.getName();
+                if (methodName.equals("hashCode")) {
+                    return Integer.valueOf(System.identityHashCode(proxy));
+                }
+                if (methodName.equals("equals")) {
+                    return Boolean.valueOf(proxy == args[0]);
+                }
+                if (methodName.equals("getXAConnection")) {
+                    // both zero and 2-arg signatures
+                    return getXAConnection();
+                }
+                try {
+                    return method.invoke(bds, args);
+                } catch (final InvocationTargetException e) {
+                    throw e.getTargetException();
+                }
+            }
+
+            protected XAConnection getXAConnection() throws SQLException {
+                return new TesterBasicXAConnection(bds.getConnection(), 
closeCounter);
+            }
+        };
+        xads = (XADataSource) Proxy.newProxyInstance(
+                InvocationHandler.class.getClassLoader(),
+                new Class[]{XADataSource.class}, handle);
+        bmds.setXaDataSourceInstance(xads);
+
+    }
+}

Reply via email to