How to alter MQ headers using Spring JmsTemplate - java

I'm using simple Spring JmsTemplate to send messages onto a MQ.
<beans:bean id="myJMSTemplate" class="org.springframework.jms.core.JmsTemplate">
<beans:property name="connectionFactory">
<beans:ref bean="cachedConnectionFactory" />
</beans:property>
<beans:property name="pubSubDomain">
<beans:value>false</beans:value>
</beans:property>
<beans:property name="receiveTimeout">
<beans:value>1000</beans:value>
</beans:property>
</beans:bean>
<int-jms:outbound-channel-adapter id="sendMessageToAvengers" channel="antEventChannel" jms-template="myJMSTemplate" destination-name='com.marvel.avengers.antMan'/>
This works fine, however, My client application isn't able to process the message as the message format is in 'MQHRF2' by default.
How can I alter my MQ headers so as to send explicitly MQSTR format.
Thanks in advance.

You must set the property targetcllient=1 to send the msg as MQSTR.
To do this in sending part of java code, change the queue name as below
String senderQ = "queue:///MYQUEUENAME?targetClient=1";
jmsTemplate.send(senderQ, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
TextMessage message = session.createTextMessage(text);
message.setJMSReplyTo(replyToQ);
return message;
}
});
Alternatively you can try setting this in jmstemplate bean
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<!-- set format to MQSTR with "targetClient=1" parameter -->
<property name="defaultDestinationName" value="queue:///default?targetClient=1" />
<property name="connectionFactory" ref="mqConnectionFactory" />
</bean>

The IBM MQ JMS interface has a property called TARGCLIENT which when set to the value MQ will not add the MQRFH2 header. I don't know whether the Spring interface allows it to be used.
Alternatively, the queue definition on the queue manager can be configured to remove the header for those applications that can't process it. This is a better way to remove the MQRFH2 header as it removes it at get time instead of at put time, thus meaning that if an application is able to process the MQRFH2 header, it is still there, but for those applications that cannot process it, it is removed for them.
To make the queue operate in this way, issue the following MQSC command on your queue manager:
ALTER QLOCAL(q-name) PROPCTL(NONE)
Additional Reading
Properties of IBM MQ classes for JMS objects > TARGCLIENT
PROPCTL queue options
DEFINE queues - see PROPCTL attribute

Related

How to set timestamp manually on spring-ws security

