Camel ProducerTemplate versus Spring JMSTemplate - apache-camel

I am using camel to send message to an IBM MQQueue.
The MDB listening to this queue expects messages of the type com.ibm.jms.JMSMapMessage.
When I use camel producerTemplate, an exception is thrown.
I am doing this
producerTemplate.sendBody("wmq:queue",hashMap);
Exception data: java.lang.ClassCastException: com.ibm.jms.JMSMapMessage incompatible with javax.jms.ObjectMessage
So I tried Spring jmsTemplate, and it worked.
jmsTemplate.send(new MessageCreator() {
#Override
public Message createMessage(Session session)
throws JMSException {
return session.createObjectMessage((Serializable) sctHmap);
}
});
Question:
The jms component documentation says
It uses Spring's JMS support for declarative transactions, including
Spring's JmsTemplate for sending and a MessageListenerContainer for
consuming.
I tried with disabling camels auto conversion using mapJmsMessage=false.
I realised it would not help as it would have sent a hash map, I still got the same exception. Is there any way I can get the producerTemplate to work in the same way as JMSTemplate? ProducerTemplate seems to be more elegant, atleast in terms of my unit tests

It seems I misinterpreted the classcast exception message. Camel was correctly sending, com.ibm.jms.JMSMapMessage, the MDB at the consumer application was expecting javax.jms.ObjectMessage.
I resolved it by setting jmsMessageType=object in the endpoint URI. :)

Related

Stop camel route if MQ becomes unavailable

I have one of the camel route as follows, there are many routes.
from("jms:queue:TEST.LQ?transacted=true&connectionFactory=jmsConnectionFactory&cacheLevelName=CACHE_NONE")
.routeId("routeid")
.autoStartup("true")
.transacted("requried")
....
....
I getting below error if TEST.LQ MQ or Queue manager is unavailable.
ERROR [JmsConsumer[TEST.LQ]] [] [o.a.c.c.j.DefaultJmsMessageListenerContainer ] Could not refresh JMS Connection for destination
I tried to handle exception by catching below code, but JmsMessageListenerContainer only throws the message not an exceptiom
onException(MQException.class, JMSException.class)
How stop route if IF MQ is not available?
The camel jms component has the option for this -
Add the testConnectionOnStartup=true option in your from(uri) :
from("jms:queue:TEST.LQ?transacted=true&connectionFactory=jmsConnectionFactory&cacheLevelName=CACHE_NONE&testConnectionOnStartup=true")
This will throw an exception if a connection is not available during startup which can then be handled.
More details are available in the jms-component page
#sree1611,
You can add exceptionListener or errorHandler query parameter in camel jms uri.
To create your own exception listener, implement org.apache.camel.spi.ExceptionHandler
To create your own error handler, implement org.springframework.util.ErrorHandler
I hope errors while consuming from MQ can't be bridged with camel error handlers, so you can't catch JMS exceptions (occurred during message consumption from MQ) in onException().

Difference between #JMSListener and #Consume annotations?

I am trying to consume JMS messages sent via spring JmsTemplate using #Consume annotated bean. The consumer is not receiving messages when sent using JmsTemplate.
Whereas, when sent using ProducerTemplate of Camel the messages are received.
What is the difference between #org.springframework.jms.annotation.JmsListener and #org.apache.camel.Consume?
Producer Logic
jmsTemplate.convertAndSend("jms:mailbox", message);
Consumer Logic
#Consume(uri="jms:mailbox")
public void onRequest(String name) {
System.out.println("Received message > "+name);
}
Apache Camel #Consume annotation can consume from any endpoint, which supports consuming. This annotation takes uri as parameter. URI consists of scheme, path and optional params. In case of JMS component the scheme is jms, path is Destination (in your case mailbox) and params are additional options customizing behavior of Consumer.
Spring #JmsListener can consume from JMS and takes Destination as parameter.
Your code does not work because the Destination is mailbox, not jms:mailbox. Spring JmsTemplate does not know about jms scheme, it is Camel specific. So use jmsTemplate.convertAndSend("mailbox", message) on Spring side and #Consume(uri="jms:mailbox") on Camel side.

Apache CXF - How to know while sending which response "Broken pipe" is occuring

