Repository: cayenne
Updated Branches:
  refs/heads/master 8aaf787bf -> 42eda59bc


CAY-2112 Expose callback for "performInTransaction"


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/42eda59b
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/42eda59b
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/42eda59b

Branch: refs/heads/master
Commit: 42eda59bc1fefddf4920830aa0f142f95c995b23
Parents: 8aaf787
Author: Andrus Adamchik <and...@objectstyle.com>
Authored: Mon Sep 19 10:23:13 2016 -0400
Committer: Andrus Adamchik <and...@objectstyle.com>
Committed: Mon Sep 19 11:23:04 2016 -0400

----------------------------------------------------------------------
 .../configuration/server/ServerRuntime.java     | 20 +++-
 .../org/apache/cayenne/tx/BaseTransaction.java  | 35 ++++++-
 .../cayenne/tx/DefaultTransactionManager.java   | 29 ++++--
 .../tx/DoNothingTransactionListener.java        | 51 +++++++++++
 .../java/org/apache/cayenne/tx/Transaction.java |  4 +-
 .../apache/cayenne/tx/TransactionListener.java  | 36 ++++++++
 .../apache/cayenne/tx/TransactionManager.java   | 21 ++++-
 .../cayenne/access/TransactionThreadIT.java     |  6 ++
 .../cayenne/access/UserTransactionIT.java       |  8 +-
 .../configuration/server/ServerRuntimeIT.java   | 96 ++++++++++++++++++++
 .../cayenne/tx/DefaultTransactionManagerIT.java |  4 +-
 docs/doc/src/main/resources/RELEASE-NOTES.txt   |  1 +
 12 files changed, 291 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/42eda59b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java
index 6e4d322..dc71ae5 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java
@@ -18,16 +18,17 @@
  ****************************************************************/
 package org.apache.cayenne.configuration.server;
 
-import javax.sql.DataSource;
-
 import org.apache.cayenne.access.DataDomain;
 import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.configuration.CayenneRuntime;
 import org.apache.cayenne.configuration.ModuleCollection;
 import org.apache.cayenne.di.Module;
+import org.apache.cayenne.tx.TransactionListener;
 import org.apache.cayenne.tx.TransactionManager;
 import org.apache.cayenne.tx.TransactionalOperation;
 
