As an irrelevant poorly opinionated opinion, I find apache camel docs too presumptuous in presuming the reader has a background in camel already.
In normal terms, a web service provider is a producer, and a client of the service it produces is a consumer.
Let's look at http://camel.apache.org/pojo-producing.html.
Which says, there are two diff ways to send messages to Camel Endpoint.
#EndpointInjecct (uri ..) ProducerTemplate ...
Is it saying
Hey I;m an endpoint and this is my uri and a template to hit me with, so hit me
Or, hmm ... there is an endpoint with this uri somewhere out there beneath the clear blue skies, and here is the template I presume I'm gonna hit it with
???
Similarly, is #Produce, and ProducerTemplate
specifying I'm an endpoint that is going to get hit?
or specifying the template of a producer I am going to hit??
Similarly, #Consume,
Am I specifying I am a consumer?
Or that I am specifying how I am to be consumed?
And BTW, the uri in #Produce(uri) or EndpointInjection (uri)
am I sending to this uri?
or recceiving under this uri?
As per your doubts, below I'm trying to clarify:
#EndpointInject (uri=...) ProducerTemplate ...
This means rather your 2nd option:
there is an endpoint with this uri somewhere out there beneath the clear blue skies, and here is the template I presume I'm gonna hit it with
I.e., uses the Camel API, ProducerTemplate, to send the message to another endpoint, defined on the uri.
Regarding the #Produce and ProducerTemplate, the closest guess here would be
specifying the template of a producer I am going to hit
Although technically the endpoint specified to be hit on the uri is not to be mistaken with the producer in Camel terminology, it is simply an endpoint, which in this context would be called a consumer since it receives messages.
Analogously, regarding #Consume marks the method as a consumer method, i.e. the one that handles the endpoint incomming messages, endpoint specified by the uri.
Hope this is of some help.
Related
We struggle to find a solution for the following scenario:
Situation
Receive a message via Spring Cloud Streamlistener
Invoke a REST-Service via Feign-Client
We have configured several Feign-RequestInterceptor to enrich
request header data.
We want to avoid passing every request header on the method call and like the central configuration approach of the request interceptors.
Problem:
How to access data from a specific message, which contains informations, that need to be added to every request call via the Feign-RequestInterceptor.
We don't have a Request-Context, as we come from a message.
Can we be sure , that the message consumption and the REST call is happening on the same thread? If yes, we could use the NamedThreadLocal to store the information.
Yes, unless you hand off to another thread in your StreamListener, the rest call will be made on the same thread (assuming you are using RestTemplate and not the reactive web client).
I have a route in camel which is as follows
errorHandler(deadLetterChannel("file:somelocation");
from("jms:queuwlocation").to(
"file:someLocation");
I have read that camel error handling comes when there's a processing between two nodes, such as Processor, Predicate etc. But what if I cannot consume the message, in my case the camel cannot connect to jms. How should I log this exception ?. As I am trying to use a deadLetterChannel to send the message to filesystem, but since I have not received the message there is nothing new on the file location. how should I encounter this type of situation?
The problem you are facing might be due to the JMS Connection Exception being thrown outside of the life cycle of your Camel exchange. Claus Ibsen refers this in "Camel in Action" as a chicken and egg situation:
You can picture this as a chicken and egg situation. Camel's error handler only applies
during routing of Exchanges (chicken), but the consumer needs successfully to create the
Exchange (hatch the egg). So if we want a chicken but only have an egg, what can we do?
The answer lies with extending the error handling boundaries to cover the entire Camel JMS Consumer:
As
a figure of speech we can tell Camel to treat the eggs as if they were chickens. This is done by
configuring the consumer to bridge its internal error handler with Camel's error handler.
For the JMS module, I suspect this involves playing around with the transferException property. Good luck with that!
Futhermore, I don't think using a deadletter channel is appropriate for your problem, since you don't gain anything from taking messages out of the queue when encountering a connectivity problem.
Typically connectivity problems are self fixing, e.g. a server was restarted, and can be solved by retrial. For your use case, a sensible redelivery strategy can do this. Luckily Camel is really good at this: https://camel.apache.org/redeliverypolicy.html.
I recommend an indefinite redelivery until connectivity commences. Something like this:
onException(SomeJmsTimeoutException.class, SomeJmsConnectivityException.class)
.useOriginalMessage()
.maximumRedeliveries(Integer.MAX_VALUE)
.retryAttemptedLogLevel(LoggingLevel.ERROR)
.logRetryStackTrace(true)
.redeliveryDelay(1000 * 60);
As far as I know the error handling does not come in play just between the nodes. It has a more complete scope than that. It also depends on the type of error you are facing.
How you should log the exception?
Well why don't you do it like this?
DeadLetterChannel defined and you refer to it on your CamelContext.
The deadletteruri refers to another route - call it errorhandler route.
In the errorhandler route you can set headers that contain errors and other information you want to set.
In the errorhandler route in your "to" send the error message to a file writing the headers with it like you would with a log file.
There is a webapp, where every request consumes various external resources. The webapp tracks those consumed resources with request scooped bean. Then HandlerInterceptor's afterCompletion method calls TaskExecutor to store this information in DB. All is fine and dandy, but there goes the requirement to add bandwith consumption as another resource. Counting outgoing response size is a typical task for servlet filter (along with response wrapper and custom stream implementation). So this is done and is also working.
The problem is that I'd like to aggregate two things together. Obviously, I can't pass "bytes sent" to Spring HandlerInterceptor, because filter's doFilter() hasn't completed yet and the amount of bytes sent isn't known when the interceptor runs. So filter must be the place to aggregate all the resource usage and start async task to store it in DB. The problem is: how can I pass data from HandlerInterceptor to Filter. I've tried simple request.setAttribute() but surprisingly it didn't worked.
As a side note: I'm aware of request scooped bean lifecycle and at the handler I'm creating a simple POJO populated with data from scooped bean.
The problem turned out to be quite trival. The app was doing a lot of forward/dispatches as a part of somehwat normal request handling. It turned out that the my filter was called (so far, so good) then another filter down the chain was doing forward/dispatch which then did actual request processing. Default filter setup catches only plain requests and you need additional configuration (web.xml) to also filter forwards/dispatches. I just did that and that solved the problem.
Please excuse stupidity as this is my first Camel application
To respond to a web request, I am sourcing the content from two different sources.
I am, therefore, making a multicast request to two methods and parallelizing it.
The response is an marshalled JSON object (using camel-jackson)
All works fine.
public class RestToBeanRouter extends RouteBuilder{
#Override
public void configure() throws Exception {
from("cxfrs://bean://rsServer")
.multicast()
.parallelProcessing()
.aggregationStrategy(new CoreSearchResponseAggregator())
.beanRef("searchRestServiceImpl", "firstMethod")
.beanRef("searchRestServiceImpl", "secondMethod")
.end()
.marshal().json(JsonLibrary.Jackson)
.to("log://camelLogger?level=DEBUG");
}
Question :
The Multicast routing expects a to in the DSL. Currently, I am mapping this to a log endpoint. Is this fine?
Since I am not using the to and the last exchange of the Aggregator strategy is the one which is returned to the user, should my endpoint be configured to something else - like a null or something? (Ah, the stupidity kicks in)
For the benefit of SO visitors, copying the solution given in the Camel mailing list here :
by Robert Simmons Jr. MSc. - Lead Java Architect # EA
Author of: Hardcore Java (2003) and Maintainable Java (2012)
The aggregated exchange is the one that gets returned and how the
aggregated exchange is created depends on the aggregation strategy you use.
When a route stops either by calling stop or merely not routing anymore,
the exchange on the last part of the route could be considered a reply. In
most cases it will reply back to the caller (unless you set a reply-to
destination in a JMS based route or some other cases). In your case if all
you want to do is return the enriched exchange then you dont need any to()
call. Just stop after the marshal.
I have this in my applcation routes file:
GET /new Tweets.create
POST /new Tweets.save
And in my view I'm creating a form like this:
#{form #save()}
...
#{/form}
But once is submit the form it's sending me to /tweets/save and not to /new. Any ideas how I can fix this? Thanks!
If you have already tried the route below (which is the correct way to use routes)
#{form #Tweets.save()}
and this did not work, I think you may have put your route in the wrong place. Make sure it is at the top of the routes file, and not after the catch-all route. The routes file is processed in order, so if the catch-all is found, this is used first and your other route is ignored. The catch-all looks like
* /{controller}/{action} {controller}.{action}
Try using
#{form #Tweets.save()}
I think it is suggested to use class names with method names.
EDIT:
The way the play framework routing works is you define some route as
GET /clients Clients.index
If a request encountered with URI /clients then it will be intercepted to Clients.index(). If you have another routing such that
GET /clients Clients.save
Then the framework ignores this routing because /clients aready has a mapping. (Most probably it is giving some error in the console or logging stream, check your logs.)
Therefore you can't make it work like that. I see, you request a reverse mapping that will return the same URI for different methods. However the framework aims to intercept requests so that it will simply ignore your second routing.
Try to separate pages. Most probably what you want is to render the same views for two functions. You can do that without redirecting them to the same URI.
I think (if I did not misread) that the issue is you expecting the wrong behavior.
As I understand you expect that the submit will go to Tweet.save() (POST method) and then back to Tweet.create() (GET method) as both share the same path (/new).
In reality Play is calling Tweet.save() and it expects a render at the end of Tweet.save() to display some result. If you want to redirect to Tweet.create() you can do a call to that method at the end of the implementation of Tweet.save(), with either:
create(<params>);
or
render("#create", <params>);
and that should redirect (via 302) to the GET version.