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

jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git


The following commit(s) were added to refs/heads/main by this push:
     new e46b803  Add tests and documentation for transaction policies
e46b803 is described below

commit e46b8030e256491bb80a7c1ca7ba0c5c3e7609a7
Author: James Netherton <[email protected]>
AuthorDate: Thu May 27 10:12:34 2021 +0100

    Add tests and documentation for transaction policies
---
 .../ROOT/pages/reference/extensions/jta.adoc       |  33 +++++-
 extensions/jta/deployment/pom.xml                  |  10 ++
 .../jta/MandatoryJtaTransactionPolicyTest.java     |  89 ++++++++++++++
 .../quarkus/component/jta/MockTransaction.java     |  60 ++++++++++
 .../jta/MockTransactionManagerProducer.java        |  38 ++++++
 .../jta/NeverJtaTransactionPolicyTest.java         |  79 ++++++++++++
 .../jta/NotSupportedJtaTransactionPolicyTest.java  |  72 +++++++++++
 .../jta/RequiredJtaTransactionPolicyTest.java      | 132 +++++++++++++++++++++
 .../jta/RequiresNewJtaTransactionPolicyTest.java   |  92 ++++++++++++++
 .../jta/SupportsJtaTransactionPolicyTest.java      |  66 +++++++++++
 extensions/jta/runtime/src/main/doc/usage.adoc     |  33 +++++-
 .../quarkus/component/jta/it/JtaResource.java      |   3 +-
 .../camel/quarkus/component/jta/it/JtaRoutes.java  |   4 +-
 .../camel/quarkus/component/jta/it/JtaTest.java    |  46 +++++--
 14 files changed, 739 insertions(+), 18 deletions(-)

diff --git a/docs/modules/ROOT/pages/reference/extensions/jta.adoc 
b/docs/modules/ROOT/pages/reference/extensions/jta.adoc
index 3ec503b..f1f213b 100644
--- a/docs/modules/ROOT/pages/reference/extensions/jta.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/jta.adoc
@@ -43,7 +43,6 @@ Check the xref:user-guide/index.adoc[User guide] for more 
information about writ
 
 This extension should be added when you need to use the `transacted()` EIP in 
the router. It leverages the transaction capabilities provided by the 
narayana-jta extension in Quarkus. 
 
-
 Refer to the https://quarkus.io/guides/transaction[Quarkus Transaction guide] 
for the more details about transaction support. For a simple usage:
 
 [source,java]
@@ -55,3 +54,35 @@ from("direct:transaction")
     .log("all data are in the ds1 and ds2")
 ----
 
