This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit 2ba9f341db00982a6506ad85c2d73bfe4bfeb337
Author: dmitrij <dmitriy.tarasie...@gmail.com>
AuthorDate: Wed May 26 11:47:26 2021 +0300

    feat: ability to add custom user connection to TransactionDescriptor
---
 .../org/apache/cayenne/tx/BaseTransaction.java     |  44 +++++----
 .../apache/cayenne/tx/TransactionDescriptor.java   | 106 +++++++++++++++++----
 .../org/apache/cayenne/tx/TransactionListener.java |   4 +
 .../cayenne/tx/DefaultTransactionManagerIT.java    |  22 +++--
 .../apache/cayenne/tx/TransactionIsolationIT.java  |   8 +-
 .../tx/TransactionPropagationRollbackIT.java       |  24 ++---
 6 files changed, 151 insertions(+), 57 deletions(-)

diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/tx/BaseTransaction.java 
b/cayenne-server/src/main/java/org/apache/cayenne/tx/BaseTransaction.java
index a83990b..e3215b5 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/tx/BaseTransaction.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/tx/BaseTransaction.java
@@ -22,11 +22,7 @@ package org.apache.cayenne.tx;
 import javax.sql.DataSource;
 import java.sql.Connection;
 import java.sql.SQLException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
+import java.util.*;
 
 import org.apache.cayenne.CayenneRuntimeException;
 
