How to inject a message selector to message listener bean in jms-spring integration? - spring

I'm working with JMS API (with HornetQ) and i'm using spring beans for message listener container and message listener:
<bean id="messageListener" class="core.messaging.handler.MessageListener">
<property name="postCommandService" ref="postCommandService" />
</bean>
<bean id="messageSender"
class="lsn.messaging.sender.MessageSender">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="destination" />
</bean>
<bean id="msgListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer"
p:connectionFactory-ref="connectionFactory"
p:destination-ref="destination"
p:messageListener-ref="messageListener"
p:concurrentConsumers="10"
p:maxConcurrentConsumers="50"
p:receiveTimeout="5000"
p:idleTaskExecutionLimit="10"
p:idleConsumerLimit="5" />
If i want my message listener, only consume specific messages (that have same StringProperty) what should i do? Where should i define selector?
I have below solution, but i don't have MessageConsumer and so i can't add selector to it:
String redSelector = "color='red'";
MessageConsumer redConsumer = session.createConsumer(queue, redSelector);
redConsumer.setMessageListener(new SimpleMessageListener("red"));
TextMessage redMessage = session.createTextMessage("Red");
redMessage.setStringProperty("color", "red");
producer.send(redMessage);

You should be able to add it to the MessageListenerContainer this way:
p:messageSelector="color='red'"

Related

Not able to Stop MQueue listener

I have the following configuration for my MQueue:
<jms:listener-container container-type="default" connection-factory="cachedConnectionFactory" acknowledge="auto">
<jms:listener id="myListenerId" destination="myDestination" ref="myListener" method="onMessage" />
</jms:listener-container>
When I try to stop the reception of JMS messages, I write the following code
jmsManagement = myProject.instance.getContext().getBean('myListenerId',Lifecycle.class);
jmsManagement.stop();
PS :
When I stop() my listener, the isRunning() return False, but I still get messages through the MQueue... the onMessage gets triggered.
jmsManagement is an instance of the class Lifecycle. Even when I changed it to DefaultMessageListenerContainer, same thing.
I'm receiving messages before calling start(), even when autoStartup is set to false.
jmsManagement.shutdown(); didn't stop the listener from being triggered.
Does anyone have an idea about how to stop this MQ listener ?
Is there something I'm missing ?
I actually had to set autoStartup to true.
Since I can't do that using jms:listener-container, I instanciated a DefaultMessageListenerContainer bean and set the autoStartup property to false.
Here's the code that worked for me :
<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer" id="pitagorCPYListener">
<property name="autoStartup" value="false" />
<property name="connectionFactory" ref="cachedConnectionFactory" />
<property name="destination" ref="defaultDestination" />
<property name="messageListener" ref="listenerPitagorCPY" />
</bean>
<bean id="defaultDestination" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="#{mqConnectionFactory.destination}"/>
</bean>

Listener method not called when using Spring JMS