+Support is provided for various transaction policies.
+
+[cols="50,.^50]
+|===
+|Policy | Description
+
+| `PROPAGATION_MANDATORY`
+
+| Support a current transaction; throw an exception if no current transaction 
exists.
+
+| `PROPAGATION_NEVER`
+
+| Do not support a current transaction; throw an exception if a current 
transaction exists.
+
+| `PROPAGATION_NOT_SUPPORTED`
+
+| Do not support a current transaction; rather always execute 
non-transactionally.
+
+| `PROPAGATION_REQUIRED`
+
+| Support a current transaction; create a new one if none exists.
+
+| `PROPAGATION_REQUIRES_NEW`
+
+| Create a new transaction, suspending the current transaction if one exists.
+
+| `PROPAGATION_SUPPORTS`
+
+| Support a current transaction; execute non-transactionally if none exists.
+
+|===
+
diff --git a/extensions/jta/deployment/pom.xml 
b/extensions/jta/deployment/pom.xml
index 1f41b53..e845f68 100644
--- a/extensions/jta/deployment/pom.xml
+++ b/extensions/jta/deployment/pom.xml
@@ -42,6 +42,16 @@
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-narayana-jta-deployment</artifactId>
         </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-junit5-internal</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-junit5-mockito</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git 
a/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/MandatoryJtaTransactionPolicyTest.java
 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/MandatoryJtaTransactionPolicyTest.java
new file mode 100644
index 0000000..4ac9c59
--- /dev/null
+++ 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/MandatoryJtaTransactionPolicyTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.camel.quarkus.component.jta;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.transaction.Status;
+import javax.transaction.TransactionManager;
+
+import io.quarkus.test.QuarkusUnitTest;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.jsoup.helper.Validate.fail;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.when;
+
+public class MandatoryJtaTransactionPolicyTest {
+
+    @RegisterExtension
+    static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
+            .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+                    .addClass(MockTransactionManagerProducer.class));
+
+    @Inject
+    TransactionManager transactionManager;
+
+    @Inject
+    @Named("PROPAGATION_MANDATORY")
+    MandatoryJtaTransactionPolicy transactionPolicy;
+
+    @AfterEach
+    public void afterEach() {
+        reset(transactionManager);
+    }
+
+    @Test
+    public void runTransactionPolicyNoTransaction() throws Exception {
+        
when(transactionManager.getStatus()).thenReturn(Status.STATUS_NO_TRANSACTION);
+        try {
+            transactionPolicy.run(() -> fail("Transaction policy should not 
run"));
+        } catch (Throwable throwable) {
+            assertTrue(throwable instanceof IllegalStateException);
+        }
+    }
+
+    @Test
+    public void runTransactionPolicyMarkedRollback() throws Exception {
+        
when(transactionManager.getStatus()).thenReturn(Status.STATUS_MARKED_ROLLBACK);
+        try {
+            transactionPolicy.run(() -> fail("Transaction policy should not 
run"));
+        } catch (Throwable throwable) {
+            assertTrue(throwable instanceof IllegalStateException);
+        }
+    }
+
+    @Test
+    public void runTransactionPolicyActiveTransaction() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        when(transactionManager.getStatus()).thenReturn(Status.STATUS_ACTIVE);
+        try {
+            transactionPolicy.run(() -> latch.countDown());
+        } catch (Throwable throwable) {
+            fail("Expected transaction policy to run successfully");
+        }
+        assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+}
diff --git 
a/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/MockTransaction.java
 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/MockTransaction.java
new file mode 100644
index 0000000..b947b8b
--- /dev/null
+++ 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/MockTransaction.java
@@ -0,0 +1,60 @@
+/*
+ * 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.camel.quarkus.component.jta;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.RollbackException;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.xa.XAResource;
+
+public class MockTransaction implements Transaction {
+
+    @Override
+    public void commit() throws RollbackException, HeuristicMixedException, 
HeuristicRollbackException, SecurityException,
+            IllegalStateException, SystemException {
+    }
+
+    @Override
+    public boolean delistResource(XAResource xaRes, int flag) throws 
IllegalStateException, SystemException {
+        return false;
+    }
+
+    @Override
+    public boolean enlistResource(XAResource xaRes) throws RollbackException, 
IllegalStateException, SystemException {
+        return false;
+    }
+
+    @Override
+    public int getStatus() throws SystemException {
+        return 0;
+    }
+
+    @Override
+    public void registerSynchronization(Synchronization sync) throws 
RollbackException, IllegalStateException, SystemException {
+    }
+
+    @Override
+    public void rollback() throws IllegalStateException, SystemException {
+    }
+
+    @Override
+    public void setRollbackOnly() throws IllegalStateException, 
SystemException {
+    }
+}
diff --git 
a/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/MockTransactionManagerProducer.java
 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/MockTransactionManagerProducer.java
new file mode 100644
index 0000000..ff31495
--- /dev/null
+++ 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/MockTransactionManagerProducer.java
@@ -0,0 +1,38 @@
+/*
+ * 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.camel.quarkus.component.jta;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Alternative;
+import javax.enterprise.inject.Produces;
+import javax.inject.Singleton;
+import javax.transaction.TransactionManager;
+
+import io.quarkus.arc.AlternativePriority;
+import org.mockito.Mockito;
+
+@ApplicationScoped
+public class MockTransactionManagerProducer {
+
+    @Alternative
+    @AlternativePriority(1)
+    @Produces
+    @Singleton
+    public TransactionManager transactionManager() {
+        return Mockito.mock(TransactionManager.class);
+    }
+}
diff --git 
a/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/NeverJtaTransactionPolicyTest.java
 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/NeverJtaTransactionPolicyTest.java
new file mode 100644
index 0000000..ae2f2f5
--- /dev/null
+++ 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/NeverJtaTransactionPolicyTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.camel.quarkus.component.jta;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.transaction.Status;
+import javax.transaction.TransactionManager;
+
+import io.quarkus.test.QuarkusUnitTest;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.jsoup.helper.Validate.fail;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.when;
+
+public class NeverJtaTransactionPolicyTest {
+
+    @RegisterExtension
+    static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
+            .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+                    .addClass(MockTransactionManagerProducer.class));
+
+    @Inject
+    TransactionManager transactionManager;
+
+    @Inject
+    @Named("PROPAGATION_NEVER")
+    NeverJtaTransactionPolicy transactionPolicy;
+
+    @AfterEach
+    public void afterEach() {
+        reset(transactionManager);
+    }
+
+    @Test
+    public void runTransactionPolicyActiveTransaction() throws Exception {
+        when(transactionManager.getStatus()).thenReturn(Status.STATUS_ACTIVE);
+        try {
+            transactionPolicy.run(() -> fail("Transaction policy should not 
run"));
+        } catch (Throwable throwable) {
+            assertTrue(throwable instanceof IllegalStateException);
+        }
+    }
+
+    @Test
+    public void runTransactionPolicyNoTransaction() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        
when(transactionManager.getStatus()).thenReturn(Status.STATUS_NO_TRANSACTION);
+        try {
+            transactionPolicy.run(() -> latch.countDown());
+        } catch (Throwable throwable) {
+            fail("Expected transaction policy to run successfully");
+        }
+        assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+}
diff --git 
a/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/NotSupportedJtaTransactionPolicyTest.java
 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/NotSupportedJtaTransactionPolicyTest.java
new file mode 100644
index 0000000..bde99c1
--- /dev/null
+++ 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/NotSupportedJtaTransactionPolicyTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.camel.quarkus.component.jta;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.transaction.TransactionManager;
+
+import io.quarkus.test.QuarkusUnitTest;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.jsoup.helper.Validate.fail;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class NotSupportedJtaTransactionPolicyTest {
+
+    @RegisterExtension
+    static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
+            .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+                    .addClasses(MockTransactionManagerProducer.class, 
MockTransaction.class));
+
+    @Inject
+    TransactionManager transactionManager;
+
+    @Inject
+    @Named("PROPAGATION_NOT_SUPPORTED")
+    NotSupportedJtaTransactionPolicy transactionPolicy;
+
+    @AfterEach
+    public void afterEach() {
+        reset(transactionManager);
+    }
+
+    @Test
+    public void runTransactionPolicy() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        MockTransaction transaction = new MockTransaction();
+        when(transactionManager.suspend()).thenReturn(transaction);
+        try {
+            transactionPolicy.run(() -> latch.countDown());
+        } catch (Throwable throwable) {
+            fail("Expected transaction policy to run successfully");
+        }
+        assertTrue(latch.await(5, TimeUnit.SECONDS));
+        verify(transactionManager, times(1)).resume(transaction);
+    }
+}
diff --git 
a/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/RequiredJtaTransactionPolicyTest.java
 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/RequiredJtaTransactionPolicyTest.java
new file mode 100644
index 0000000..3686226
--- /dev/null
+++ 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/RequiredJtaTransactionPolicyTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.camel.quarkus.component.jta;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.transaction.Status;
+import javax.transaction.TransactionManager;
+
+import io.quarkus.test.QuarkusUnitTest;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.jsoup.helper.Validate.fail;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class RequiredJtaTransactionPolicyTest {
+
+    @RegisterExtension
+    static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
+            .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+                    .addClass(MockTransactionManagerProducer.class));
+
+    @Inject
+    TransactionManager transactionManager;
+
+    @Inject
+    @Named("PROPAGATION_REQUIRED")
+    RequiredJtaTransactionPolicy transactionPolicy;
+
+    @AfterEach
+    public void afterEach() {
+        reset(transactionManager);
+    }
+
+    @Test
+    public void runTransactionPolicyNoTransaction() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        
when(transactionManager.getStatus()).thenReturn(Status.STATUS_NO_TRANSACTION);
+        try {
+            transactionPolicy.run(() -> latch.countDown());
+        } catch (Throwable throwable) {
+            fail("Expected transaction policy to run successfully");
+        }
+        assertTrue(latch.await(5, TimeUnit.SECONDS));
+        verify(transactionManager, times(1)).begin();
+        verify(transactionManager, times(1)).commit();
+    }
+
+    @Test
+    public void runTransactionPolicyMarkedRollback() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        
when(transactionManager.getStatus()).thenReturn(Status.STATUS_MARKED_ROLLBACK);
+        try {
+            transactionPolicy.run(() -> latch.countDown());
+        } catch (Throwable throwable) {
+            fail("Expected transaction policy to run successfully");
+        }
+        assertTrue(latch.await(5, TimeUnit.SECONDS));
+        verify(transactionManager, times(1)).begin();
+        verify(transactionManager, times(1)).commit();
+    }
+
+    @Test
+    public void runTransactionPolicyActiveTransaction() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        when(transactionManager.getStatus()).thenReturn(Status.STATUS_ACTIVE);
+        try {
+            transactionPolicy.run(() -> latch.countDown());
+        } catch (Throwable throwable) {
+            fail("Expected transaction policy to run successfully");
+        }
+        assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void runTransactionPolicyWithException() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        
when(transactionManager.getStatus()).thenReturn(Status.STATUS_NO_TRANSACTION);
+        try {
+            transactionPolicy.run(() -> {
+                latch.countDown();
+                throw new Exception("Simulated exception");
+            });
+        } catch (Throwable throwable) {
+            // Expected
+        }
+        assertTrue(latch.await(5, TimeUnit.SECONDS));
+        verify(transactionManager, times(1)).rollback();
+    }
+
+    @Test
+    public void runTransactionPolicyWithExceptionActiveTransaction() throws 
Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        when(transactionManager.getStatus()).thenReturn(Status.STATUS_ACTIVE);
+        try {
+            transactionPolicy.run(() -> {
+                latch.countDown();
+                throw new Exception("Simulated exception");
+            });
+        } catch (Throwable throwable) {
+            // Expected
+        }
+        assertTrue(latch.await(5, TimeUnit.SECONDS));
+        verify(transactionManager, times(1)).setRollbackOnly();
+    }
+
+}
diff --git 
a/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/RequiresNewJtaTransactionPolicyTest.java
 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/RequiresNewJtaTransactionPolicyTest.java
new file mode 100644
index 0000000..64a3d16
--- /dev/null
+++ 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/RequiresNewJtaTransactionPolicyTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.camel.quarkus.component.jta;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.transaction.Status;
+import javax.transaction.TransactionManager;
+
+import io.quarkus.test.QuarkusUnitTest;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.jsoup.helper.Validate.fail;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class RequiresNewJtaTransactionPolicyTest {
+
+    @RegisterExtension
+    static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
+            .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+                    .addClasses(MockTransactionManagerProducer.class, 
MockTransaction.class));
+
+    @Inject
+    TransactionManager transactionManager;
+
+    @Inject
+    @Named("PROPAGATION_REQUIRES_NEW")
+    RequiresNewJtaTransactionPolicy transactionPolicy;
+
+    @AfterEach
+    public void afterEach() {
+        reset(transactionManager);
+    }
+
+    @Test
+    public void runTransactionPolicy() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        MockTransaction transaction = new MockTransaction();
+        when(transactionManager.suspend()).thenReturn(transaction);
+        
when(transactionManager.getStatus()).thenReturn(Status.STATUS_NO_TRANSACTION);
+        try {
+            transactionPolicy.run(() -> latch.countDown());
+        } catch (Throwable throwable) {
+            fail("Expected transaction policy to run successfully");
+        }
+        assertTrue(latch.await(5, TimeUnit.SECONDS));
+        verify(transactionManager, times(1)).begin();
+        verify(transactionManager, times(1)).commit();
+        verify(transactionManager, times(1)).resume(transaction);
+    }
+
+    @Test
+    public void runTransactionPolicyWithException() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        
when(transactionManager.getStatus()).thenReturn(Status.STATUS_NO_TRANSACTION);
+        try {
+            transactionPolicy.run(() -> {
+                latch.countDown();
+                throw new Exception("Simulated exception");
+            });
+        } catch (Throwable throwable) {
+            // Expected
+        }
+        assertTrue(latch.await(5, TimeUnit.SECONDS));
+        verify(transactionManager, times(1)).rollback();
+    }
+}
diff --git 
a/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/SupportsJtaTransactionPolicyTest.java
 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/SupportsJtaTransactionPolicyTest.java
new file mode 100644
index 0000000..8b43402
--- /dev/null
+++ 
b/extensions/jta/deployment/src/test/java/org/apache/camel/quarkus/component/jta/SupportsJtaTransactionPolicyTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.camel.quarkus.component.jta;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.transaction.TransactionManager;
+
+import io.quarkus.test.QuarkusUnitTest;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.jsoup.helper.Validate.fail;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.reset;
+
+public class SupportsJtaTransactionPolicyTest {
+
+    @RegisterExtension
+    static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
+            .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+                    .addClass(MockTransactionManagerProducer.class));
+
+    @Inject
+    TransactionManager transactionManager;
+
+    @Inject
+    @Named("PROPAGATION_SUPPORTS")
+    SupportsJtaTransactionPolicy transactionPolicy;
+
+    @AfterEach
+    public void afterEach() {
+        reset(transactionManager);
+    }
+
+    @Test
+    public void runTransactionPolicy() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        try {
+            transactionPolicy.run(() -> latch.countDown());
+        } catch (Throwable throwable) {
+            fail("Expected transaction policy to run successfully");
+        }
+        assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+}
diff --git a/extensions/jta/runtime/src/main/doc/usage.adoc 
b/extensions/jta/runtime/src/main/doc/usage.adoc
index 1aadb4a..56c279f 100644
--- a/extensions/jta/runtime/src/main/doc/usage.adoc
+++ b/extensions/jta/runtime/src/main/doc/usage.adoc
@@ -1,6 +1,5 @@
 This extension should be added when you need to use the `transacted()` EIP in 
the router. It leverages the transaction capabilities provided by the 
narayana-jta extension in Quarkus. 
 
-
 Refer to the https://quarkus.io/guides/transaction[Quarkus Transaction guide] 
for the more details about transaction support. For a simple usage:
 
 [source,java]
@@ -11,3 +10,35 @@ from("direct:transaction")
     .to("sql:INSERT INTO A TABLE ...?dataSource=ds2")
     .log("all data are in the ds1 and ds2")
 ----
+
+Support is provided for various transaction policies.
+
+[cols="50,.^50]
+|===
+|Policy | Description
+
+| `PROPAGATION_MANDATORY`
+
+| Support a current transaction; throw an exception if no current transaction 
exists.
+
+| `PROPAGATION_NEVER`
+
+| Do not support a current transaction; throw an exception if a current 
transaction exists.
+
+| `PROPAGATION_NOT_SUPPORTED`
+
+| Do not support a current transaction; rather always execute 
non-transactionally.
+
+| `PROPAGATION_REQUIRED`
+
+| Support a current transaction; create a new one if none exists.
+
+| `PROPAGATION_REQUIRES_NEW`
+
+| Create a new transaction, suspending the current transaction if one exists.
+
+| `PROPAGATION_SUPPORTS`
+
+| Support a current transaction; execute non-transactionally if none exists.
+
+|===
diff --git 
a/integration-tests/jta/src/main/java/org/apache/camel/quarkus/component/jta/it/JtaResource.java
 
b/integration-tests/jta/src/main/java/org/apache/camel/quarkus/component/jta/it/JtaResource.java
index 7fc6035..588f8d9 100644
--- 
a/integration-tests/jta/src/main/java/org/apache/camel/quarkus/component/jta/it/JtaResource.java
+++ 
b/integration-tests/jta/src/main/java/org/apache/camel/quarkus/component/jta/it/JtaResource.java
@@ -67,7 +67,8 @@ public class JtaResource {
                     statement.execute("drop table example");
                 } catch (Exception ignored) {
                 }
-                statement.execute("create table example (id serial primary 
key, message varchar(255) not null)");
+                statement.execute(
+                        "create table example (id serial primary key, message 
varchar(255) not null, origin varchar(5) not null)");
             }
         }
     }
diff --git 
a/integration-tests/jta/src/main/java/org/apache/camel/quarkus/component/jta/it/JtaRoutes.java
 
b/integration-tests/jta/src/main/java/org/apache/camel/quarkus/component/jta/it/JtaRoutes.java
index a39d446..2828635 100644
--- 
a/integration-tests/jta/src/main/java/org/apache/camel/quarkus/component/jta/it/JtaRoutes.java
+++ 
b/integration-tests/jta/src/main/java/org/apache/camel/quarkus/component/jta/it/JtaRoutes.java
@@ -52,7 +52,7 @@ public class JtaRoutes extends RouteBuilder {
                 .transacted()
                 .setHeader("message", body())
                 
.to("jms:queue:txTest?connectionFactory=#xaConnectionFactory&disableReplyTo=true")
-                .transform().simple("insert into example(message) values 
('${body}')")
+                .transform().simple("insert into example(message, origin) 
values ('${body}', 'jdbc')")
                 .to("jdbc:camel-ds?resetAutoCommit=false")
                 .choice()
                 .when(header("message").startsWith("fail"))
@@ -68,7 +68,7 @@ public class JtaRoutes extends RouteBuilder {
                 .transacted()
                 .setHeader("message", body())
                 
.to("jms:queue:txTest?connectionFactory=#xaConnectionFactory&disableReplyTo=true")
-                .to("sql:insert into example(message) values (:#message)")
+                .to("sql:insert into example(message, origin) values 
(:#message, 'sqltx')")
                 .choice()
                 .when(header("message").startsWith("fail"))
                 .log("Failing forever with exception")
diff --git 
a/integration-tests/jta/src/test/java/org/apache/camel/quarkus/component/jta/it/JtaTest.java
 
b/integration-tests/jta/src/test/java/org/apache/camel/quarkus/component/jta/it/JtaTest.java
index b518438..af1defc 100644
--- 
a/integration-tests/jta/src/test/java/org/apache/camel/quarkus/component/jta/it/JtaTest.java
+++ 
b/integration-tests/jta/src/test/java/org/apache/camel/quarkus/component/jta/it/JtaTest.java
@@ -16,12 +16,21 @@
  */
 package org.apache.camel.quarkus.component.jta.it;
 
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
 import io.quarkus.test.common.QuarkusTestResource;
 import io.quarkus.test.h2.H2DatabaseTestResource;
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.RestAssured;
 import io.restassured.http.ContentType;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 
 import static org.hamcrest.Matchers.is;
 
@@ -136,34 +145,32 @@ class JtaTest {
                 .body(is("not_supported"));
     }
 
-    @Test
-    public void testJdbcInTx() {
-        testTx("/jta/jdbc");
-    }
-
-    @Test
-    public void testSqlInTx() {
-        testTx("/jta/sqltx");
-    }
-
-    private void testTx(String url) {
+    @ParameterizedTest
+    @ValueSource(strings = { "jdbc", "sqltx" })
+    public void testTx(String url) throws SQLException {
         final String msg = java.util.UUID.randomUUID().toString().replace("-", 
"");
 
         RestAssured.given()
                 .contentType(ContentType.TEXT)
                 .body(msg)
-                .post(url)
+                .post("/jta/" + url)
                 .then()
                 .statusCode(201)
                 .body(is(msg + " added"));
 
+        // One row inserted
+        assertDBRowCount(url, 1);
+
         RestAssured.given()
                 .contentType(ContentType.TEXT)
                 .body("fail")
-                .post(url)
+                .post("/jta/" + url)
                 .then()
                 .statusCode(500);
 
+        // Should still have the original row as the other insert attempt was 
rolled back
+        assertDBRowCount(url, 1);
+
         RestAssured.given()
                 .contentType(ContentType.TEXT)
                 .get("/jta/mock")
@@ -172,4 +179,17 @@ class JtaTest {
                 .body(is("empty"))
                 .log();
     }
+
+    private void assertDBRowCount(String source, int expectedRowCount) throws 
SQLException {
+        try (Connection connection = 
DriverManager.getConnection("jdbc:h2:tcp://localhost/mem:test")) {
+            try (Statement statement = connection.createStatement()) {
+                try (ResultSet resultSet = statement
+                        .executeQuery("SELECT count(*) FROM example WHERE 
origin = '" + source + "'")) {
+                    if (resultSet.next()) {
+                        Assertions.assertEquals(expectedRowCount, 
resultSet.getInt(1));
+                    }
+                }
+            }
+        }
+    }
 }

Reply via email to