I see lots of exceptions[ClientAbortException: java.net.SocketException: Broken pipe] in
my catalina log while trying to send the response back but i am not able to tie this exception
to a particular request with a particular Inbound Message ID, Is there any way by which i can know, while sending
which response this exception is occuring in cxf ?
Try enabling SOAP logging. If you enable SOAP logging as follows, you will see SOAP requests and/or responses including HTTP headers. CXF also assigns a message ID for each request/response.
#WebService
#org.apache.cxf.annotations.Logging
public interface AssetServices {
....
}

How to connect an Apache Camel synchronous request/reply endpoint with asynchronous sub-routes

I'd like to route a webservice request to an InOnly endpoint of a jms queue. Then route a response jms message received from a separate InOnly endpoint back to the webservice client as the response. The webservice request/response is a synchronous InOut pattern, and the sub-routes are asynchronous. What options do I have to achieve this with Camel?
The Camel route here is used to explain my question:
String uri={webserice uri}
from(uri)
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
ServcieRequest req =
exchange.getIn().getBody(ServcieRequest.class);
// One option to me is to spawn another route here to route to jms queue...
ProducerTemplate template = exchange.getContext().createProducerTemplate();
template.sendBodyAndHeaders("jms:queue:INQueue", req.getPayload(), headers);
// then need to wait ...until received jms response from the route below
}});
from("jms:queue:OUTQueue")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
// received jms response message
// need to update the exchange data in the above route based on jms message
// so the final response to the webservice cilent can receive the data ...
}});
I think you should rely on the request reply mechanism in Camel for this task.
Camel Doc, Exclusive Fixed Reply Queue
So I guess the following DSL route does pretty much what you want (if there is no other reason why you should use a InOnly pattern for the JMS part?). Make sure you tune the requestTimeout if you need (as it defaults to 20Sec timeout).
from(webserviceURI)
.inOut().to("jms:queue:INQueue?replyTo=OUTQueue?replyToType=Exclusive");
Yes, one other thing. If you run this on several nodes, then you need one exclusive queue per node.

Camel CXF consumer, webservice method has no response

I'm trying to consume a webservice from camel using the cxf component, like this:
<cxf:cxfEndpoint id="webservice"
address="http://webservice.url.com/webservice"
serviceClass="com.url.webservice.MyWebService"/>
<camel:camelContext>
<camel:route>
<camel:from uri="direct:a"/>
<camel:inOnly uri="cxf:bean:webservice?defaultOperationName=sendMessage"/>
</camel:route>
</camel:camelContext>
The sendMessage method has no response, hence the inOnly rather than to (although I have the same problem when I try to instead). The problem is that apparently camel still expects a response, and the route hangs while waiting for one. I suppose if I let it try long enough, it would eventually time out.
To be clear, I'm running a test method:
/* ... */
#Produce(uri = "direct:a")
protected ProducerTemplate directA;
#Test
public void sendMessage() throws Exception {
directA.sendBody(new String[] {"client id", "message"});
directB.sendBody(new String[] {"client id", "message 2"});
}
And I'm seeing the effect of the first call (that is, the message arrives at the server), but not the second, and the method doesn't finish running (again, I'm assuming it'll timeout at some point... if so, the timeout's pretty long: I ran the test as I started writing this, and it's still running).
Am I missing something? Is it a bug? Is it just bad practice to have webservice methods with no response?
By the way, when testing methods which have a response, it works fine.
I think Willem Jiang recently fixed some issue with one-way CXF in Camel recently. Maybe try Camel 2.6-SNAPSHOT from trunk.
I personally prefer two-way with web services, just returning some ACK back in case there is no data to return back. The client most often want some confirmation the server has received and acknowledged the data.
camel-cxf producer decides if it will handle the response message by checking if the operation is oneway. Even the sendMessage operation is oneway invocation, your server should send Http states 202 message to the client according the HTTP protocol, otherwise camel-cxf producer will still wait for the response.
BTW, I think the issue[1] that Claus said was related to async invocation of camel-cxf producer with one way message, not sure if it's the same issue as you mentioned(I didn't know which version of camel are you using).
[1]https://issues.apache.org/jira/browse/CAMEL-3426
Willem

Resources