tx-control-service spec compliance
No Transaction scope should allow post-completion registrations from inside pre-completion callbacks
diff --git a/tx-control-services/tx-control-service-common/src/main/java/org/apache/aries/tx/control/service/common/impl/NoTransactionContextImpl.java b/tx-control-services/tx-control-service-common/src/main/java/org/apache/aries/tx/control/service/common/impl/NoTransactionContextImpl.java
index aa3d6d0..c345d64 100644
--- a/tx-control-services/tx-control-service-common/src/main/java/org/apache/aries/tx/control/service/common/impl/NoTransactionContextImpl.java
+++ b/tx-control-services/tx-control-service-common/src/main/java/org/apache/aries/tx/control/service/common/impl/NoTransactionContextImpl.java
@@ -20,7 +20,7 @@
import static org.osgi.service.transaction.control.TransactionStatus.NO_TRANSACTION;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import javax.transaction.xa.XAResource;
@@ -32,7 +32,11 @@
public class NoTransactionContextImpl extends AbstractTransactionContextImpl
implements TransactionContext {
- private final AtomicBoolean finished = new AtomicBoolean(false);
+ private enum Status {
+ WORKING, PRE, POST;
+ }
+
+ private final AtomicReference<Status> status = new AtomicReference<>(Status.WORKING);
public NoTransactionContextImpl() {
super();
@@ -60,9 +64,9 @@
@Override
public void preCompletion(Runnable job) throws IllegalStateException {
- if (finished.get()) {
+ if (status.get() != Status.WORKING) {
throw new IllegalStateException(
- "The transaction context has finished");
+ "The scoped work has returned. No more pre-completion callbacks can be registered");
}
preCompletion.add(job);
@@ -71,9 +75,9 @@
@Override
public void postCompletion(Consumer<TransactionStatus> job)
throws IllegalStateException {
- if (finished.get()) {
+ if (status.get() == Status.POST) {
throw new IllegalStateException(
- "The transaction context has finished");
+ "Post completion callbacks have begun. No more post-completion callbacks can be registered");
}
postCompletion.add(job);
@@ -106,13 +110,14 @@
@Override
protected boolean isAlive() {
- return !finished.get();
+ return status.get() == Status.WORKING;
}
@Override
public void finish() {
- if(finished.compareAndSet(false, true)) {
+ if(status.compareAndSet(Status.WORKING, Status.PRE)) {
beforeCompletion(() -> {});
+ status.set(Status.POST);
afterCompletion(NO_TRANSACTION);
}
}
diff --git a/tx-control-services/tx-control-service-common/src/test/java/org/apache/aries/tx/control/service/common/impl/NoTransactionContextTest.java b/tx-control-services/tx-control-service-common/src/test/java/org/apache/aries/tx/control/service/common/impl/NoTransactionContextTest.java
index 4cf4c81..d1e1219 100644
--- a/tx-control-services/tx-control-service-common/src/test/java/org/apache/aries/tx/control/service/common/impl/NoTransactionContextTest.java
+++ b/tx-control-services/tx-control-service-common/src/test/java/org/apache/aries/tx/control/service/common/impl/NoTransactionContextTest.java
@@ -23,6 +23,7 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import static org.osgi.service.transaction.control.TransactionStatus.COMMITTED;
import static org.osgi.service.transaction.control.TransactionStatus.NO_TRANSACTION;
import java.util.concurrent.atomic.AtomicInteger;
@@ -236,6 +237,20 @@
assertEquals(5, value.get());
}
+
+ @Test
+ public void testPreCompletionRegisterPostCompletion() throws Exception {
+
+ AtomicInteger value = new AtomicInteger(2);
+
+ ctx.preCompletion(() -> ctx.postCompletion(t -> value.compareAndSet(1, t.ordinal())));
+
+ assertEquals(2, value.getAndSet(1));
+
+ ctx.finish();
+
+ assertEquals(NO_TRANSACTION.ordinal(), value.get());
+ }
@Test(expected=IllegalStateException.class)
public void testPreCompletionAfterEnd() throws Exception {