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
Related
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
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.
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.
Create connection factory where broker url to JVM
<!--tcp://localhost:61616-->
<bean id="connectionFactoryActiveMQ" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost"/>
<property name="useAsyncSend" value="true"/>
</bean>
Create single connection factory becose need one connection
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="connectionFactoryActiveMQ"/>
</bean>
create topic destination because need implemented some classes
<bean id="destination" class="org.apache.activemq.command.ActiveMQTopic">
<property name="physicalName" value="TEST"/>
</bean>
Generate jmsTemplate object
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestination" ref="destination"/>
<property name="pubSubDomain" value="true"/>
</bean>
My classes who receive messages
<bean id="messageListener1" class="com.aimrposoft.jms.server.Server"/>
<bean id="messageListener2" class="com.aimrposoft.jms.server.Server1"/>
<bean id="messageListener3" class="com.aimrposoft.jms.server.Server2"/>
Generate message class
<bean id="producer" class="com.aimrposoft.jms.client.Producer"/>
<!--<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">-->
<!--<property name="connectionFactory" ref="connectionFactory"/>-->
<!--<property name="destination" ref="destination"/>-->
<!--<property name="messageListener" ref="messageListener1"/>-->
<!--</bean>-->
<jms:listener-container
connection-factory="connectionFactory" destination-type="topic" acknowledge="transacted">
<jms:listener destination="TEST" ref="messageListener1" method="onMessage" subscription="subscription"/>
<jms:listener destination="TEST" ref="messageListener2" method="onMessage" subscription="subscription"/>
<jms:listener destination="TEST" ref="messageListener3" method="onMessage" subscription="subscription"/>
</jms:listener-container>
When I am using vm://localhost message listener don't working correctly, but if I run activeMQ and change broker URL to tcp://localhost:61616, all work is fine.
I think you are missing configuration to start up a embedded broker, can you try adding this to your configuration also:
<amq:broker id="activeMQBroker">
<amq:transportConnectors>
<amq:transportConnector uri="vm://localhost" />
</amq:transportConnectors>
</amq:broker>
amq namespace prefix can be defined this way:
xmlns:amq="http://activemq.apache.org/schema/core"
To further Biju's answer, I use queues not topics, here's my spring config that appears to work just fine (62999 is just a random available port number):
<amq:broker useJmx="false" persistent="false">
<amq:transportConnectors>
<amq:transportConnector uri="tcp://localhost:62999" />
</amq:transportConnectors>
</amq:broker>
<bean id="rawConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localEmbeddedBroker" />
</bean>
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="rawConnectionFactory" />
<property name="sessionCacheSize" value="30" />
<property name="cacheProducers" value="true" />
<property name="cacheConsumers" value="false" />
</bean>
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>