how to enforce the redelivery for un acknowledge jms message - java

I read on : http://www.javaworld.com/article/2074123/java-web-development/transaction-and-redelivery-in-jms.html?page=2
"Generally, acknowledging a particular message acknowledges all prior messages the session receives" ( in Client acknowledgement mode )
"Message redelivery is not automatic, but messages are redelivered under certain circumstances"
My questions :
how can I ensure there is a new session every time I recive a message (but reuse the connection)?
how to enforce the redelivery for un acknowledge message ?
Im using this configration :
<bean id="jmsConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory"
lazy-init="true">
<property name="queueManager" value="${queueManager}" />
<property name="hostName" value="${hostName}" />
<property name="transportType" value="${transportType}" />
<property name="port" value="${port}" />
<property name="channel" value="${channel}" />
<property name="SSLCipherSuite" value="${SSLCipherSuite}" />
</bean>
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="maxConnections" value="10"/>
<property name="maximumActive" value="100"/>
<property name="connectionFactory" ref="jmsConnectionFactory"/>
</bean>
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
<property name="transacted" value="false"/>
</bean>
<bean id="mqNonJmsDestRes" class="calypsox.tk.util.NonJmsMQQueueDestinationResolver" />
<bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
<property name="configuration" ref="jmsConfig" />
<property name="acknowledgementModeName" value="CLIENT_ACKNOWLEDGE" />
<property name="destinationResolver" ref="mqNonJmsDestRes" />
</bean>
and I use camel processor as endpoint bean as singleton

That article you referenced is from 2002. All of the MQ based systems have received a lot of work since then. On your AMQ PooledConnectionFactory there are settings to control how long your connections last before they are destroyed and what you should do if you encounter an error. I recommend reading into some of the newer documentation since there has been a lot of changes in the last 14 years. So some things have become much easier.
You can also check into the exceptionListener on "org.apache.camel.component.jms.JmsComponent" to configure how to manage exceptions and even write your own if the current options don't suit your needs.

Related

Spring Integration JMS/IBM MQ: how can I business logic it if not receiving a response

My project is using jms+ibmmq to send a message out. it's working properly, and I'm able to push a message to the outbound queue, and then receive a response from the inbound queue. Recently, a client asks if we can send out an alert email if unable to get a response within like 2 min. I checked the spring integration messaging related document, seems gatway can implement it? but still can't get an idea how to use it. can someone help me out?
my current xml configuration
<integration:service-activator id="serviceActivator1" input-channel="inputChannel"
ref="messageProcessService" method="callMsgProcessor" output-channel="requestChannel" />
<bean id="ibmConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory">
<bean class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="transportType">
<util:constant static-field="com.ibm.msg.client.wmq.WMQConstants.WMQ_CM_CLIENT"/>
</property>
<property name="hostName" value="${hostName}"/>
<property name="queueManager" value="${queue-manager}"/>
<property name="channel" value="${channel}"/>
<property name="port" value="${port}"/>
</bean>
</property>
<property name="sessionCacheSize" value="5"/>
</bean>
<bean id="requestQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="${request-queue}"/>
<property name="targetClient">
<util:constant static-field="com.ibm.msg.client.wmq.WMQConstants.WMQ_CLIENT_NONJMS_MQ"/>
</property>
</bean>
<jms:outbound-channel-adapter id="request.queue.adapter" connection-factory="ibmConnectionFactory"
destination="requestQueue" channel="requestChannel"/>
<integration:channel id="requestChannel"/>
<bean id="responseQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="${response-queue}"/>
</bean>
<jms:message-driven-channel-adapter id="responseJMSAdapater"
destination="responseQueue"
channel="responseChannel"
connection-factory="ibmConnectionFactory"
error-channel="errorChannel"
acknowledge="transacted"
/>
<integration:channel id="responseChannel">
<integration:queue capacity="500"/>
<integration:interceptors>
<integration:wire-tap channel="logger"/>
</integration:interceptors>
</integration:channel>
if add a gateway, it looks like
<integration:gateway id="serviceAdaptedGateway" service-interface="com.mycompany.service.gatewayServiceInterface"
default-request-channel="requestChannel"
default-reply-channel="responseChannel"
default-reply-timeout="120000"/>
my question is
seems timeout not working, nothing happen even the waiting time exceed the timeout
although the gateway provide timeout property, where I can add my business logic like send email alert?

Client Acknowledge in camel-kafka

