I would like to make a camel route from jms to a POJO which can receive a TextMessage.
Right now I route to a bean like this:
from("jms:person_queue").to("bean:QueueConsumerBean?method=consume")
I then receive a String in my bean method. I would rather have a custom class with a "onMessage" method and a TextMessage. The reason is that I want to use client acknowledgement for the message, like a transaction.
Or is there another way to use client ack?
Camel's JMS consumer automatically handles the ack type for you. If the route succeeds, it will ack the message. If it doesn't (ie.. exchange hits an exception handler) it will roll it back.
BIG WARNING: CLIENT_ACKNOWLEDGE's behavior is not intuitive.. per the JMS spec.. it ack's current message AND all previous in a session.. this cannot be counted on to be a per-message ack. If you need per-message ack.. use TRANSACTED.
Related
Bit of a Camel newbie but here goes.
I have the following route:
from("activemq:queue:outputQueue").inputType(HelloWorld.class)
.to("log:stream")
.marshal().json(JsonLibrary.Jackson, HelloWorld.class)
.to("http:localhost:5000/messageForYouSir?bridgeEndpoint=true");
This retrieves messages from the queue and sends them to the HTTP endpoint as JSON. Fine.
But what if there is an error? Say a HTTP error code of 400? Then I want the message to stay on the queue. I have tried looking into not acknowledging the message, but have not been able to make it work.
Also I have made an Exception handler
onException(HttpOperationFailedException.class)
.handled(false)
.setBody().constant("Vi fekk ein feil");
But still the messages are gone from the queue. Is there some magic spell that can make Camel not acknowledge the messages when there is some error?
You have to consume transacted from the queue to be able to do a rollback. This is configured on the connection configuration to the broker.
Take a look at the Camel JMS docs (the ActiveMQ component extends the JMS component), especially the sections about cache levels and transacted consumption.
The most simple setup is using broker transactions by simply set transacted = true and lazyCreateTransactionManager = false on the JmsConfiguration. This way no Spring TX manager is required.
If transacted consumption is in place and the HTTP server returns an error (basically if an Exception occurs in the Camel Route), Camel does automatically a rollback (if you don't catch the error).
We have a camel route where we read a message from an input queue, process it, set some JMS Header( using Exchange.getIn().setHeader(...) ) and then route the message to some output queue. During MQ Failover scenario, the message is redelivered. However, while the message is redelivered the JMS Headers which I put earlier are lost.
Is there any way to preserve the JMS Headers even after redelivery ?
JMS redelivery
No, not if the message is redelivered from the input queue. Simply because it is the same original message you received before. The JMS broker does not know anything about the modifications you did in the Camel route.
However, this is normally not a problem. Because on a redelivery, the same consumer consumes the message again and does the same modifications again on the message.
As soon as you reach a "transaction boundary" in your route (that means, something has done that cannot be repeated or would yield a different result), you should put the modified message on another queue to "save" its current state.
From there you can continue with another consumer and so forth. If you build a processing chain like this, your system is a Pipes and Filter EIP.
Camel redelivery
Another possibility is to use the Camel ErrorHandler. It handles errors on a single route-step level. It can also do retries, but then you have to make sure the message is correctly handled if all Camel retries fail (for example send the message to an error queue).
As long as the broker redelivery is the last resort for your message, you should build your system with potential redelivery in mind.
I have this problem, too. i'm forced to convert my objects to json and save in headers of jms. and after i convert again to object. it's worked for me!
How can I determine what, if any, ActiveMQ queue a camel route is a consumer of? The route is running as a bundle within Karaf.
You have to define it yourself. Every Camel route starts with a from statement. For ActiveMQ this would look somehow like this
from("activemq:queue:myAwesomeQueue")...
This route would create an ActiveMQ consumer that consumes every message arriving on the myAwesomeQueue.
The connection to the broker is "hidden" behind the activemq:. This is a Camel component (the ActiveMQ component) that needs to be configured to connect to the broker.
EDIT: Add operational perspective
Hawtio is a webconsole that uses Jolokia to get data. Jolokia makes JMX information available through a REST API.
If JMX is enabled, you can get loads of information about the CamelContext and/or ActiveMQ. For example the endpoint of an ActiveMQ consumer as in your case.
Unfortunately I can't upload a screenshot because the image domain of SO is blocked, but Google gives you lots of them.
Some AMQP enabled brokers like Microsoft Service Bus or ActiveMQ allow only one active producer or consumer per session. The Apache JMS Camel component seems not be able to handle this correctly, which result that JMS throws exceptions when processing InOut messages sent from e.g. Service Bus.
A small JMS test application with separate sessions for producer and consumer works nice. With using the same session, it run into the same problem.
Issue is rooted in the Spring JMS template, which is used as base for the Camel JMS implementation.
Does anybody know how to overcome that behavior?
You can define a 2nd JMS component and use that for the "other".
Or you can turn off any kind of connection pooling maybe.
If you use XML then you can define a 2nd jms component
<bean id="jms2" class="org.apache.camel.component.jms.JmsComponent"/>
What's the best strategy to send SMS via SMPP with Camel ? Should I use the ProducerTemplate ?
I'm new to camel so I'm not confident if my strategy is the best.
In my application upon reception of an SMS, I have to send back an other SMS with some computed content.
I created a
route smsIn that looks like this
from "uri=smpp ..."
unmarshal ref="bindyDataFormat"
to "uri=bean:myBean
and a route smsOut with
from "uri=direct:smsOut"
to "uri=smpp ..."
The smsIn route, receives the sms, transforms its conent (csv data) in a pojo and send that pojo to myBean.
In myBean I do some processing and then call a ProducerTemplate which send my computed message to the endpoint "direct:smsOut".
The reason I use the producerTemplate is that I have to set some info from my pojo in the header (CamelSmppDestAddr) and the body of the Exchange.
I have tested with the logica SMSC simulator, this seems to work fine, but would like to have your opinion about this solution ?
What about reliability , transaction ?
Should I store my message before trying to send it to the SMSC ?
Should I store it in a database, post it to a queue ?
I'm not sure why you have a producer template, you could just build up the route instead (given that you return something from your bean or takes an Exchange as paramter).
<from uri="smpp: ..."/>
<bean ref="bean:myBean"/>
<to uri="jms:queue:myQueue"/>
then not use direct, but use a JMS queue that is transactional and persistent. Say your smpp call fails, the message would have been gone. Using a queue like this and make sure its transactional, you can make sure not to lose data in this stage of the route.
<from uri="jms:queue:myQueue"/>
<transactional/>
<to uri="smpp.."/>
I suggest using Apache ActiveMQ as JMS middleware. Actually, if you download ActiveMQ, you get camel bundled, so you could actually run your Camel routes from ActiveMQ.
You might want to tweak how retries and error handling occurs dependent on what you want to happen (retry every second forever?, retry five times, then put to error queue? etc).
Read this page: Transaction Error handling in Camel
For deeper info and more tweaks, you might also want to read this:
Transactional Client