Client and server do not have sync time so that the soap server's security return not authorized responses.
I will get the server's current time and I will use that time while sending the soap request(On security header, username token created vs).
How to set timestamp manually on spring-ws.
I am using spring ws.client.core, ws.soap.security.wss4j2 (Wss4jSecurityInterceptor and WebServiceTemplate).
WS-Usernametoken is sent for security(nonce, username, password, created (I guess that created is the problem. I should set that.)
The server is onvif device.
You could do the following( source here here)
<bean class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="validationActions" value="Timestamp"/>
<property name="timestampStrict" value="true"/>
<property name="timeToLive" value="10"/>
In Short, you can do the following
Call the Create() class method of %SOAP.Security.Timestamp
set ts=##class(%SOAP.Security.Timestamp).Create()
Call the AddSecurityElement() method of the SecurityOut property of your web client or web service
do client.SecurityOut.AddSecurityElement(ts)e
Send the SOAP message

How to use #JmsListener for topic in Spring 4

I am using Spring 4.3.3 and I am trying to listen to a message where the destination type is topic.
I can achieve it in xml:
<jms:listener-container connection-factory="connectionFactory"
destination-type="topic"
message-converter="jackson2MessageConverter">
<jms:listener destination="test.topic" ref="jmsTopicMessageListener1" method="receiveMessage"/>
<jms:listener destination="test.topic" ref="jmsTopicMessageListener2" method="receiveMessage"/>
</jms:listener-container>
But I want to use #JmsListener. at the moment it is only working for queue destination like this:
#JmsListener(destination = "mailbox", containerFactory = "jmsListenerContainerFactory")
public void receiveMessage(DataObject dataObject) {
System.out.println("Received <" + dataObject.getName() + ">");
}
How do I listen to a topic with this annotation #JmsListener?
Thanks in advance.
UPDATE:
I have tried this in the config:
<bean id="topicJmsListenerContainerFactory"
class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
<property name="connectionFactory" ref="cachingConnectionFactory"/>
<property name="destinationResolver" ref="jmsDestResolver"/>
<property name="concurrency" value="3-10"/>
<property name="messageConverter" ref="jackson2MessageConverter"/>
<property name="pubSubDomain" value="true"/>
</bean>
then this:
#JmsListener(destination = "test.topic", containerFactory = "topicJmsListenerContainerFactory")
public void receiveMessage(DataObject dataObject) {
System.out.println("Received <" + dataObject.getName() + ">" + 1);
}
I can get the values now but i get duplicates.
Since you have fixed your config (you are receiving messages that is) the only problem to solve is the fact that you are receiving duplicate messages. This is due to this piece of your config:
<property name="concurrency" value="3-10"/>
If you check the javadoc of DefaultMessageListenerContainer (which JmsListenerContainerFactory extends), you will find that:
...for a topic, you will typically stick with the default number of 1
consumer, otherwise you'd receive the same message multiple times on
the same node.
This is due to the architecture of the topic itself, multiple consumers will be treated as multiple subscribers who need to receive each message that was sent.
On the solution side:
You might need to reachitecture your code a bit. But most cases changing from Topic to VirtualTopic does the job. With VirtualTopics you can get "Queue-like" behaviour on the consumer side, meaning that messages will get consumed by a consumer, so multiple consumers cannot see the same message twice.
The other option of course is shifting the parallel processing workload to some other place and use a single consumer at the JMS entrypoint. Depending on the task at hand it might be a sufficient solution too.

Synchronous & Asynchronous Message Receiver in 1 queue (Spring w/ ActiveMQ) JMS API

I am using Spring JMS with ActiveMQ as the broker and running the application on Tomcat.
I have one queue, let's say queue.a. In my web app, I already have a MessageListener running whenever I start my web app. The only thing is, I want to add some kind of queue consumer but synchronously. I already try using JmsTemplate etc. But when both of my consumer (listener async & consumer synchronous) is up and I trigger the .receive() method, the message sent to the queue always sucked up to the message listener that have been always online since the web app started. After the end of the timeout,the synchronous receiver did not consume any message at all.
But,when I comment out the messageListener, the synchronous customer run well.
I'm still a newbie,do any of you have any way to make what I want possible? Thanks! Sorry for my bad english :(
<bean id="someQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0" value="TEST.QUEUE?consumer.priority=10" />
</bean>
and then, set it to your listener/receiver bean:
<bean id="someReceiver" class="blah.blah.SomeReceiver">
<property name="destination" ref="someQueue" />
<property name="jmsTemplate" ref="jmsTemplate" />
</bean>
Does this solve your problem?

http request - camel's concurrency

Does any method of camel's consumer exist which is able to process >20 http requests per second? I try to work with restlet and jetty components, but failed with both.
For example, I set this config for a jetty component:
<bean id="jetty" class="org.apache.camel.component.jetty.JettyHttpComponent">
<property name="httpClientMinThreads" value="10"/>
<property name="httpClientMaxThreads" value="254" />
<property name="minThreads" value="10"/>
<property name="maxThreads" value="254" />
</bean>
and hoped that everything will be OK, but nothing.
My route config:
from("jetty:http://0.0.0.0:8888" + linkRequest+"?matchOnUriPrefix=true")
.onException(Exception.class)
.log(LoggingLevel.ERROR, "${exception.stacktrace}")
.useOriginalMessage()
.handled(true)
.setBody(simple("Something went wrong"))
.end()
.process(new MyFirstProcessor())//here I get httpHeaders,create entity A
.to("jpa:RequestEntity")
.process(new MySecondProcessor())//set some filed in entity A and send it
.to("bean:service?method=process")//here I recieve entity A and create entity B
.to("jpa:ResponseEntity")
.process(new MyThirdProcessor())//here response is created;
Please explain to me how I can configurate parameters of camel (I glance at the threading model configuration), jetty-component or restlet component - so that my router can handle all incoming requests.
UPDATE
These problems were caused by the settings of the connection pool to the database.

jms error handler: receive a callback only when jms gives up

I am using spring-jms with active mq.
I have a ErrorHandler listener set up, that receives a callback each time a jms message delivery fails - i.e. the method that processes the message throws an exception instead of returning gracefully.
However my jms is configured to retry several times until the jms delivery finally succeeds. And my callback is notified of all of the failures.
What I want is a listener that receives a notification only when all the retries finally fail. The motivation is to bring the issue up for the admin's attention. But I don't want spurious notifications in the admin's console.
<bean abstract="true" id="abstractDestinationListener"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="jmsFactory" />
<property name="errorHandler" ref="destinationErrorHandler"/>
<property name="sessionTransacted" value="true"/>
</bean>
What you might consider is using a per-destination dead-letter queue (individualDeadLetterStrategy - https://activemq.apache.org/message-redelivery-and-dlq-handling.html) for the destinations in question. When the maximum redelivery count has been hit, the message is moved out to the DLQ. You can then set up a consumer on that queue with a listener that emails the administrator.
Another way to do it might be to wrap your listener with a try-catch, and rethrow any exceptions only if message.getIntProperty("JMSXDeliveryCount") < MAX_REDELIVERY_COUNT, and email the admin otherwise. However, that option means placing your redelivery limit in two places - the broker config and the code.
if you need more fine-grained control/flexibility/routing with JMS messaging/handling, then you should just use Apache Camel's error handling...

Categories

Resources