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 4a014cabfc Update jms doc to add some usages about IBM MQ Client 4a014cabfc is described below commit 4a014cabfc6be78c1b49be3e20202b400163c818 Author: Zheng Feng <zh.f...@gmail.com> AuthorDate: Fri Sep 22 14:38:02 2023 +0800 Update jms doc to add some usages about IBM MQ Client * Update jms doc to add some usages about IBM MQ Client * Update extensions/jms/runtime/src/main/doc/usage.adoc Co-authored-by: James Netherton <jamesnether...@users.noreply.github.com> * Replace to use Named * update docs --------- Co-authored-by: James Netherton <jamesnether...@users.noreply.github.com> --- .../ROOT/pages/reference/extensions/jms.adoc | 81 +++++++++++++++++++--- extensions/jms/runtime/src/main/doc/usage.adoc | 81 +++++++++++++++++++--- .../camel/quarkus/messaging/jms/JmsRoutes.java | 4 +- 3 files changed, 148 insertions(+), 18 deletions(-) diff --git a/docs/modules/ROOT/pages/reference/extensions/jms.adoc b/docs/modules/ROOT/pages/reference/extensions/jms.adoc index 678d7edfb2..07be4a5d4e 100644 --- a/docs/modules/ROOT/pages/reference/extensions/jms.adoc +++ b/docs/modules/ROOT/pages/reference/extensions/jms.adoc @@ -76,31 +76,96 @@ quarkus.pooled-jms.max-connections = 8 endif::[] You can use the `quarkus-pooled-jms` extension to get pooling and XA support for JMS connections. Refer to the https://quarkiverse.github.io/quarkiverse-docs/quarkus-pooled-jms/dev/index.html[quarkus-pooled-jms] extension documentation for more information. -Currently, it only works with `quarkus-artemis-jms` extension. Just add these two dependencies to your `pom.xml`: +Currently, it can work with `quarkus-artemis-jms`, `quarkus-qpid-jms` and `ibmmq-client`. Just add the dependency to your `pom.xml`: [source,xml] ---- <dependency> <groupId>io.quarkiverse.messaginghub</groupId> <artifactId>quarkus-pooled-jms</artifactId> </dependency> +---- + +Pooling is enabled by default. +[NOTE] +==== +`clientID` and `durableSubscriptionName` are not supported in pooling connections. If `setClientID` is called on a `reused` connection from the pool, an `IllegalStateException` will be thrown. You will get some error messages such like `Cause: setClientID can only be called directly after the connection is created` +==== + +To enable XA, you need to add `quarkus-narayana-jta` extension: +[source,xml] +---- <dependency> - <groupId>io.quarkiverse.artemis</groupId> - <artifactId>quarkus-artemis-jms</artifactId> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-narayana-jta</artifactId> </dependency> ---- +and add the following configuration to your `application.properties`: +[source,properties] +---- +quarkus.pooled-jms.transaction=xa +quarkus.transaction-manager.enable-recovery=true +---- -Note that pooling is enabled by default. +XA support is only available with `quarkus-artemis-jms` and `ibmmq-client`. Also We highly recommend to enable transaction recovery. -To enable XA, you need to add the following configuration to your `application.properties`: -[source,properties] +Since there is no quarkus extension for `ibmmq-client` currently, you need to create a custom `ConnectionFactory` and wrap it by yourself. Here is an example: +[source,java] ---- -quarkus.pooled-jms.xa.enabled=true +@Produces +public ConnectionFactory createXAConnectionFactory(PooledJmsWrapper wrapper) { + MQXAConnectionFactory mq = new MQXAConnectionFactory(); + try { + mq.setHostName(ConfigProvider.getConfig().getValue("ibm.mq.host", String.class)); + mq.setPort(ConfigProvider.getConfig().getValue("ibm.mq.port", Integer.class)); + mq.setChannel(ConfigProvider.getConfig().getValue("ibm.mq.channel", String.class)); + mq.setQueueManager(ConfigProvider.getConfig().getValue("ibm.mq.queueManagerName", String.class)); + mq.setTransportType(WMQConstants.WMQ_CM_CLIENT); + mq.setStringProperty(WMQConstants.USERID, + ConfigProvider.getConfig().getValue("ibm.mq.user", String.class)); + mq.setStringProperty(WMQConstants.PASSWORD, + ConfigProvider.getConfig().getValue("ibm.mq.password", String.class)); + } catch (Exception e) { + throw new RuntimeException("Unable to create new IBM MQ connection factory", e); + } + return wrapper.wrapConnectionFactory(mq); +} ---- [NOTE] ==== -`clientID` and `durableSubscriptionName` are not supported in pooling connections. If `setClientID` is called on a `reused` connection from the pool, an `IllegalStateException` will be thrown. You will get some error messages such like `Cause: setClientID can only be called directly after the connection is created` +If you use `ibmmq-client` to consume messages and enable XA, you need to configure `TransactionManager` in the camel route like this: +[source,java] +---- +@Inject +TransactionManager transactionManager; + +@Override +public void configure() throws Exception { + from("jms:queue:DEV.QUEUE.XA?transactionManager=#jtaTransactionManager"); +} + +@Named("jtaTransactionManager") +public PlatformTransactionManager getTransactionManager() { + return new JtaTransactionManager(transactionManager); +} +---- + +Otherwise, you will get an exception like `MQRC_SYNCPOINT_NOT_AVAILABLE`. +==== + +ifeval::[{doc-show-extra-content} == true] + +[NOTE] ==== +When you are using `ibmmq-client` and rollback a transaction, there will be a WARN message like: +[source] +---- +WARN [com.arj.ats.jta] (executor-thread-1) ARJUNA016045: attempted rollback of < formatId=131077, gtrid_length=35, bqual_length=36, tx_uid=0:ffffc0a86510:aed3:650915d7:16, node_name=quarkus, branch_uid=0:ffffc0a86510:aed3:650915d7:1f, subordinatenodename=null, eis_name=0 > (com.ibm.mq.jmqi.JmqiXAResource@79786dde) failed with exception code XAException.XAER_NOTA: javax.transaction.xa.XAException: The method 'xa_rollback' has failed with errorCode '-4'. +---- +==== + it may be ignored and can be assumed that MQ has discarded the transaction's work. Please refer to https://access.redhat.com/solutions/1250743[Red Hat Knowledgebase] for more information. + +endif::[] [id="extensions-jms-transferexception-option-in-native-mode"] diff --git a/extensions/jms/runtime/src/main/doc/usage.adoc b/extensions/jms/runtime/src/main/doc/usage.adoc index 582028bcc5..5e4592c15e 100644 --- a/extensions/jms/runtime/src/main/doc/usage.adoc +++ b/extensions/jms/runtime/src/main/doc/usage.adoc @@ -24,28 +24,93 @@ quarkus.pooled-jms.max-connections = 8 endif::[] You can use the `quarkus-pooled-jms` extension to get pooling and XA support for JMS connections. Refer to the https://quarkiverse.github.io/quarkiverse-docs/quarkus-pooled-jms/dev/index.html[quarkus-pooled-jms] extension documentation for more information. -Currently, it only works with `quarkus-artemis-jms` extension. Just add these two dependencies to your `pom.xml`: +Currently, it can work with `quarkus-artemis-jms`, `quarkus-qpid-jms` and `ibmmq-client`. Just add the dependency to your `pom.xml`: [source,xml] ---- <dependency> <groupId>io.quarkiverse.messaginghub</groupId> <artifactId>quarkus-pooled-jms</artifactId> </dependency> +---- + +Pooling is enabled by default. +[NOTE] +==== +`clientID` and `durableSubscriptionName` are not supported in pooling connections. If `setClientID` is called on a `reused` connection from the pool, an `IllegalStateException` will be thrown. You will get some error messages such like `Cause: setClientID can only be called directly after the connection is created` +==== + +To enable XA, you need to add `quarkus-narayana-jta` extension: +[source,xml] +---- <dependency> - <groupId>io.quarkiverse.artemis</groupId> - <artifactId>quarkus-artemis-jms</artifactId> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-narayana-jta</artifactId> </dependency> ---- +and add the following configuration to your `application.properties`: +[source,properties] +---- +quarkus.pooled-jms.transaction=xa +quarkus.transaction-manager.enable-recovery=true +---- -Note that pooling is enabled by default. +XA support is only available with `quarkus-artemis-jms` and `ibmmq-client`. Also We highly recommend to enable transaction recovery. -To enable XA, you need to add the following configuration to your `application.properties`: -[source,properties] +Since there is no quarkus extension for `ibmmq-client` currently, you need to create a custom `ConnectionFactory` and wrap it by yourself. Here is an example: +[source,java] ---- -quarkus.pooled-jms.xa.enabled=true +@Produces +public ConnectionFactory createXAConnectionFactory(PooledJmsWrapper wrapper) { + MQXAConnectionFactory mq = new MQXAConnectionFactory(); + try { + mq.setHostName(ConfigProvider.getConfig().getValue("ibm.mq.host", String.class)); + mq.setPort(ConfigProvider.getConfig().getValue("ibm.mq.port", Integer.class)); + mq.setChannel(ConfigProvider.getConfig().getValue("ibm.mq.channel", String.class)); + mq.setQueueManager(ConfigProvider.getConfig().getValue("ibm.mq.queueManagerName", String.class)); + mq.setTransportType(WMQConstants.WMQ_CM_CLIENT); + mq.setStringProperty(WMQConstants.USERID, + ConfigProvider.getConfig().getValue("ibm.mq.user", String.class)); + mq.setStringProperty(WMQConstants.PASSWORD, + ConfigProvider.getConfig().getValue("ibm.mq.password", String.class)); + } catch (Exception e) { + throw new RuntimeException("Unable to create new IBM MQ connection factory", e); + } + return wrapper.wrapConnectionFactory(mq); +} ---- [NOTE] ==== -`clientID` and `durableSubscriptionName` are not supported in pooling connections. If `setClientID` is called on a `reused` connection from the pool, an `IllegalStateException` will be thrown. You will get some error messages such like `Cause: setClientID can only be called directly after the connection is created` +If you use `ibmmq-client` to consume messages and enable XA, you need to configure `TransactionManager` in the camel route like this: +[source,java] +---- +@Inject +TransactionManager transactionManager; + +@Override +public void configure() throws Exception { + from("jms:queue:DEV.QUEUE.XA?transactionManager=#jtaTransactionManager"); +} + +@Named("jtaTransactionManager") +public PlatformTransactionManager getTransactionManager() { + return new JtaTransactionManager(transactionManager); +} +---- + +Otherwise, you will get an exception like `MQRC_SYNCPOINT_NOT_AVAILABLE`. +==== + +ifeval::[{doc-show-extra-content} == true] + +[NOTE] ==== +When you are using `ibmmq-client` and rollback a transaction, there will be a WARN message like: +[source] +---- +WARN [com.arj.ats.jta] (executor-thread-1) ARJUNA016045: attempted rollback of < formatId=131077, gtrid_length=35, bqual_length=36, tx_uid=0:ffffc0a86510:aed3:650915d7:16, node_name=quarkus, branch_uid=0:ffffc0a86510:aed3:650915d7:1f, subordinatenodename=null, eis_name=0 > (com.ibm.mq.jmqi.JmqiXAResource@79786dde) failed with exception code XAException.XAER_NOTA: javax.transaction.xa.XAException: The method 'xa_rollback' has failed with errorCode '-4'. +---- +==== + it may be ignored and can be assumed that MQ has discarded the transaction's work. Please refer to https://access.redhat.com/solutions/1250743[Red Hat Knowledgebase] for more information. + +endif::[] diff --git a/integration-tests/messaging/jms/src/main/java/org/apache/camel/quarkus/messaging/jms/JmsRoutes.java b/integration-tests/messaging/jms/src/main/java/org/apache/camel/quarkus/messaging/jms/JmsRoutes.java index 0a1647fe1c..221f664005 100644 --- a/integration-tests/messaging/jms/src/main/java/org/apache/camel/quarkus/messaging/jms/JmsRoutes.java +++ b/integration-tests/messaging/jms/src/main/java/org/apache/camel/quarkus/messaging/jms/JmsRoutes.java @@ -18,8 +18,8 @@ package org.apache.camel.quarkus.messaging.jms; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; +import jakarta.inject.Named; import jakarta.transaction.TransactionManager; -import org.apache.camel.BindToRegistry; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.quarkus.component.messaging.it.util.scheme.ComponentScheme; import org.springframework.transaction.PlatformTransactionManager; @@ -70,7 +70,7 @@ public class JmsRoutes extends RouteBuilder { .endChoice(); } - @BindToRegistry("jtaTransactionManager") + @Named("jtaTransactionManager") public PlatformTransactionManager getTransactionManager() { return new JtaTransactionManager(transactionManager); }