+import javax.sql.DataSource;
+
 /**
  * An object representing Cayenne server-stack that connects directly to the
  * database via JDBC. This is an entry point for user applications to access
@@ -80,6 +81,21 @@ public class ServerRuntime extends CayenneRuntime {
        }
 
        /**
+        * Runs provided operation wrapped in a single transaction. Transaction
+        * handling delegated to the internal {@link TransactionManager}. Nested
+        * calls to 'performInTransaction' are safe and attached to the same
+        * in-progress transaction. TransactionalOperation can be some arbitrary
+        * user code, which most often than not will consist of multiple Cayenne
+        * operations.
+        *
+        * @since 4.0
+        */
+       public <T> T performInTransaction(TransactionalOperation<T> op, 
TransactionListener callback) {
+               TransactionManager tm = 
injector.getInstance(TransactionManager.class);
+               return tm.performInTransaction(op, callback);
+       }
+
+       /**
         * Returns the main runtime DataDomain. Note that by default the 
returned
         * DataDomain is the same as the main DataChannel returned by
         * {@link #getChannel()}. Although users may redefine DataChannel 
provider

http://git-wip-us.apache.org/repos/asf/cayenne/blob/42eda59b/cayenne-server/src/main/java/org/apache/cayenne/tx/BaseTransaction.java
----------------------------------------------------------------------
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 fb23db0..8ed44fc 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
@@ -20,8 +20,10 @@
 package org.apache.cayenne.tx;
 
 import java.sql.Connection;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.Map;
 
 /**
@@ -45,6 +47,7 @@ public abstract class BaseTransaction implements Transaction {
        protected static final int STATUS_MARKED_ROLLEDBACK = 7;
 
        protected Map<String, Connection> connections;
+       protected Collection<TransactionListener> listeners;
        protected int status;
 
        static String decodeStatus(int status) {
@@ -100,6 +103,15 @@ public abstract class BaseTransaction implements 
Transaction {
                return status == STATUS_MARKED_ROLLEDBACK;
        }
 
+       @Override
+       public void addListener(TransactionListener listener) {
+               if(listeners == null) {
+                       listeners = new LinkedHashSet<>();
+               }
+
+               listeners.add(listener);
+       }
+
        /**
         * Starts a Transaction. If Transaction is not started explicitly, it 
will
         * be started when the first connection is added.
@@ -126,6 +138,12 @@ public abstract class BaseTransaction implements 
Transaction {
                                        + "Current status: " + 
BaseTransaction.decodeStatus(status));
                }
 
+               if(listeners != null) {
+                       for(TransactionListener listener : listeners) {
+                               listener.willCommit(this);
+                       }
+               }
+
                processCommit();
 
                status = BaseTransaction.STATUS_COMMITTED;
@@ -139,6 +157,7 @@ public abstract class BaseTransaction implements 
Transaction {
        public void rollback() {
 
                try {
+
                        if (status == BaseTransaction.STATUS_NO_TRANSACTION || 
status == BaseTransaction.STATUS_ROLLEDBACK
                                        || status == 
BaseTransaction.STATUS_ROLLING_BACK) {
                                return;
@@ -150,6 +169,12 @@ public abstract class BaseTransaction implements 
Transaction {
                                                                + "Current 
status: " + BaseTransaction.decodeStatus(status));
                        }
 
+                       if(listeners != null) {
+                               for(TransactionListener listener : listeners) {
+                                       listener.willRollback(this);
+                               }
+                       }
+
                        processRollback();
 
                        status = BaseTransaction.STATUS_ROLLEDBACK;
@@ -167,13 +192,19 @@ public abstract class BaseTransaction implements 
Transaction {
        }
 
        @Override
-       public void addConnection(String name, Connection connection) {
+       public void addConnection(String connectionName, Connection connection) 
{
+
+               if(listeners != null) {
+                       for(TransactionListener listener : listeners) {
+                               listener.willAddConnection(this, 
connectionName, connection);
+                       }
+               }
 
                if (connections == null) {
                        connections = new HashMap<>();
                }
 
-               if (connections.put(name, connection) != connection) {
+               if (connections.put(connectionName, connection) != connection) {
                        connectionAdded(connection);
                }
        }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/42eda59b/cayenne-server/src/main/java/org/apache/cayenne/tx/DefaultTransactionManager.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/tx/DefaultTransactionManager.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/tx/DefaultTransactionManager.java
index b8c284c..61ed4b6 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/tx/DefaultTransactionManager.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/tx/DefaultTransactionManager.java
@@ -37,23 +37,27 @@ public class DefaultTransactionManager implements 
TransactionManager {
 
     @Override
     public <T> T performInTransaction(TransactionalOperation<T> op) {
+        return performInTransaction(op, 
DoNothingTransactionListener.getInstance());
+    }
+
+    @Override
+    public <T> T performInTransaction(TransactionalOperation<T> op, 
TransactionListener callback) {
+
+        // Either join existing tx (in such case do not try to commit or 
rollback), or start a new tx and manage it
+        // till the end
 
-        // join existing tx if it is in progress... in such case do not try to
-        // commit or roll it back
         Transaction currentTx = BaseTransaction.getThreadTransaction();
-        if (currentTx != null) {
-            return op.perform();
-        }
+        return (currentTx != null)
+                ? performInTransaction(currentTx, op, callback)
+                : performInLocalTransaction(op, callback);
+    }
 
-        // start a new tx and manage it till the end
+    protected <T> T performInLocalTransaction(TransactionalOperation<T> op, 
TransactionListener callback) {
         Transaction tx = txFactory.createTransaction();
         BaseTransaction.bindThreadTransaction(tx);
         try {
-
-            T result = op.perform();
-
+            T result = performInTransaction(tx, op, callback);
             tx.commit();
-
             return result;
 
         } catch (CayenneRuntimeException ex) {
@@ -78,4 +82,9 @@ public class DefaultTransactionManager implements 
TransactionManager {
         }
     }
 
+    protected <T> T performInTransaction(Transaction tx, 
TransactionalOperation<T> op, TransactionListener callback) {
+        tx.addListener(callback);
+        return op.perform();
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/42eda59b/cayenne-server/src/main/java/org/apache/cayenne/tx/DoNothingTransactionListener.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/tx/DoNothingTransactionListener.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/tx/DoNothingTransactionListener.java
new file mode 100644
index 0000000..f133ad4
--- /dev/null
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/tx/DoNothingTransactionListener.java
@@ -0,0 +1,51 @@
+/*****************************************************************
+ *   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.cayenne.tx;
+
+import java.sql.Connection;
+
+/**
+ * Created by andrus on 9/19/16.
+ */
+class DoNothingTransactionListener implements TransactionListener {
+
+    private static TransactionListener INSTANCE = new 
DoNothingTransactionListener();
+
+    public static TransactionListener getInstance() {
+        return INSTANCE;
+    }
+
+    private DoNothingTransactionListener() {
+    }
+
+    @Override
+    public void willCommit(Transaction tx) {
+        // do nothing...
+    }
+
+    @Override
+    public void willRollback(Transaction tx) {
+        // do nothing...
+    }
+
+    @Override
+    public void willAddConnection(Transaction tx, String connectionName, 
Connection connection) {
+        // do nothing...
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/42eda59b/cayenne-server/src/main/java/org/apache/cayenne/tx/Transaction.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/tx/Transaction.java 
b/cayenne-server/src/main/java/org/apache/cayenne/tx/Transaction.java
index efc47b8..789573f 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/tx/Transaction.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/tx/Transaction.java
@@ -43,5 +43,7 @@ public interface Transaction {
 
     Connection getConnection(String name);
 
-    void addConnection(String name, Connection connection);
+    void addConnection(String connectionName, Connection connection);
+
+    void addListener(TransactionListener listener);
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/42eda59b/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionListener.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..61d15fb
--- /dev/null
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionListener.java
@@ -0,0 +1,36 @@
+/*****************************************************************
+ *   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.cayenne.tx;
+
+import java.sql.Connection;
+
+/**
+ * A callback that is notified as transaction progresses through stages. It 
can customize transaction isolation level,
+ * etc.
+ *
+ * @since 4.0
+ */
+public interface TransactionListener {
+
+    void willCommit(Transaction tx);
+
+    void willRollback(Transaction tx);
+
+    void willAddConnection(Transaction tx, String connectionName, Connection 
connection);
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/42eda59b/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionManager.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionManager.java 
b/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionManager.java
index 142c503..56ae93f 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionManager.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionManager.java
@@ -22,15 +22,30 @@ package org.apache.cayenne.tx;
  * An optional utility service that simplifies wrapping multiple operations in
  * transactions. Users only rarely need to invoke it directly, as all standard
  * Cayenne operations are managing their own transactions internally.
- * 
+ *
  * @since 4.0
  */
 public interface TransactionManager {
 
     /**
      * Starts a new transaction (or joins an existing one) calling
-     * {@link org.apache.cayenne.tx.TransactionalOperation#perform()}, and then
-     * committing or rolling back the transaction. Frees the user
+     * {@link org.apache.cayenne.tx.TransactionalOperation#perform()}, and 
then committing or rolling back the
+     * transaction.
+     *
+     * @param op an operation to perform within the trsnaction.
+     * @return a value returned by the "op" operation.
      */
     <T> T performInTransaction(TransactionalOperation<T> op);
+
+    /**
+     * Starts a new transaction (or joins an existing one) calling
+     * {@link org.apache.cayenne.tx.TransactionalOperation#perform()}, and 
then committing or rolling back the
+     * transaction. As transaction goes through stages, callback methods are 
invoked allowing the caller to customize
+     * transaction parameters.
+     *
+     * @param op       an operation to perform within the trsnaction.
+     * @param callback a callback to notify as transaction progresses through 
stages.
+     * @return a value returned by the "op" operation.
+     */
+    <T> T performInTransaction(TransactionalOperation<T> op, 
TransactionListener callback);
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/42eda59b/cayenne-server/src/test/java/org/apache/cayenne/access/TransactionThreadIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/access/TransactionThreadIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/access/TransactionThreadIT.java
index a19b86c..50368e2 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/access/TransactionThreadIT.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/access/TransactionThreadIT.java
@@ -26,6 +26,7 @@ import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.tx.BaseTransaction;
 import org.apache.cayenne.tx.CayenneTransaction;
 import org.apache.cayenne.tx.Transaction;
+import org.apache.cayenne.tx.TransactionListener;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.ServerCase;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
@@ -107,5 +108,10 @@ public class TransactionThreadIT extends ServerCase {
 
             delegate.addConnection(name, connection);
         }
+
+        @Override
+        public void addListener(TransactionListener listener) {
+            delegate.addListener(listener);
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/42eda59b/cayenne-server/src/test/java/org/apache/cayenne/access/UserTransactionIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/access/UserTransactionIT.java 
b/cayenne-server/src/test/java/org/apache/cayenne/access/UserTransactionIT.java
index 55b27d1..f644639 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/access/UserTransactionIT.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/access/UserTransactionIT.java
@@ -26,6 +26,7 @@ import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.tx.BaseTransaction;
 import org.apache.cayenne.tx.CayenneTransaction;
 import org.apache.cayenne.tx.Transaction;
+import org.apache.cayenne.tx.TransactionListener;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.ServerCase;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
@@ -66,9 +67,9 @@ public class UserTransactionIT extends ServerCase {
 
     class TxWrapper implements Transaction {
 
-        private Transaction delegate;
         int commitCount;
         int connectionCount;
+        private Transaction delegate;
 
         TxWrapper(Transaction delegate) {
             this.delegate = delegate;
@@ -103,6 +104,11 @@ public class UserTransactionIT extends ServerCase {
             connectionCount++;
             delegate.addConnection(name, connection);
         }
+
+        @Override
+        public void addListener(TransactionListener listener) {
+            delegate.addListener(listener);
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/42eda59b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeIT.java
new file mode 100644
index 0000000..4668264
--- /dev/null
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeIT.java
@@ -0,0 +1,96 @@
+/*****************************************************************
+ *   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.cayenne.configuration.server;
+
+import org.apache.cayenne.PersistenceState;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.testdo.testmap.Artist;
+import org.apache.cayenne.tx.Transaction;
+import org.apache.cayenne.tx.TransactionListener;
+import org.apache.cayenne.tx.TransactionalOperation;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.apache.cayenne.validation.ValidationException;
+import org.junit.Test;
+
+import java.sql.Connection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class ServerRuntimeIT extends ServerCase {
+
+    @Inject
+    private ServerRuntime runtime;
+
+    @Test
+    public void testPerformInTransaction_Local_Callback() {
+
+        TransactionListener callback = mock(TransactionListener.class);
+
+        Artist a = runtime.performInTransaction(new 
TransactionalOperation<Artist>() {
+
+            @Override
+            public Artist perform() {
+
+                Artist localArtist = 
runtime.newContext().newObject(Artist.class);
+                localArtist.setArtistName("A1");
+                localArtist.getObjectContext().commitChanges();
+                return localArtist;
+            }
+        }, callback);
+
+        assertEquals("A1", a.getArtistName());
+        assertEquals(PersistenceState.COMMITTED, a.getPersistenceState());
+        verify(callback).willCommit(any(Transaction.class));
+        verify(callback).willAddConnection(any(Transaction.class), 
any(String.class), any(Connection.class));
+        verify(callback, times(0)).willRollback(any(Transaction.class));
+    }
+
+    @Test
+    public void testPerformInTransaction_Local_Callback_Rollback() {
+
+        TransactionListener callback = mock(TransactionListener.class);
+
+        try {
+            runtime.performInTransaction(new TransactionalOperation<Artist>() {
+
+                @Override
+                public Artist perform() {
+
+                    Artist localArtist = 
runtime.newContext().newObject(Artist.class);
+                    localArtist.getObjectContext().commitChanges();
+                    return localArtist;
+                }
+            }, callback);
+
+            fail("Exception expected");
+        } catch (ValidationException v) {
+            verify(callback).willRollback(any(Transaction.class));
+            verify(callback, 
times(0)).willAddConnection(any(Transaction.class), any(String.class), 
any(Connection.class));
+            verify(callback, times(0)).willCommit(any(Transaction.class));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/42eda59b/cayenne-server/src/test/java/org/apache/cayenne/tx/DefaultTransactionManagerIT.java
----------------------------------------------------------------------
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 3da3af4..6b9f001 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
@@ -33,7 +33,7 @@ import static org.mockito.Mockito.when;
 public class DefaultTransactionManagerIT extends ServerCase {
 
     @Test
-    public void testPerformInTransaction_NoTx() {
+    public void testPerformInTransaction_Local() {
 
         final BaseTransaction tx = mock(BaseTransaction.class);
         TransactionFactory txFactory = mock(TransactionFactory.class);
@@ -78,4 +78,6 @@ public class DefaultTransactionManagerIT extends ServerCase {
             BaseTransaction.bindThreadTransaction(null);
         }
     }
+
+
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/42eda59b/docs/doc/src/main/resources/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/docs/doc/src/main/resources/RELEASE-NOTES.txt 
b/docs/doc/src/main/resources/RELEASE-NOTES.txt
index d496e84..d6af992 100644
--- a/docs/doc/src/main/resources/RELEASE-NOTES.txt
+++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt
@@ -30,6 +30,7 @@ CAY-2103 cayenne-crypto: support for mapping non-String and 
non-binary types
 CAY-2106 cayenne-crypto: allow DI contribution of type converters inside 
ValueTransformerFactory
 CAY-2107 cayenne-crypto: Lazy initialization of crypto subsystem
 CAY-2111 Unbind transaction object from the current thread for iterated queries
+CAY-2112 Expose callback for "performInTransaction"
 
 Bug Fixes:
 

Reply via email to