I'm using camel-kafka version 2.14.3 . I used client acknowledge while reading from ibm MQ by creating the bean as follows
<bean id="ibmMQwithClientAck" class="org.apache.camel.component.jms.JmsComponent">
<property name="configuration">
<bean class="org.apache.camel.component.jms.JmsConfiguration">
<property name="acknowledgementModeName"
value="CLIENT_ACKNOWLEDGE" />
<property name="connectionFactory">
<bean class="com.ibm.mq.jms.MQConnectionFactory">
<property name="transportType" value="<transportType>" />
<property name="hostName" value="<hostName>" />
<property name="port" value="<port>" />
<property name="channel" value="<channel>" />
<property name="queueManager" value="<queueManager>" />
</bean>
</property>
</bean>
</property>
</bean>
I'm looking for client commit in camel-kafka. Can this be accomplished from consumer itself, or something needs to configured at the kafka cluster end?
I'm using camel-kafka version 2.14.3 .
Below is the kafka URI :
<from uri="kafka:{brokerlist}?topic={topic-name}&zookeeperHost={zookeeperHost}&zookeeperPort={zookeeperPort}&groupId={groupId-name}&consumerStreams=2" />
You can use manual commit via allowManualCommit=true, see the docs at: https://camel.apache.org/components/2.x/kafka-component.html
At the section: https://camel.apache.org/components/2.x/kafka-component.html#_using_manual_commit_with_kafka_consumer

Spring JMS Template

I'm really struggling to get my Spring JMS template to work and send messages to a queue. Here's what I've got attempted:
In my XML:
<bean name="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<constructor-arg ref="mqQueueConnectionFactory" />
<property name="defaultDestination" ref="mqQueue" />
</bean>
<bean name="mqQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="${MQ_QUEUE_MANAGER_NAME}" />
<constructor-arg value="${MQ_QUEUE_NAME}" />
</bean>
<bean name="mqQueueConnectionFactory" class="com.ibm.mq.jms.MQXAQueueConnectionFactory">
<property name="hostName" value="${MQ_HOST_NAME}" />
<property name="channel" value="${MQ_CHANNEL}" />
<property name="port" value="${MQ_PORT}" />
<property name="queueManager" value="${MQ_QUEUE_MANAGER_NAME}" />
<property name="transportType" ref="wmq_cl_binding" />
</bean>
So those are my beans for setting up the template/queue.
Now I setup a listener and jmsContainer:
<bean id="messageListener" class="CloseoutListener" />
<bean id="jmsContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="mqQueueConnectionFactory" />
<property name="destination" ref="mqQueue" />
<property name="messageListener" ref="messageListener" />
</bean>
and my implementation of CloseoutListener is the same that is on the Spring JMS docs: Listener
In addition to this, I am trying to send a message in the same way that Spring sends a message in the docs: Sender
Full disclosure: First time using queues and any sort of JMS, as well as my second time using Spring so I'm aware if this is sloppy or just plain wrong. That's why I'm asking for assistance.
No message is appearing in the queue and in addition I'm getting this message in my logs:
INFO DefaultMessageListenerContainer.handleListenerSetupFailure :825 - JMS message listener invoker needs to establish shared Connection

Spring : JMS Consumer Sessions/Connections not removed on Message Broker post Batch Job Completion

I have a Batch Job Configured to read messages from JMS Destination and write to a XML file using Chuck Tasklet. The JMS reader is custom implemented which inturn invokes JMSTemplate's receive method. I am using webMethods Broker as JMS Broker. During Batch run, we observed that the Consumer session created while reading the messages from Broker Destination are not being destroyed up on completion of the batch. They are only destroyed after I shutdown the JVM. I have provided more details below,
JMS Spring XML Configuration :
<bean id="JMS.SourceQueue.JndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<map>
<entry key="java.naming.provider.url" value="wmjmsnaming://Broker #1#X.X.X.X:6849" />
<entry key="java.naming.factory.initial" value="com.webmethods.jms.naming.WmJmsNamingCtxFactory" />
<entry key="com.webmethods.jms.naming.clientgroup" value="IS-JMS" />
</map>
</property>
</bean>
<bean id="JMS.SourceQueue.JmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="JMS.SourceQueue.JndiTemplate" />
<property name="jndiName" value="SmartBatchConnectionFactory" />
<property name="lookupOnStartup" value="true" />
<property name="cache" value="false" />
<property name="proxyInterface" value="javax.jms.ConnectionFactory" />
</bean>
<bean id="JMS.SourceQueue.ConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<constructor-arg ref="JMS.SourceQueue.JmsConnectionFactory" />
</bean>
<bean id="JMS.SourceQueue.DefaultDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="JMS.SourceQueue.JndiTemplate" />
<property name="jndiName" value="SourceQueue" />
</bean>
<bean id="JMS.SourceQueue.MessageTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="JMS.SourceQueue.ConnectionFactory" />
<property name="receiveTimeout" value="10000" />
<property name="sessionTransacted" value="true" />
<property name="defaultDestination" ref="JMS.SourceQueue.DefaultDestination" />
</bean>
Any help on pointing out the actual issue would be great.
Call destroy() on the JMS.SourceQueue.ConnectionFactory at the end of the last step (or otherwise when the job is completed).
Using the caching connection factory is recommended to avoid creating connections/consumers for each message, but it needs to be told when to physically release the resources.

