Camel Wiretap with choice - apache-camel

I am using Spring Boot with Apache camel. I am invoking the routes from the controller. Once the route completes, the control goes back to the controller.
I am generating the response in the VerifyLimitProcessor and ApprovedLimitProcessor. If I don't provide the wiretap configuration in the route, the controller retrieves the header and the body as expected. But if I introduce wiretap in the route, the controller receives header and body as null. It will be a great help if someone points me out what I need to do so that I can introduce the wiretap configuration for both the processor, namely VerifyLimitProcessor and ApprovedLimitProcessor in the choice statement.
Thanks in advance for your suggestion.
from(SERVICE_ENDPOINT).process(new ValidatorProcessor())
.to(bean:limitDataDaoImpl?method=getLimitData(${body}))
.process(new AuthorizationProcessor())
.choice()
.when(isLimitGreater())
.log("Limit is greater ")
.to(bean:limitDataDaoImpl?method=getVerifiedLimit(${body}))
.process(new VerifyLimitProcessor())
.otherwise()
.process(new ApprovedLimitProcessor())
.endChoice()
.end()
.wireTap("direct:auditEndPoint")
.executorServiceRef("wireTapThreadPool");

endChoice().end() might be the cause.
Try with the end() only. In other words, remove the endchoice()

Related

In Apache Camel what does "route()" do in a restful declaration?

Trying to google "route" in relation to Camel is like trying to google "the". Browsing the docs and can't find it either, only an interface called Route.
Inherited some code that looks like
rest("/someRoute")
.description("Some description")
.consumes("text/plain")
.produces("text/plain")
.post()
.route()
.to("direct:toSomewhere");
What does route() do? I have tried with and without route() and it doesn't seem to do anything.
Using .route allows you to define new route(s) within your rest-definition. It can be handy if your route is short or if you just want to process/transform/validate the message in someway before sending it to your actual consumer endpoint.
For example
rest("/someRoute")
.id("someRoute")
.description("Some description")
.post()
.consumes("text/plain")
.produces("text/plain")
.route()
.routeId("someRoutePost")
.process(new SomeMessageProcessor())
.to("direct:toSomewhere")
.end()
.endRest()
.get()
.route()
.routeId("someRouteGet")
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(405))
.setBody(constant("GET not allowed on this route"))
.end()
.endRest()
But if you just want to call direct consumer endpoint and do this stuff there instead you can do that.
it is up to ones preference really.
thanks, I see if I wanted to say call .log() I would have to put .route() first
Yes. Camel uses method-chaining with its Java-DSL where something like this is often required. When defining Rest most methods return RestDefinition but if you look closely .route method returns RouteDefition instead.
To get back to RestDefition from route one can use .endRest() as the .end() in the example doesn't really do anything other than make it easier to see where to RouteDefition block ends.
Update: Note that this example is for Camel 3.14.0. In Newer versions of Camel route() and endRest() methods have been Removed from RestDefition class. Example for Camel 3.18.1 can be found here.

Camel unit of work

I am trying to understand the unit of work concept in Camel. I have a simple question hopefully someone here can help.
If there are multiple routes involved in routing the Excachange for example
from("aws-sqs:Q1").to("direct:processMe");//route1
from("direct:processMe").to("direct:aws-post");//route2
from("direct:aws-post").to("htt4:myservice");//route3
Is the unit of work invoked at the end of each routes? Or only at the end of route3? In my example, will the SQS message be deleted off of SQS once route1 completes? Or will it wait until my message reaches "myservice"?
Thanks.
FOLLOW UP:
I've modified the route slighty:
from("aws-sqs:Q1").to("direct:processMe");//route1
from("direct:processMe").process(
new Processor(){
public void process(Exchange exchange) throws Exception {
throw new RuntimeException("fail on purpose");
}
}
).to("direct:aws-post");//route2
from("direct:aws-post").to("http4:myservice");//route3
The thought process is this:
If the unit of work is invoked at end of each route then once the message is read from SQS Queue it will be acknowledged as read by the SQS component. On the other hand if unit of work is only invoked once the Exchange is done routing through all routes, then the exception in route 2 will result in the message not being acknowledged and will be available for redelivery once the visibility period expires.
The test showed that the message remains on the Q despite being read by first route. It is picked up again and again (until it ends up in dead letter q). As such I strongly believe that the unit boundary is defined by the end of Exchange being routed.
A unit of work is basically a transaction.
By default a message for a route (a camel Exchange) runs inside a single UnitOfWork context.
In your example there are 3 UnitOfWorks set up, starting at each from and finishing at the final to in each route.
I would expect the message from SQS to be consumed after the 1st route finishes. To test, you could add in a sleep to allow you to check the queue.
from("direct:processMe").process(new Processor()
{ void process() { try { Thread.sleep(60000L) } catch (Exception e) { } }
}).to("direct:aws-post")
If you want the message to remain on the queue until myservice gets the message then you need to put the processing in a single route.
I have found a great explanation as to the unit of work boundary:
"The OnCompletion DSL name is used to define an action that is to take place when a Unit of Work is completed.
A Unit of Work is a Camel concept that encompasses an entire exchange. See Section 43.1, “Exchanges”. The onCompletion command has the following features:
The scope of the OnCompletion command can be global or per route. A route scope overrides global scope.
OnCompletion can be configured to be triggered on success for failure.
The onWhen predicate can be used to only trigger the onCompletion in certain situations.
You can define whether or not to use a thread pool, though the default is no thread pool."
In case of SQS processing, the consumer defines onCompletion on the exchange. So it is invoked only after the exchange is done routing.
The whole answer can be found here: Apache Camel Development Guide2.11. OnCompletion

