I am trying to figure out how to re-route dynamically for a camel route. I currently calculate the route in a processor based on some inputs. The route is then put into the message header. I thought I'd be able to re-route dynamically using
.routingSlip(header("myHeader").toString())
or something like it, but I have not had any luck so far.
Any help is appreciated...
You should not use the .toString(), it should simply be
.routingSlip(header("myHeader"))
As documented in the Camel documentation
http://camel.apache.org/routing-slip
Then "myHeader" should just contain 1..n endpoints where the message should be routed. If you have multiple endpoints then separate them with comma.
We, during our processor, set a property:
exchange.setProperty("sendTo", blah);
then, instead of routingSlip, use recipientList like:
.recipientList(property("sendTo"));
...which works great. I don't think a full example is necessary for this?
Related
I'm developing a REST API using Restlet.
So far everything has been working just fine. However, I now encountered an issue with the Router mapping of URL to ServerResource.
I've got the following scenario:
GET /car returns a list of all cars
GET /car/{id} returns details about the car with id 1
GET /car/advancedsearch?param1=test should run a search across all cars with some parameters
The first two calls work without any problems. If I try to hit the third call though, the Restlet Router somehow maps it to the second one instead. How can I tell Restlet to instead use the third case?
My mapping is defined as follows:
router.attach("/car", CarListResource.class);
router.attach("/car/{id}", CarResource.class);
router.attach("/car/advancedsearch", CarSearchResource.class);
CarSearchResource is never invoked, but rather the request ends up in CarResource.
The router's default matching mode is set to Template.MODE_EQUALS, so that can't be causing it.
Does anyone have any further suggestions how I could fix it?
Please don't suggest to use /car with the parameters instead, as there's already another kind of search in place on that level. Also, I'm not in control of the API structure, so it has to remain as it is.
you need to add .setMatchingQuery(true); to that rout in order it to recognize that it is with a query at the end of it.
Router router = (Router) super.createInboundRoot();
TemplateRoute route1 = router.attach("/car/advancedsearch?{query_params}", MyResource.class);
route1.setMatchingQuery(true);
return router;
Mind that this pattern is with the exact specific order that you have determined in the route i.e. advancedsearch comes first and query_params comes after
I was able to solve this by simply reordering the attach statements:
router.attach("/car/advancedsearch", CarSearchResource.class);
router.attach("/car", CarListResource.class);
router.attach("/car/{id}", CarResource.class);
I have a pretty simple purpose
URIs of form ->/random/* go to /*. For example /random/users goes to /users.
I don't wish to use redirect() to solve the problem.
I have a tried a few ways but not sure about implementation -
Intercept the request before it reaches the router. And change the URI somehow. I am trying to Override the onRequest method, but unable to proceed as I don't know the implementation. (possible issue with: should routing really be here?)
Have an entry in routes which is like /random/*, make it point to a controller method. From inside the controller call the router method again with the modified URI. Again here unable to proceed as stuck with implementation.
Double the routes file or put a regex in routes file. For each entry, copy it and append /random to it. I dont want to do this, since it makes the file difficult to manage. Last resort really.
Please help regarding how to implementation Point 1 or Point 2.
If there is any other much simpler way please help..
Add a new Random-controller and create an action which forwards the calls to the proper controllers.
Use the following route:
GET /random/:controller controllers.Random.handleRandom(controller:String)
Let the handleRandom-action forward the calls accordingly (with or without redirect). You can either do some reflection-magic to forward the call to other controllers, or use a if-then-else- or switch-clause.
Essentially, I'd like to aspect a whole camel route, so that I can grab the payload at the start and the end.
Now, I know I can just aspect the main "doing" class in the middle, not pulling it from a queue and placing it on the disk at the end. And this is fine for a simple route, not one that has many "doing" classes.
But is there a way to tie up the start and end of a route, without putting this into the route?
I have got a lot of routes and I'd like to keep them as clean of logging code as possible.
Use the interception possibilities of Camel as described here:
intercept that intercepts each and every processing step while routing an Exchange in the route.
interceptFrom that intercepts incoming Exchange in the route.
interceptSendToEndpoint that intercepts when an Exchange is about to be sent to the given Endpoint.
In your case the second and third possibility may be of interest.
I think you've got two choices:
Add a wiretap at the start and end of each route. See http://camel.apache.org/wire-tap.html. This obviously means editing the routes but is simple easy and it only two lines per route.
Use RouteDefinition.adviceWith to dynamically add an interceptor. See http://camel.apache.org/advicewith.html. I've not seen this used outside testing but I don't see any reason why you can't use it in live code.
I'm designing a system using comet where there is a common channel where data getting published. I need to filter the data using some conditions based on client subscription details. Can anyone tell how I can do this? I thought I can do this using DataFilter.
Channel.addDataFilter(DataFilter filter);
Is this the correct way? If so any sample code to achieve this please?
There is no Channel.addDataFilter(DataFilter) method, but you can achieve the same results in a different way.
First, have a look at the available DataFilter implementations already available.
Then it's enough that you add a DataFilterMessageListener to the channel you want to filter data on, and specify one or more DataFilter to the DataFilterMessageListener.
You can find an example of this in the CometD demos shipped with the CometD distribution, for example here.
The right way to add the DataFilterMessageListener is during channel initialization, as it is done in the example linked above through a #Configure annotation, or equivalently via ServerChannel.Initializer.
Finally, have a look at how messages are processed on the server from the documentation: http://docs.cometd.org/reference/#concepts_message_processing.
It is important to understand that modifications made by DataFilter are seen by all subscribers.
I am not really a fan of the default messages used if the #RequestParam fails to validate (type, required, etc). I would like to use my own custom messages.
I also have several parameters that are conditionally required.
I am thinking to achieve this I will need to roll my own HandlerMethodInvoker. resolveHandlerArguments using a modified version of RequestParam.
Is there an easy way to 'inject' my new version of HandlerMethodInvoker into Spring? If not, will I need to create my own DispatcherServlet and the various pieces between it and HandlerMethodInvoker?
If you only want to replace the validation messages then you only need to add some properties to the message files.
For more details read Spring Reference Chapter 5.3 Resolving codes to error messages and have a look at the java doc of org.springframework.validation.DefaultMessageCodesResolver, it explain the used message codes very vell.