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
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).
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.
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.
I currently have a camel route that exposes a cxf endpoint. When a messages comes through the endpoint I would first enrich that message with some information from another webservice and then do more processing afterwards. However, I want make the first half of this route synchronous so I can send back a response to whomever called my exposed cxf endpoint.
The route looks something like this:
from(cxf:CxfEndpoint)
.process(someProcessing)
.to(cxf:ExternalCxfEndpoint)
.to(activemq:queue:somequeue)
//return a response back to caller here
from(activemq:queue:somequeue)
... //additional processing here
...
The reason for this is because when a message comes via my exposed cxf endpoint I don't know if it's a valid message. I need to first validate it with the message enrichment. Once the message is enriched, I want let whomever sent the message know that their message is accepted but don't want them to wait for the message to make it through the whole route as that could take hours.
Does anyone know how this would work?
Thanks in advance!
I believe all you need to do is set exchangePattern to InOnly a.k.a. make it an Event Message. This should have your route not wait for a reply from ActiveMQ. Camel exchange will default to InOut when it's originating from a web service, as in your case.
A related question with an answer from a Camel dev here.
Also see this one for some details on the behavior when your broker is down.
Yes definitely , 100% possible. A simple example would be this :
From cxf endpoint
Store your request in a camel property or header
To xslt - generate xslt for cxf endpoint - Synchronous flow
Reset your original payload using set body.
Wiretap Endpoint - to any endpoint downstream or even a route , this becomes asynchronous . This won't take part in the above sync response .
Note- step 2 & 4 may not be required, it depends on your use case .
There are whole lots of things you can do, I just gave a very simple example . It doesn't need to be wiretap as well, but wiretap helps us not to write any additional custom exceptional handling.
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"/>