I have an application built on Spring 4.1. I am trying to create a JMS Listener using XML configuration and trying to convert the incoming XML message to Java Object. Below is my xml configuration:
<jms:listener-container concurrency="10"
connection-factory="connectionFactory"
message-converter="marshallingMessageConverter">
<jms:listener destination="destination.name" ref="messageListener" method="processMessage"/>
</jms:listener-container>
<bean id="messageListener" class="com.example.CustomMessageListener">
</bean>
<bean id="marshallingMessageConverter" class="org.springframework.jms.support.converter.MarshallingMessageConverter">
<property name="marshaller" ref="xmlMarshaller"/>
<property name="unmarshaller" ref="xmlMarshaller"/>
</bean>
<bean id="xmlMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound" value="com.example.CustomObject"/>
</bean>
The Class com.example.CustomMessageListener looks like below:
public class CustomMessageListener{
public void processMessage(Message message, CustomObject object){
//Do Something.
}
Now when I post a message into the destination queue, the method processMessage() on the Listener is not getting called and I am getting the below error in spring logs:
Failed to invoke target method 'processMessage' with arguments {com.example.CustomObject#52ee271d};
nested exception is java.lang.NoSuchMethodException:
com.example.CustomMessageListener.processMessage(com.example.CustomObject).
Now if I change the Listerner method's argument to just accept the CustomObject, it works and I get the CustomObject properly constructed from the XML:
public void processMessage(CustomObject, object)
But I also need the original javax.jms.Message instance and according to this documentation, it should be possible to receive that instance by specifying it in the parameter list.
Can somebody please help me out here?
try this it should work
<jms:listener-container concurrency="10" connection-factory="connectionFactory" >
<jms:listener destination="destination.name" ref="defaultMessageListener" />
</jms:listener-container>
<bean id="messageListener" class="com.example.CustomMessageListener">
</bean>
<bean id="marshallingMessageConverter" class="org.springframework.jms.support.converter.MarshallingMessageConverter">
<property name="marshaller" ref="xmlMarshaller"/>
<property name="unmarshaller" ref="xmlMarshaller"/>
</bean>
<bean id="xmlMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound" value="com.example.CustomObject"/>
</bean>
<bean id="payloadArgumentResolver" class="org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver">
<property name="converter" ref="marshallingMessageConverter"/>
</bean>
<bean id="handlerMethod" class="org.springframework.messaging.handler.invocation.InvocableHandlerMethod">
<constructor-arg
ref="messageListener" index="0"/>
<constructor-arg
value="processMessage" index="1"/>
<constructor-arg
value="javax.jms.Message" type="java.lang.Class" index="2"/>
<constructor-arg
value="com.example.CustomObject" type="java.lang.Class" index="3"/>
<property name="argumentResolvers" ref="payloadArgumentResolver" />
</bean>
<bean id="defaultMessageListener" class="org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter">
<property name="handlerMethod" ref="handlerMethod" />
</bean>

Spring Integration, jms Inbound gateway for WMQ; Unable to consume messages

I have recently started exploring Spring Integration as that is one of the option we want to evaluate for our project.
The issue i am facing is below.
I have created a JMS inbound gateway to listen to WMQ queue and i am expecting the inboudnd gateway (using DML) should pick up the messages as and when they are available on queue(event - driven).
But some how the example isn't working. It fails to pick messages from the queue. However i can see (using a tool) that there are consumers created on the queue.
Help here is really appreaciated.
Code snippet below.
<bean id="mqFactory" class="com.ibm.mq.jms.MQConnectionFactory">
<property name="hostName" value="${mq.hostName}"/>
<property name="port" value="${mq.port}"/>
<property name="queueManager" value="${mq.queueManager}"/>
<property name="channel" value="${mq.channel}"/>
<property name="transportType" value="${mq.transportType}"/>
<property name="SSLCipherSuite" value="${mq.SSLCipherSuite}"/>
</bean>
<bean id="inCachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="mqFactory" />
<property name="sessionCacheSize" value="5" />
</bean>
<bean id="requestQueue-mq" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="${mq.example.queue}"/>
</bean>
<bean id="demoBean" class="com.jpmchase.example.spring.DemoBean">
</bean>
<jms:inbound-gateway id="wMQ_in_gateway" concurrent-consumers="2" max-concurrent-consumers="5" connection-factory="inCachingConnectionFactory" request-destination="requestQueue-mq"
request-channel="demoChannel" />
<integration:channel id="demoChannel">
</integration:channel>
<integration:service-activator input-channel="demoChannel" ref="demoBean"/>
Below is the service-activator java code.
enter #MessageEndpoint
public class DemoBean {
#ServiceActivator
public String upperCase(String input) {
System.out.println("inside the service activator " + input);
return "JMS response: " + input.toUpperCase();
}
here

MessageListenerContainer with MessageHandler?

If I use Spring Integration with XML-Configuration, a Message Listener can be done like the following:
<int:channel id="handlerChannel"/>
<bean class="org.springframework.integration.endpoint.EventDrivenConsumer">
<constructor-arg name="inputChannel" ref="handlerChannel"/>
<constructor-arg name="handler" ref="alertHandler" />
</bean>
<int-jms:message-driven-channel-adapter channel="handlerChannel" container="listenerContainer" />
<bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer" scope="prototype">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="defaultDestination"/>
</bean>
The problem is: I want to create own ListenerContainers at the runtime... how I can get the same result or rather how can I combine a MessageHandler with a MessageListenerContainer?
thx and greeting
MessageChannel channel = new DirectChannel();
DefaultMessageListenerContainer container = ...
JmsMessageDrivenEndpoint inbound = new JmsMessageDrivenEndpoint(container);
inbound.setOutputChannel(channel);
handler.subscribe(channel);
inbound.afterPropertiesSet();
inbound.start();
However, why use Spring Integration at all here; you can wire a MessageListener into the message listener container directly.

Spring-JMS(Websphere MQ)

I have the below configurations in Spring , it is working fine but performance is too low (it takes 1 min for 20 messages). Can you please suggest me changes to increase the performance.
<bean id="jmsConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="transportType"><value>1</value></property>
<property name="queueManager"><value></value></property>
<property name="hostName"><value></value></property>
<property name="port"><value></value></property>
<property name="channel"><value></value></property>
<property name="clientId"><value></value></property>
</bean>
<bean id="SenderJMSTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory"><ref bean="jmsConnectionFactory" /> </property>
<property name="pubSubDomain"><value>false</value></property>
<property name="defaultDestination"><ref bean="senderQueue" /></property>
</bean>
<bean id="senderQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="TEST" />
<property name="baseQueueManagerName"><value>tree.queue.manager</value></property>
<property name="baseQueueName"><value>ORANGE.QUEUE</value></property>
</bean>
<bean id="jmsSender" class="org.tree.jms.spring.JMSSender">
<property name="jmsTemplate"><ref bean="SenderJMSTemplate"/></property>
</bean>
I am calling from spring as
JMSSender obj = (JMSSender) context.getBean("jmsSender");
And My Sender program is :
#Cacheable("message")
public void sendMesage() {
jmsTemplate.send(new MessageCreator() {
public Message createMessage(Session session)throws JMSException {
message = (Message) session.createTextMessage(stringBuffer.toString());
return message;
}
});
}
}
A common problem when using JMSTemplate to send messages out of JavaEE containers is the it's extremly slow since it acquires a new connection for each message (and then closes it). You would probably need a pooled/cached connection to gain speed here.
Read this article, it's written for ActiveMQ, but applies in a similar way to WebSphere MQ: http://activemq.apache.org/jmstemplate-gotchas.html
You can setup a cached connection factory in spring using something like this:
<bean id="cachedConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory"
p:targetConnectionFactory-ref="jmsConnectionFactory"
p:sessionCacheSize="10" />
Then use it instead of the original one for JMS connections.

Resources