I'm using Camel with Spring Boot. I want to set "connectionTimeToLive" option for http component at global scope so that every use of the component will have the option. How can I do that?
After reading Camel test cases, I found out this solution using Custom Camel context configuration:
#Bean
CamelContextConfiguration contextConfiguration() {
return new CamelContextConfiguration() {
#Override
public void beforeApplicationStart(CamelContext context) {
HttpComponent http = context.getComponent("http4", HttpComponent.class);
http.setConnectionTimeToLive(5000);
}
#Override
public void afterApplicationStart(CamelContext camelContext) {
}
};
}
You have several options.
Add it to the camel registry and fetch it from there.
Add it as a Camel Exchange property.
Fetch it from a property file.
The way Camel works, you will have to configure this value in a property placeholder.
Also you can define endpoints in camel, instead of defining them straight away in the routes. (Eg: <endpoint id="bla" uri="foo" .. />). This way you can refer them in multiple places.
Also if you want to use this endpoint for multiple hosts, then consider passing things like host name, etc as a header. Eg: Exchange.HTTP_PATH
I am not sure whether Camel has any other Global config approach.
Cheers.
Related
Requisite disclaimer about being new to Camel--and, frankly, new to developing generally. I'd like to have a string generated as the output of some function be the source of my camel route which then gets written to some file. It's the first part that seems challenging: I have a string, how do I turn it into a message? I can't write it into a file nor can I use JMS. I feel like it should be easy and obvious, but I'm having a hard time finding a simple guide to help.
Some pseudo-code using the Java DSL:
def DesiredString() {return "MyString";}
// A camel route to be implemented elsewhere; I want something like:
class MyRoute() extends RouteBuilder {
source(DesiredString())
.to("file://C:/out/?fileName=MyFileFromString.txt");
}
I vaguely understand using the bean component, but I'm not sure that solves the problem: I can execute my method that generates the string, but how do I turn that into a message? The "vague" is doing a lot of work there: I could be missing something there.
Thanks!
Not sure if I understand your problem. There is a bit of confusion about what the String should be become: the route source or the message body.
However, I guess that you want to write the String returned by your method into a File through a Camel route.
If this is correct, I have to clarify first the route source. A Camel Route normally starts with
from(component:address)
So if you want to receive requests from remote via HTTP it could be
from("http4:localhost:8080")
This creates an HTTP server that listens on port 8080 for messages.
In your case I don't know if the method that returns the String is in the same application as the Camel route. If it is, you can use the Direct component for "method-like" calls in the same process.
from(direct:input)
.to("file:...");
input is a name you can freely choose. You can then route messages to this route from another Camel route or with a ProducerTemplate
ProducerTemplate template = camelContext.createProducerTemplate();
template.sendBody("direct:input", "This is my string");
The sendBody method takes the endpoint where to send the message and the message body. But there are much more variants of sendBody with different signatures depending on what you want to send it (headers etc).
If you want to dive into Camel get a copy of Camel in Action 2nd edition. It contains everything you need to know about Camel.
Example:Sending String(as a body content)to store in file using camel Java DSL:
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
public void configure() {
from("timer:StringSentToFile?period=2000")
.setBody(simple(DesiredString()))
.to("file:file://C:/out/?fileName=MyFileFromString.txt&noop=true")
.log("completed route");
}
});
ProducerTemplate template = context.createProducerTemplate();
context.start();
Is there a way to use method references in Camel routes? :
from(X).bean(instance::method)
Thanks
There's two ways you can do this. As CookieSoup mentioned, you can use the bean bindings like this bean(Instance.class, "method(String)").
Or you can use camel Processors and Transforms. There's an example on github of how to use this (you'll need Camel 2.18.0 or greater).
class SomeClass {
public void method(String body) {
}
public String methodWithReturn(String body) {
return body;
}
}
.processor
.body(String.class, instance::method)
.translate
.body(String.class, instance::methodWithReturn)
Note, processors are consumers, whereas transforms are functions that return a transformed message body.
An existing application uses Camel logging (bog the "log()" DSL, and also the Log component.
We would like to either intercept or override so that every log message also logs out a specific Header value (e.g. x-correlation-id=ABC-123)
What is a good, idiomatic way to achieve this?
Apache Camel supports pluggable LogListener since version 2.19.0. This is pretty powerful, because its method onLog, which is invoked right before logging, have instances of Exchange, CamelLogger and message. You can customize the message there with almost no limitations.
Implementation of LogListener:
public class MyLogListener implements LogListener {
#Override
public String onLog(Exchange exchange, CamelLogger camelLogger, String message) {
return String.format("%s: %s", exchange.getIn().getHeader(Exchange.CORRELATION_ID), message);
}
}
LogListener registration:
getContext().addLogListener(new MyLogListener());
If you are using Apache Camel version 2.21.0 and newer, you dont need register it to context, because it is looked up in Registry, so annotating MyLogListener as #Bean is enough.
I'm using Camel Rest (with restlet component) and I have the following APIs:
rest("/order")
.get("/{orderId}").produces("application/json")
.param().dataType("int").type(RestParamType.path).name("orderId").endParam()
.route()
.bean(OrderService.class, "findOrderById")
.endRest()
.get("/customer").produces("application/json").route()
.bean(OrderService.class, "findOrderByCustomerId")
.endRest()
The problem is that the /order/customer doesn't works (see Exception below). The parameters for /customer comes from JWT...
java.lang.String to the required type: java.lang.Long with value
customer due Illegal characters: customer
I think that camel is confusing the ../{orderId} parameter with .../customer.
If I change the /customer for /customer/orders it's works.
The same idea in Spring Boot could have done with:
#RequestMapping("/order/{orderId}")
public Order getOrder(#PathVariable Long orderId) {
return orderRepo.findOne(orderId);
}
#RequestMapping("/order/customer")
public List<Order> getOrder() {
return orderRepo.listOrderByCustomer(1l);
}
Any idea about what's happening?
Try changing the order of your GET operations in the Camel Rest DSL. The restlet component has some issues in matching the best possible methods.
There is a couple of JIRA tickets related to this:
https://issues.apache.org/jira/browse/CAMEL-12320
https://issues.apache.org/jira/browse/CAMEL-7906
I am creating a JMS route programatically by following code :
from("jms:queue:OUTBOUND_QUEUE?concurrentConsumers=5&messageListenerContainerFactoryRef=msgListenerContainerFactory").processRef("mqprocessor");
I have class :
public class MessageListenerContainerFactoryImpl implements MessageListenerContainerFactory {
#Override
public AbstractMessageListenerContainer createMessageListenerContainer(
JmsEndpoint endpoint) {
}
}
I want to exchange some information/parameter between the above route and endpoint. And based on the parameter value I want choose the connection factory to be set in this message listener container.
Please let me know if I was able to explain my problem statement.
Is there any other way to achieve this? I want build connectionfactory at runtime and so do route.
Is there any method in JmsEndpoint which I can leverage to know route-id?
I would create such a route in a method, supply the MLC as a parameter, then when needed, remove that route gracefully and recreate it with new parameters. Changing the parameters does not really make much sense.