ActiveMQ: Correct config with both Queues (with concurrent consumers) and Topics

We have an ActiveMQ / Camel configuration that has previously been using exclusively message queues, with concurrent consumers.
However, we're now introducing message topics, and finding that - because of the concurrent consumers - messages received in the topic are consumed mulltiple times.
What's the correct configuration for this scenario?
ie., we want multiple concurrent consumers for messages received on a queue, but only a single consumer defined for messages received on a topic.
Here's the current configuration:
<amq:connectionFactory id="amqConnectionFactory"
useAsyncSend="true" brokerURL="${${ptl.Servername}.jms.cluster.uri}"
userName="${jms.username}" password="${jms.password}" sendTimeout="1000"
optimizeAcknowledge="true" disableTimeStampsByDefault="true">
</amq:connectionFactory>
<bean id="cachingConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="amqConnectionFactory"></property>
<property name="cacheConsumers" value="true"></property>
<property name="cacheProducers" value="true"></property>
<property name="reconnectOnException" value="true"></property>
<property name="sessionCacheSize" value="${jms.sessioncachesize}"></property>
</bean>
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="cachingConnectionFactory" />
<property name="transacted" value="false" />
<property name="concurrentConsumers" value="${jms.concurrentConsumer}" />
<property name="maxConcurrentConsumers" value="${jms.max.concurrentConsumer}" />
<property name="preserveMessageQos" value="true" />
<property name="timeToLive" value="${jms.timeToLive}" />
</bean>
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig" />
</bean>
you can explicitly set concurrentConsumers/maxConcurrentConsumers to "1" for any topic consumers.
from("activemq:topic:myTopic?concurrentConsumers=1&maxConcurrentConsumers=1")...
alternatively, set the JmsConfiguration concurrent/maxConcurrentConsumers properties to "1" and then explicitly enable concurrent consumption for queues as needed.
from("activemq:queue:myQueue?maxConcurrentConsumers=5")...
also, you can use Virtual Topics to perform concurrent consumption of Topic messages without getting duplicates (highly recommended over traditional Topics)
The solution I ended up using was to create a separate jmsConfig/activeMQ config block.
The total configration looks as follows:
<!-- This is appropriate for consuming Queues, but not topics. For topics, use
jmsTopicConfig / activemqTopics -->
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="cachingConnectionFactory" />
<property name="transacted" value="false" />
<property name="concurrentConsumers" value="${jms.concurrentConsumer}" />
<property name="maxConcurrentConsumers" value="${jms.max.concurrentConsumer}" />
<property name="preserveMessageQos" value="true" />
<property name="timeToLive" value="${jms.timeToLive}" />
</bean>
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig" />
</bean>
<!-- This config limits to a single concurrent consumer. This config is appropriate for
consuming Topics, not Queues. -->
<bean id="jmsTopicConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="cachingConnectionFactory" />
<property name="transacted" value="false" />
<property name="concurrentConsumers" value="1" />
<property name="maxConcurrentConsumers" value="1" />
<property name="preserveMessageQos" value="true" />
<property name="timeToLive" value="${jms.timeToLive}" />
</bean>
<bean id="activemqTopics" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsTopicConfig" />
</bean>
Then, in the camel pipeline, consuming the topic off the activemqTopics bean, as follows:
<camel:route id="myTopicResponder">
<camel:from uri="activemqTopics:topic:stockQuotes?concurrentConsumers=1" />
<camel:to uri="bean:stockQuoteResponder?method=saveStockQuote"/>
</camel:route>

Categories