@@ -204,7 +200,10 @@ public abstract class BaseTransaction implements 
Transaction {
         Connection c = getExistingConnection(connectionName);
 
         if (c == null || c.isClosed()) {
-            c = dataSource.getConnection();
+            if(descriptor.getCustomConnectionSupplier() != null)
+                c = descriptor.getCustomConnectionSupplier().get();
+            else
+                c = dataSource.getConnection();
             addConnection(connectionName, c);
         }
 
@@ -219,19 +218,18 @@ public abstract class BaseTransaction implements 
Transaction {
 
     protected Connection addConnection(String connectionName, Connection 
connection) {
 
-        if(descriptor.getIsolation() != 
TransactionDescriptor.ISOLATION_DEFAULT) {
-            try {
-                defaultIsolationLevel = connection.getTransactionIsolation();
-                connection.setTransactionIsolation(descriptor.getIsolation());
-            } catch (SQLException ex) {
-                throw new CayenneRuntimeException("Unable to set required 
isolation level: " + descriptor.getIsolation(), ex);
-            }
-        }
+        setIsolationLevelFrom(connection);
 
-        TransactionConnectionDecorator wrapper = new 
TransactionConnectionDecorator(connection);
+        TransactionConnectionDecorator wrapper = null;
 
         if (listeners != null) {
             for (TransactionListener listener : listeners) {
+                connection = listener.decorateConnection(this, connection);
+            }
+
+            wrapper = new TransactionConnectionDecorator(connection);
+
+            for (TransactionListener listener : listeners) {
                 listener.willAddConnection(this, connectionName, wrapper);
             }
         }
@@ -241,6 +239,9 @@ public abstract class BaseTransaction implements 
Transaction {
             connections = new HashMap<>();
         }
 
+        if (wrapper == null)
+            wrapper = new TransactionConnectionDecorator(connection);
+
         if (connections.put(connectionName, wrapper) != wrapper) {
             connectionAdded(connection);
         }
@@ -248,6 +249,17 @@ public abstract class BaseTransaction implements 
Transaction {
         return wrapper;
     }
 
+    private void setIsolationLevelFrom(Connection connection) {
+        if (descriptor.getIsolation() != 
TransactionDescriptor.ISOLATION_DEFAULT) {
+            try {
+                defaultIsolationLevel = connection.getTransactionIsolation();
+                connection.setTransactionIsolation(descriptor.getIsolation());
+            } catch (SQLException ex) {
+                throw new CayenneRuntimeException("Unable to set required 
isolation level: " + descriptor.getIsolation(), ex);
+            }
+        }
+    }
+
     protected void connectionAdded(Connection connection) {
 
         // implicitly begin transaction
@@ -278,7 +290,7 @@ public abstract class BaseTransaction implements 
Transaction {
                 // ignore for now
             } finally {
                 // restore connection default isolation level ...
-                if(defaultIsolationLevel != -1) {
+                if (defaultIsolationLevel != -1) {
                     try {
                         c.setTransactionIsolation(defaultIsolationLevel);
                     } catch (SQLException ignore) {
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionDescriptor.java 
b/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionDescriptor.java
index 7dd60ce..ecb273a 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionDescriptor.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionDescriptor.java
@@ -19,8 +19,10 @@
 
 package org.apache.cayenne.tx;
 
+import java.sql.Connection;
+import java.util.function.Supplier;
+
 /**
- *
  * Descriptor that provide desired transaction isolation level and propagation 
logic.
  *
  * @since 4.1
@@ -32,47 +34,53 @@ public class TransactionDescriptor {
      */
     public static final int ISOLATION_DEFAULT = -1;
 
-    private final int isolation;
+    private int isolation;
 
-    private final TransactionPropagation propagation;
+    private TransactionPropagation propagation;
+
+    private Supplier<Connection> customConnectionSupplier;
+
+    private TransactionDescriptor() {
+    }
 
     /**
-     * @param isolation one of the following <code>Connection</code> constants:
-     *        <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>,
-     *        <code>Connection.TRANSACTION_READ_COMMITTED</code>,
-     *        <code>Connection.TRANSACTION_REPEATABLE_READ</code>,
-     *        <code>Connection.TRANSACTION_SERIALIZABLE</code>, or
-     *        <code>TransactionDescriptor.ISOLATION_DEFAULT</code>
-     *
+     * @param isolation   one of the following <code>Connection</code> 
constants:
+     *                    <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>,
+     *                    <code>Connection.TRANSACTION_READ_COMMITTED</code>,
+     *                    <code>Connection.TRANSACTION_REPEATABLE_READ</code>,
+     *                    <code>Connection.TRANSACTION_SERIALIZABLE</code>, or
+     *                    <code>TransactionDescriptor.ISOLATION_DEFAULT</code>
      * @param propagation transaction propagation behaviour
-     *
      * @see TransactionPropagation
+     * @deprecated since 4.2.M4. Use builder instead
      */
+    @Deprecated
     public TransactionDescriptor(int isolation, TransactionPropagation 
propagation) {
         this.isolation = isolation;
         this.propagation = propagation;
     }
 
     /**
-     *
      * Create transaction descriptor with desired isolation level and 
<code>NESTED</code> propagation
      *
      * @param isolation one of the following <code>Connection</code> constants:
-     *        <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>,
-     *        <code>Connection.TRANSACTION_READ_COMMITTED</code>,
-     *        <code>Connection.TRANSACTION_REPEATABLE_READ</code>,
-     *        <code>Connection.TRANSACTION_SERIALIZABLE</code>, or
-     *        <code>TransactionDescriptor.ISOLATION_DEFAULT</code>
+     *                  <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>,
+     *                  <code>Connection.TRANSACTION_READ_COMMITTED</code>,
+     *                  <code>Connection.TRANSACTION_REPEATABLE_READ</code>,
+     *                  <code>Connection.TRANSACTION_SERIALIZABLE</code>, or
+     *                  <code>TransactionDescriptor.ISOLATION_DEFAULT</code>
      */
+    @Deprecated
     public TransactionDescriptor(int isolation) {
         this(isolation, TransactionPropagation.NESTED);
     }
 
     /**
-     *
      * @param propagation transaction propagation behaviour
      * @see TransactionPropagation
+     * @deprecated since 4.2.M4. Use builder instead
      */
+    @Deprecated
     public TransactionDescriptor(TransactionPropagation propagation) {
         this(ISOLATION_DEFAULT, propagation);
     }
@@ -90,4 +98,66 @@ public class TransactionDescriptor {
     public TransactionPropagation getPropagation() {
         return propagation;
     }
+
+    /**
+     * @return custom connection supplier, passed by user
+     */
+    public Supplier<Connection> getCustomConnectionSupplier() {
+        return customConnectionSupplier;
+    }
+
+    /**
+     * Builder class for TransactionDescriptor.
+     *
+     * @since 4.2.M4
+     */
+    public static class Builder {
+        private final TransactionDescriptor transactionDescriptor = new 
TransactionDescriptor();
+
+        /**
+         * @param isolation one of the following <code>Connection</code> 
constants:
+         *                  
<code>Connection.TRANSACTION_READ_UNCOMMITTED</code>,
+         *                  <code>Connection.TRANSACTION_READ_COMMITTED</code>,
+         *                  
<code>Connection.TRANSACTION_REPEATABLE_READ</code>,
+         *                  <code>Connection.TRANSACTION_SERIALIZABLE</code>, 
or
+         *                  
<code>TransactionDescriptor.ISOLATION_DEFAULT</code>
+         */
+        public Builder isolation(int isolation) {
+            transactionDescriptor.isolation = isolation;
+            return this;
+        }
+
+        /**
+         * @param connection custom connection
+         * @see Connection
+         */
+        public Builder connectionSupplier(Connection connection) {
+            transactionDescriptor.customConnectionSupplier = () -> connection;
+            return this;
+        }
+
+        /**
+         * @param connectionSupplier custom connection supplier
+         * @see Connection
+         * @see Supplier
+         */
+        public Builder connectionSupplier(Supplier<Connection> 
connectionSupplier){
+            transactionDescriptor.customConnectionSupplier = 
connectionSupplier;
+            return this;
+        }
+
+        /**
+         * @param propagation transaction propagation behaviour
+         * @see TransactionPropagation
+         */
+        public Builder propagation(TransactionPropagation propagation) {
+            transactionDescriptor.propagation = propagation;
+            return this;
+        }
+
+        public TransactionDescriptor build() {
+            return transactionDescriptor;
+        }
+    }
+
 }
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionListener.java 
b/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionListener.java
index dc230e1..b891f6b 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionListener.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionListener.java
@@ -33,4 +33,8 @@ public interface TransactionListener {
     void willRollback(Transaction tx);
 
     void willAddConnection(Transaction tx, String connectionName, Connection 
connection);
+
+    default Connection decorateConnection(Transaction tx, Connection 
connection){
+        return connection;
+    }
 }
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/tx/DefaultTransactionManagerIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/tx/DefaultTransactionManagerIT.java
index deb025a..ef9de67 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/tx/DefaultTransactionManagerIT.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/tx/DefaultTransactionManagerIT.java
@@ -83,10 +83,12 @@ public class DefaultTransactionManagerIT {
         try {
             final Object expectedResult = new Object();
             Object result = txManager.performInTransaction(() -> {
-                    assertSame(tx, BaseTransaction.getThreadTransaction());
-                    return expectedResult;
-                },
-                new TransactionDescriptor(TransactionPropagation.NESTED)
+                        assertSame(tx, BaseTransaction.getThreadTransaction());
+                        return expectedResult;
+                    },
+                    new TransactionDescriptor.Builder()
+                            .propagation(TransactionPropagation.NESTED)
+                            .build()
             );
             assertSame(expectedResult, result);
         } finally {
@@ -109,7 +111,9 @@ public class DefaultTransactionManagerIT {
                         assertSame(tx, BaseTransaction.getThreadTransaction());
                         return expectedResult;
                     },
-                    new TransactionDescriptor(TransactionPropagation.MANDATORY)
+                    new TransactionDescriptor.Builder()
+                            .propagation(TransactionPropagation.MANDATORY)
+                            .build()
             );
             assertSame(expectedResult, result);
         } finally {
@@ -133,7 +137,9 @@ public class DefaultTransactionManagerIT {
                         assertSame(tx, BaseTransaction.getThreadTransaction());
                         return expectedResult;
                     },
-                    new TransactionDescriptor(TransactionPropagation.MANDATORY)
+                    new TransactionDescriptor.Builder()
+                            .propagation(TransactionPropagation.MANDATORY)
+                            .build()
             );
             assertSame(expectedResult, result);
         } finally {
@@ -163,7 +169,9 @@ public class DefaultTransactionManagerIT {
                         assertSame(tx2, 
BaseTransaction.getThreadTransaction());
                         return expectedResult;
                     },
-                    new 
TransactionDescriptor(TransactionPropagation.REQUIRES_NEW)
+                    new TransactionDescriptor.Builder()
+                            .propagation(TransactionPropagation.REQUIRES_NEW)
+                            .build()
             );
             assertSame(expectedResult, result);
             assertSame(tx1, BaseTransaction.getThreadTransaction());
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionIsolationIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionIsolationIT.java
index 6f6cfbb..c2d00af 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionIsolationIT.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionIsolationIT.java
@@ -74,10 +74,10 @@ public class TransactionIsolationIT extends ServerCase {
             return;
         }
 
-        TransactionDescriptor descriptor = new TransactionDescriptor(
-                Connection.TRANSACTION_SERIALIZABLE,
-                TransactionPropagation.REQUIRES_NEW
-        );
+        TransactionDescriptor descriptor = new TransactionDescriptor.Builder()
+                .propagation(TransactionPropagation.REQUIRES_NEW)
+                .isolation(Connection.TRANSACTION_SERIALIZABLE)
+                .build();
 
         CountDownLatch startSignal = new CountDownLatch(1);
         CountDownLatch resumeSerializableTransaction = new CountDownLatch(1);
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionPropagationRollbackIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionPropagationRollbackIT.java
index 6c8985e..cd6c937 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionPropagationRollbackIT.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionPropagationRollbackIT.java
@@ -69,10 +69,10 @@ public class TransactionPropagationRollbackIT extends 
ServerCase {
      */
     @Test
     public void testPropagationRequiresNew() {
-        TransactionDescriptor descriptor = new TransactionDescriptor(
-                Connection.TRANSACTION_SERIALIZABLE, // ensure that 
transaction not visible to each other
-                TransactionPropagation.REQUIRES_NEW  // require new 
transaction for every operation
-        );
+        TransactionDescriptor descriptor = new TransactionDescriptor.Builder()
+                .propagation(TransactionPropagation.REQUIRES_NEW)
+                .isolation(Connection.TRANSACTION_SERIALIZABLE)
+                .build();
 
         performInTransaction(descriptor);
 
@@ -89,10 +89,10 @@ public class TransactionPropagationRollbackIT extends 
ServerCase {
     @Test
     public void testPropagationNested() {
 
-        TransactionDescriptor descriptor = new TransactionDescriptor(
-                Connection.TRANSACTION_SERIALIZABLE, // ensure that 
transaction not visible to each other
-                TransactionPropagation.NESTED        // allow joining to 
existing transaction
-        );
+        TransactionDescriptor descriptor = new TransactionDescriptor.Builder()
+                .isolation(Connection.TRANSACTION_SERIALIZABLE)
+                .propagation(TransactionPropagation.NESTED)
+                .build();
 
         performInTransaction(descriptor);
 
@@ -109,10 +109,10 @@ public class TransactionPropagationRollbackIT extends 
ServerCase {
     @Test
     public void testPropagationMandatory() {
 
-        TransactionDescriptor descriptor = new TransactionDescriptor(
-                Connection.TRANSACTION_SERIALIZABLE, // ensure that 
transaction not visible to each other
-                TransactionPropagation.MANDATORY     // requires existing 
transaction to join
-        );
+        TransactionDescriptor descriptor = new TransactionDescriptor.Builder()
+                .isolation(Connection.TRANSACTION_SERIALIZABLE)
+                .propagation(TransactionPropagation.MANDATORY)
+                .build();
 
         performInTransaction(descriptor);
 

Reply via email to