Apache Camel - recipientList - need of end

After using recipientList in a camel route, within a choice.when, I would like to route this further to another destination with to("xy").
Syntax-highlighting in a java IDE is showing me that this is not possible.
If I put an end after recipientList, all appears to fit again.
Is that required? I could not find any examples in the docs/net showing s/t similar...
.choice()
.when(aPredicate)
.setHeader(Exchange.FILE_NAME).simple("st")
.recipientList(getAValueBuilder())
.end()
.to("ftp:me#ftpserv//usr/dest")
.when(anotherPredicate)
.to(nirv)
.setHeader(Exchange.FILE_NAME).simple("nt")
.to("ftp:me#ftpserv//usr/anotherdest")
.end()
Generarilly I am not sure, while using choice, when to use end. And to make it more difficult, there is an endChoice...
I tryed to use the formatting, to show the way I think it should be use above.
Thanks for feedback.

Handling incoming JMSCorrelationId in an Apache Camel route

I have an camel route consuming on a JMS (activemq) queue targeted to be called in a request/reply manner. Inside this route I split the message and invoke another activemq queue (also in a request/reply manner).
Heres a minimal route showing the situation
<route>
<from uri="activemq:A" />
<split>
<xpath>/root/subpart</xpath>
<inOut uri="activemq:B" />
</split>
</route>
The problem is that Camel does not set a new JMSCorrelationId (since there is already one from the incoming message). If nothing is done, you get responses with unknown correlationId's and the exchanges never end.
I didn't go into details but my guess is that the same temporaryQueue is used for the hole splitter but that it (logically) expects different correlation id's for each of the messages. All using the same, it recieves the first and does not know what to do with the others.
What would be the best solution to handle the situation ?
The one I've found working is to save in another header the incoming JMSCorrelationId (not sure I need to though), and removing it. This is not really as clean as I would want it to be, but I couldn't think of something else. Any ideas ?
Essentially, your case is described in this Jira issue It seems there will be an addition in 2.11 where you can ask Camel to create a new corr-id.
So, in the meantime, why don't you continue what you had working - to remove the JMSCorrelationId header <removeHeader headerName="JMSCorrelationId" /> before you send it to "activemq:B"? I guess that is the best solution for now.
You could, of course, play with the "useMessageIDAsCorrelationID" option as well on the second endpoint.

Idiomatic way to consume from an endpoint in Apache Camel for the response to an endpoint

What I want to be able to do is following:
from(...)
.replyWith()
.from(...)
.end()
So that the response to my producer is taken from the consumption of another endpoint, an example would be something like a REST endpoint for a queue.
Is there an idiomatic way in Camel to be able to do something like the above without grabbing an Endpoint from a CamelContext instance and manually retrieving the contents and setting them into the Exchange?
Can you explain a bit more?
You dont want to just do
from A
to B
from B
to C
So that a message send to A will be send to B. And B is processed in another route, and the response from this will be send back to the first route, which will be used as reply to any client invoking A in the first place.
Also if you want something with dynamic endpoints, then you can use the Recipient List EIP pattern
http://camel.apache.org/recipient-list.html
from("http://0.0.0.0:9001/getResultsFromQueue")
.pollEnrich("activemq:queue:myQueue")
.to("log:test?level=DEBUG");

Resources