You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2016/09/19 15:23:20 UTC
cayenne git commit: CAY-2112 Expose callback for
"performInTransaction"
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 <an...@objectstyle.com>
Authored: Mon Sep 19 10:23:13 2016 -0400
Committer: Andrus Adamchik <an...@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: