This is an automated email from the ASF dual-hosted git repository. ppalaga pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/master by this push: new 28ad160 Fix #1263 - Add the camel-jta extension (#1411) 28ad160 is described below commit 28ad1604e4821ffc907cc22d5b11c963c0a9e3ca Author: Amos Feng <zf...@redhat.com> AuthorDate: Sun Jun 28 22:08:12 2020 +0800 Fix #1263 - Add the camel-jta extension (#1411) --- .github/test-categories.yaml | 1 + docs/modules/ROOT/pages/extensions/jta.adoc | 28 +++++ .../pages/list-of-camel-quarkus-extensions.adoc | 4 +- extensions/jta/deployment/pom.xml | 67 +++++++++++ .../component/jta/deployment/JtaProcessor.java | 68 +++++++++++ extensions/jta/pom.xml | 39 ++++++ extensions/jta/runtime/pom.xml | 98 +++++++++++++++ .../jta/MandatoryJtaTransactionPolicy.java | 32 +++++ .../component/jta/NeverJtaTransactionPolicy.java | 33 +++++ .../jta/NotSupportedJtaTransactionPolicy.java | 35 ++++++ .../jta/RequiredJtaTransactionPolicy.java | 28 +++++ .../jta/RequiresNewJtaTransactionPolicy.java | 35 ++++++ .../jta/SupportsJtaTransactionPolicy.java | 28 +++++ .../jta/TransactionalJtaTransactionPolicy.java | 105 ++++++++++++++++ .../main/resources/META-INF/quarkus-extension.yaml | 29 +++++ extensions/pom.xml | 1 + integration-tests/jta/pom.xml | 130 ++++++++++++++++++++ .../quarkus/component/jta/it/JtaResource.java | 67 +++++++++++ .../camel/quarkus/component/jta/it/JtaRoutes.java | 51 ++++++++ .../camel/quarkus/component/jta/it/JtaIT.java | 24 ++++ .../camel/quarkus/component/jta/it/JtaTest.java | 134 +++++++++++++++++++++ integration-tests/pom.xml | 1 + poms/bom/pom.xml | 15 +++ 23 files changed, 1052 insertions(+), 1 deletion(-) diff --git a/.github/test-categories.yaml b/.github/test-categories.yaml index 1f99bda..ccf686e 100644 --- a/.github/test-categories.yaml +++ b/.github/test-categories.yaml @@ -54,6 +54,7 @@ foundation: - exec - file - hystrix + - jta - jsonpath - quartz - scheduler diff --git a/docs/modules/ROOT/pages/extensions/jta.adoc b/docs/modules/ROOT/pages/extensions/jta.adoc new file mode 100644 index 0000000..9ee1cc5 --- /dev/null +++ b/docs/modules/ROOT/pages/extensions/jta.adoc @@ -0,0 +1,28 @@ +// Do not edit directly! +// This file was generated by camel-quarkus-maven-plugin:update-extension-doc-page + +[[jta]] += JTA + +[.badges] +[.badge-key]##Since Camel Quarkus##[.badge-version]##1.0.0-CR3## [.badge-key]##JVM##[.badge-supported]##supported## [.badge-key]##Native##[.badge-supported]##supported## + +Enclose Camel routes in the transactions using Java Transaction API (JTA) and Narayana transaction manager + +== What's inside + +* https://camel.apache.org/components/latest/others/jta.html[JTA] + +Please refer to the above link for usage and configuration details. + +== Maven coordinates + +[source,xml] +---- +<dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-jta</artifactId> +</dependency> +---- + +Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications. diff --git a/docs/modules/ROOT/pages/list-of-camel-quarkus-extensions.adoc b/docs/modules/ROOT/pages/list-of-camel-quarkus-extensions.adoc index 13f45dc..8144a1f 100644 --- a/docs/modules/ROOT/pages/list-of-camel-quarkus-extensions.adoc +++ b/docs/modules/ROOT/pages/list-of-camel-quarkus-extensions.adoc @@ -433,7 +433,7 @@ Number of Camel languages: 13 in 7 JAR artifacts (0 deprecated) == Miscellaneous Extensions // others: START -Number of miscellaneous extensions: 16 in 16 JAR artifacts (1 deprecated) +Number of miscellaneous extensions: 17 in 17 JAR artifacts (1 deprecated) [width="100%",cols="4,1,1,1,5",options="header"] |=== @@ -451,6 +451,8 @@ Number of miscellaneous extensions: 16 in 16 JAR artifacts (1 deprecated) | xref:extensions/hystrix.adoc[Hystrix] | camel-quarkus-hystrix | Native + Stable | 1.0.0-M1 | *deprecated* Circuit Breaker EIP using Netflix Hystrix +| xref:extensions/jta.adoc[JTA] | camel-quarkus-jta | Native + Stable | 1.0.0-CR3 | Using Camel With JTA Transaction Manager + | xref:extensions/kotlin.adoc[Kotlin] | camel-quarkus-kotlin | Native + Stable | 1.0.0-M3 | Write Camel integration routes in Kotlin | xref:extensions/main.adoc[Main] | camel-quarkus-main | Native + Stable | 1.0.0-CR3 | Bootstrap Camel using Camel Main which brings advanced auto-configuration capabilities and integration with Quarkus Command Mode diff --git a/extensions/jta/deployment/pom.xml b/extensions/jta/deployment/pom.xml new file mode 100644 index 0000000..a7833ad --- /dev/null +++ b/extensions/jta/deployment/pom.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-jta-parent</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>camel-quarkus-jta-deployment</artifactId> + <name>Camel Quarkus :: JTA :: Deployment</name> + + <dependencies> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-core-deployment</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-jta</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-narayana-jta-deployment</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <annotationProcessorPaths> + <path> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-extension-processor</artifactId> + <version>${quarkus.version}</version> + </path> + </annotationProcessorPaths> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/extensions/jta/deployment/src/main/java/org/apache/camel/quarkus/component/jta/deployment/JtaProcessor.java b/extensions/jta/deployment/src/main/java/org/apache/camel/quarkus/component/jta/deployment/JtaProcessor.java new file mode 100644 index 0000000..085b9fb --- /dev/null +++ b/extensions/jta/deployment/src/main/java/org/apache/camel/quarkus/component/jta/deployment/JtaProcessor.java @@ -0,0 +1,68 @@ +/* + * 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.deployment; + +import com.arjuna.ats.internal.arjuna.utils.SocketProcessId; +import io.quarkus.arc.deployment.AdditionalBeanBuildItem; +import io.quarkus.deployment.Capabilities; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.FeatureBuildItem; +import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; +import org.apache.camel.quarkus.component.jta.MandatoryJtaTransactionPolicy; +import org.apache.camel.quarkus.component.jta.NeverJtaTransactionPolicy; +import org.apache.camel.quarkus.component.jta.NotSupportedJtaTransactionPolicy; +import org.apache.camel.quarkus.component.jta.RequiredJtaTransactionPolicy; +import org.apache.camel.quarkus.component.jta.RequiresNewJtaTransactionPolicy; +import org.apache.camel.quarkus.component.jta.SupportsJtaTransactionPolicy; + +class JtaProcessor { + + private static final String FEATURE = "camel-jta"; + + @BuildStep + FeatureBuildItem feature() { + return new FeatureBuildItem(FEATURE); + } + + @BuildStep + void transactedPolicy( + BuildProducer<AdditionalBeanBuildItem> additionalBeans, + BuildProducer<ReflectiveClassBuildItem> reflectiveClass, + Capabilities capabilities) { + if (capabilities.isCapabilityPresent(Capabilities.TRANSACTIONS)) { + AdditionalBeanBuildItem.Builder builder = AdditionalBeanBuildItem.builder(); + builder.addBeanClass(RequiredJtaTransactionPolicy.class); + builder.addBeanClass(RequiresNewJtaTransactionPolicy.class); + builder.addBeanClass(MandatoryJtaTransactionPolicy.class); + builder.addBeanClass(NeverJtaTransactionPolicy.class); + builder.addBeanClass(NotSupportedJtaTransactionPolicy.class); + builder.addBeanClass(SupportsJtaTransactionPolicy.class); + + additionalBeans.produce(builder.build()); + + reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, + IllegalStateException.class.getName())); + } + } + + @BuildStep //TODO remove this BuildStep when https://github.com/quarkusio/quarkus/issues/10180 gets resolved + void registerNarayanaReflectiveClass(BuildProducer<ReflectiveClassBuildItem> reflectiveClass) { + reflectiveClass.produce( + new ReflectiveClassBuildItem(false, false, SocketProcessId.class.getName())); + } +} diff --git a/extensions/jta/pom.xml b/extensions/jta/pom.xml new file mode 100644 index 0000000..62d65f8 --- /dev/null +++ b/extensions/jta/pom.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-build-parent</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>../../poms/build-parent/pom.xml</relativePath> + </parent> + + <artifactId>camel-quarkus-jta-parent</artifactId> + <name>Camel Quarkus :: JTA</name> + <packaging>pom</packaging> + + <modules> + <module>deployment</module> + <module>runtime</module> + </modules> +</project> diff --git a/extensions/jta/runtime/pom.xml b/extensions/jta/runtime/pom.xml new file mode 100644 index 0000000..a2e8521 --- /dev/null +++ b/extensions/jta/runtime/pom.xml @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-jta-parent</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>camel-quarkus-jta</artifactId> + <name>Camel Quarkus :: JTA :: Runtime</name> + <description>Enclose Camel routes in the transactions using Java Transaction API (JTA) and Narayana transaction manager</description> + + <properties> + <firstVersion>1.0.0-CR3</firstVersion> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-bom</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-core</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-jta</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-narayana-jta</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-maven-plugin</artifactId> + <executions> + <execution> + <id>update-extension-doc-page</id> + <goals><goal>update-extension-doc-page</goal></goals> + <phase>process-classes</phase> + </execution> + </executions> + </plugin> + <plugin> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-bootstrap-maven-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <annotationProcessorPaths> + <path> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-extension-processor</artifactId> + <version>${quarkus.version}</version> + </path> + </annotationProcessorPaths> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/MandatoryJtaTransactionPolicy.java b/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/MandatoryJtaTransactionPolicy.java new file mode 100644 index 0000000..8c7f106 --- /dev/null +++ b/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/MandatoryJtaTransactionPolicy.java @@ -0,0 +1,32 @@ +/* + * 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.inject.Named; + +@Named("PROPAGATION_MANDATORY") +public final class MandatoryJtaTransactionPolicy extends TransactionalJtaTransactionPolicy { + + @Override + public void run(final Runnable runnable) throws Throwable { + if (!hasActiveTransaction()) { + throw new IllegalStateException( + "Policy 'PROPAGATION_MANDATORY' is configured but no active transaction was found!"); + } + runWithTransaction(runnable, false); + } +} diff --git a/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/NeverJtaTransactionPolicy.java b/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/NeverJtaTransactionPolicy.java new file mode 100644 index 0000000..da23634 --- /dev/null +++ b/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/NeverJtaTransactionPolicy.java @@ -0,0 +1,33 @@ +/* + * 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.inject.Named; + +@Named("PROPAGATION_NEVER") +public final class NeverJtaTransactionPolicy extends TransactionalJtaTransactionPolicy { + + @Override + public void run(final Runnable runnable) throws Throwable { + if (hasActiveTransaction()) { + throw new IllegalStateException( + "Policy 'PROPAGATION_NEVER' is configured but an active transaction was found!"); + } + + runnable.run(); + } +} diff --git a/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/NotSupportedJtaTransactionPolicy.java b/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/NotSupportedJtaTransactionPolicy.java new file mode 100644 index 0000000..f058651 --- /dev/null +++ b/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/NotSupportedJtaTransactionPolicy.java @@ -0,0 +1,35 @@ +/* + * 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.inject.Named; +import javax.transaction.Transaction; + +@Named("PROPAGATION_NOT_SUPPORTED") +public final class NotSupportedJtaTransactionPolicy extends TransactionalJtaTransactionPolicy { + + @Override + public void run(final Runnable runnable) throws Throwable { + Transaction suspendedTransaction = null; + try { + suspendedTransaction = suspendTransaction(); + runnable.run(); + } finally { + resumeTransaction(suspendedTransaction); + } + } +} diff --git a/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/RequiredJtaTransactionPolicy.java b/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/RequiredJtaTransactionPolicy.java new file mode 100644 index 0000000..d157fa9 --- /dev/null +++ b/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/RequiredJtaTransactionPolicy.java @@ -0,0 +1,28 @@ +/* + * 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.inject.Named; + +@Named("PROPAGATION_REQUIRED") +public final class RequiredJtaTransactionPolicy extends TransactionalJtaTransactionPolicy { + + @Override + public void run(final Runnable runnable) throws Throwable { + runWithTransaction(runnable, !hasActiveTransaction()); + } +} diff --git a/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/RequiresNewJtaTransactionPolicy.java b/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/RequiresNewJtaTransactionPolicy.java new file mode 100644 index 0000000..1e4af6f --- /dev/null +++ b/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/RequiresNewJtaTransactionPolicy.java @@ -0,0 +1,35 @@ +/* + * 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.inject.Named; +import javax.transaction.Transaction; + +@Named("PROPAGATION_REQUIRES_NEW") +public final class RequiresNewJtaTransactionPolicy extends TransactionalJtaTransactionPolicy { + + @Override + public void run(final Runnable runnable) throws Throwable { + Transaction suspendedTransaction = null; + try { + suspendedTransaction = suspendTransaction(); + runWithTransaction(runnable, true); + } finally { + resumeTransaction(suspendedTransaction); + } + } +} diff --git a/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/SupportsJtaTransactionPolicy.java b/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/SupportsJtaTransactionPolicy.java new file mode 100644 index 0000000..a898d1c --- /dev/null +++ b/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/SupportsJtaTransactionPolicy.java @@ -0,0 +1,28 @@ +/* + * 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.inject.Named; + +@Named("PROPAGATION_SUPPORTS") +public final class SupportsJtaTransactionPolicy extends TransactionalJtaTransactionPolicy { + + @Override + public void run(final Runnable runnable) throws Throwable { + runnable.run(); + } +} diff --git a/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/TransactionalJtaTransactionPolicy.java b/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/TransactionalJtaTransactionPolicy.java new file mode 100644 index 0000000..16dc630 --- /dev/null +++ b/extensions/jta/runtime/src/main/java/org/apache/camel/quarkus/component/jta/TransactionalJtaTransactionPolicy.java @@ -0,0 +1,105 @@ +/* + * 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.inject.Inject; +import javax.transaction.HeuristicMixedException; +import javax.transaction.HeuristicRollbackException; +import javax.transaction.RollbackException; +import javax.transaction.Status; +import javax.transaction.SystemException; +import javax.transaction.Transaction; +import javax.transaction.TransactionManager; + +import org.apache.camel.CamelException; +import org.apache.camel.jta.JtaTransactionPolicy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Helper methods for transaction handling + */ +public abstract class TransactionalJtaTransactionPolicy extends JtaTransactionPolicy { + + private static final Logger LOG = LoggerFactory.getLogger(TransactionalJtaTransactionPolicy.class); + + @Inject + TransactionManager transactionManager; + + protected void runWithTransaction(final Runnable runnable, final boolean isNew) throws Throwable { + if (isNew) { + begin(); + } + try { + runnable.run(); + } catch (Throwable e) { + rollback(isNew); + throw e; + } + if (isNew) { + commit(); + } + } + + private void begin() throws Exception { + transactionManager.begin(); + } + + private void commit() throws Exception { + try { + transactionManager.commit(); + } catch (HeuristicMixedException | HeuristicRollbackException | RollbackException | SystemException e) { + throw new CamelException("Unable to commit transaction", e); + } catch (Exception | Error e) { + rollback(true); + throw e; + } + } + + final protected void rollback(boolean isNew) throws Exception { + try { + if (isNew) { + transactionManager.rollback(); + } else { + transactionManager.setRollbackOnly(); + } + } catch (Throwable e) { + LOG.warn("Could not rollback transaction!", e); + } + } + + final protected Transaction suspendTransaction() throws Exception { + return transactionManager.suspend(); + } + + final protected void resumeTransaction(final Transaction suspendedTransaction) { + if (suspendedTransaction == null) { + return; + } + + try { + transactionManager.resume(suspendedTransaction); + } catch (Throwable e) { + LOG.warn("Could not resume transaction!", e); + } + } + + final protected boolean hasActiveTransaction() throws Exception { + return transactionManager.getStatus() != Status.STATUS_MARKED_ROLLBACK + && transactionManager.getStatus() != Status.STATUS_NO_TRANSACTION; + } +} diff --git a/extensions/jta/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/jta/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000..c79d8e7 --- /dev/null +++ b/extensions/jta/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,29 @@ +# +# 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. +# + +# This is a generated file. Do not edit directly! +# To re-generate, run the following command from the top level directory: +# +# mvn -N cq:update-quarkus-metadata +# +--- +name: "Camel JTA" +description: "Enclose Camel routes in the transactions using Java Transaction API (JTA) and Narayana transaction manager" +metadata: + guide: "https://camel.apache.org/camel-quarkus/latest/extensions/jta.html" + categories: + - "integration" diff --git a/extensions/pom.xml b/extensions/pom.xml index e14064d..b208a07 100644 --- a/extensions/pom.xml +++ b/extensions/pom.xml @@ -114,6 +114,7 @@ <module>johnzon</module> <module>json-validator</module> <module>jsonpath</module> + <module>jta</module> <module>kafka</module> <module>kotlin</module> <module>kubernetes</module> diff --git a/integration-tests/jta/pom.xml b/integration-tests/jta/pom.xml new file mode 100644 index 0000000..4916910 --- /dev/null +++ b/integration-tests/jta/pom.xml @@ -0,0 +1,130 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-integration-tests</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>camel-quarkus-integration-test-jta</artifactId> + <name>Camel Quarkus :: Integration Tests :: JTA</name> + <description>Integration tests for Camel Quarkus JTA extension</description> + + <properties> + <!-- mvnd, a.k.a. Maven Daemon: https://github.com/gnodet/mvnd --> + <!-- The following rule tells mvnd to build the listed deployment modules before this module. --> + <!-- This is important because mvnd builds modules in parallel by default. The deployment modules are not --> + <!-- explicit dependencies of this module in the Maven sense, although they are required by the Quarkus Maven plugin. --> + <!-- Please update rule whenever you change the dependencies of this module by running --> + <!-- mvn process-resources -Pformat from the root directory --> + <mvnd.builder.rule>camel-quarkus-jta-deployment,camel-quarkus-support-policy-deployment</mvnd.builder.rule> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-bom-test</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-direct</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-jta</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-resteasy</artifactId> + </dependency> + + <!-- test dependencies --> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-junit5</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.rest-assured</groupId> + <artifactId>rest-assured</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>build</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <profiles> + <profile> + <id>native</id> + <activation> + <property> + <name>native</name> + </property> + </activation> + <properties> + <quarkus.package.type>native</quarkus.package.type> + </properties> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-failsafe-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>integration-test</goal> + <goal>verify</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> + +</project> 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 new file mode 100644 index 0000000..5c757a5 --- /dev/null +++ b/integration-tests/jta/src/main/java/org/apache/camel/quarkus/component/jta/it/JtaResource.java @@ -0,0 +1,67 @@ +/* + * 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.it; + +import java.net.URI; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.transaction.Transactional; +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.apache.camel.ProducerTemplate; +import org.jboss.logging.Logger; + +@Path("/jta") +@ApplicationScoped +public class JtaResource { + + private static final Logger LOG = Logger.getLogger(JtaResource.class); + + @Inject + ProducerTemplate producerTemplate; + + @Path("/{policy}") + @POST + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + public Response post(@PathParam("policy") String policy, String message) throws Exception { + LOG.infof("Sending to jta policy %s: %s", policy, message); + final String response = producerTemplate.requestBody("direct:" + policy, message, String.class); + LOG.infof("Got response from jta: %s", response); + return Response + .created(new URI("https://camel.apache.org/")) + .entity(response) + .build(); + } + + @Path("/in_tx/{policy}") + @POST + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + @Transactional + public Response postInTx(@PathParam("policy") String policy, String message) throws Exception { + return post(policy, message); + } + +} 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 new file mode 100644 index 0000000..a2fd01f --- /dev/null +++ b/integration-tests/jta/src/main/java/org/apache/camel/quarkus/component/jta/it/JtaRoutes.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.camel.quarkus.component.jta.it; + +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; + +public class JtaRoutes extends RouteBuilder { + @Override + public void configure() throws Exception { + onException(IllegalStateException.class).maximumRedeliveries(0).handled(true) + .process(exchange -> { + Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); + if (cause != null) { + exchange.getMessage().setBody(cause.getMessage()); + } + }); + + from("direct:required") + .transacted().transform().constant("required"); + + from("direct:requires_new") + .transacted("PROPAGATION_REQUIRES_NEW").transform().constant("requires_new"); + + from("direct:mandatory") + .transacted("PROPAGATION_MANDATORY").transform().constant("mandatory"); + + from("direct:never") + .transacted("PROPAGATION_NEVER").transform().constant("never"); + + from("direct:supports") + .transacted("PROPAGATION_SUPPORTS").transform().constant("supports"); + + from("direct:not_supported") + .transacted("PROPAGATION_NOT_SUPPORTED").transform().constant("not_supported"); + } +} diff --git a/integration-tests/jta/src/test/java/org/apache/camel/quarkus/component/jta/it/JtaIT.java b/integration-tests/jta/src/test/java/org/apache/camel/quarkus/component/jta/it/JtaIT.java new file mode 100644 index 0000000..8aacd7c --- /dev/null +++ b/integration-tests/jta/src/test/java/org/apache/camel/quarkus/component/jta/it/JtaIT.java @@ -0,0 +1,24 @@ +/* + * 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.it; + +import io.quarkus.test.junit.NativeImageTest; + +@NativeImageTest +class JtaIT extends JtaTest { + +} 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 new file mode 100644 index 0000000..bf7382c --- /dev/null +++ b/integration-tests/jta/src/test/java/org/apache/camel/quarkus/component/jta/it/JtaTest.java @@ -0,0 +1,134 @@ +/* + * 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.it; + +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; +import io.restassured.http.ContentType; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.Matchers.is; + +@QuarkusTest +class JtaTest { + + @Test + public void testNoTx() { + final String msg = java.util.UUID.randomUUID().toString().replace("-", ""); + + RestAssured.given() + .contentType(ContentType.TEXT) + .body(msg) + .post("/jta/required") + .then() + .statusCode(201) + .body(is("required")); + + RestAssured.given() + .contentType(ContentType.TEXT) + .body(msg) + .post("/jta/requires_new") + .then() + .statusCode(201) + .body(is("requires_new")); + + RestAssured.given() + .contentType(ContentType.TEXT) + .body(msg) + .post("/jta/mandatory") + .then() + .statusCode(201) + .body(is("Policy 'PROPAGATION_MANDATORY' is configured but no active transaction was found!")); + + RestAssured.given() + .contentType(ContentType.TEXT) + .body(msg) + .post("/jta/never") + .then() + .statusCode(201) + .body(is("never")); + + RestAssured.given() + .contentType(ContentType.TEXT) + .body(msg) + .post("/jta/supports") + .then() + .statusCode(201) + .body(is("supports")); + + RestAssured.given() + .contentType(ContentType.TEXT) + .body(msg) + .post("/jta/not_supported") + .then() + .statusCode(201) + .body(is("not_supported")); + } + + @Test + public void testInTx() { + final String msg = java.util.UUID.randomUUID().toString().replace("-", ""); + + RestAssured.given() + .contentType(ContentType.TEXT) + .body(msg) + .post("/jta/in_tx/required") + .then() + .statusCode(201) + .body(is("required")); + + RestAssured.given() + .contentType(ContentType.TEXT) + .body(msg) + .post("/jta/in_tx/requires_new") + .then() + .statusCode(201) + .body(is("requires_new")); + + RestAssured.given() + .contentType(ContentType.TEXT) + .body(msg) + .post("/jta/in_tx/mandatory") + .then() + .statusCode(201) + .body(is("mandatory")); + + RestAssured.given() + .contentType(ContentType.TEXT) + .body(msg) + .post("/jta/in_tx/never") + .then() + .statusCode(201) + .body(is("Policy 'PROPAGATION_NEVER' is configured but an active transaction was found!")); + + RestAssured.given() + .contentType(ContentType.TEXT) + .body(msg) + .post("/jta/in_tx/supports") + .then() + .statusCode(201) + .body(is("supports")); + + RestAssured.given() + .contentType(ContentType.TEXT) + .body(msg) + .post("/jta/in_tx/not_supported") + .then() + .statusCode(201) + .body(is("not_supported")); + } +} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 70b0f1c..ae6820f 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -101,6 +101,7 @@ <module>jira</module> <module>json-validator</module> <module>jsonpath</module> + <module>jta</module> <module>kafka</module> <module>kubernetes</module> <module>kudu</module> diff --git a/poms/bom/pom.xml b/poms/bom/pom.xml index a17970e..ab8b4d3 100644 --- a/poms/bom/pom.xml +++ b/poms/bom/pom.xml @@ -785,6 +785,11 @@ </dependency> <dependency> <groupId>org.apache.camel</groupId> + <artifactId>camel-jta</artifactId> + <version>${camel.version}</version> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> <artifactId>camel-kafka</artifactId> <version>${camel.version}</version> </dependency> @@ -2137,6 +2142,16 @@ </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-jta</artifactId> + <version>${camel-quarkus.version}</version> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-jta-deployment</artifactId> + <version>${camel-quarkus.version}</version> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-kafka</artifactId> <version>${camel-quarkus.version}</version> </dependency>