Current behaviour: When I'm running a Quarkus App with Camel it automatically starts all the RouteBuilder Extensions as Routes.
What I want to achieve: On startup only the Routes that I configured are started.
What I tried:
With the following snippet it's possible to explicitly start the CamelMainApplication but I dont know how to get control over e.g. the CamelContext at this point where I would be able to configure my routes.
#QuarkusMain
public class Main {
public static void main(String[] args) throws Exception {
Quarkus.run(CamelMainApplication.class, args);
}
}
On the Route I can use .noAutoStartup() to disable the route on startup. But this means that it's not the default for all routes to be disabled at first and second I don't know where to activate them as I don't know where in a Quarkus App I can get a hand on the Camel Context to activate the route.
With the following in my application.yml I can disable the automatic route discovery but then the remaining question is how I can manually start the route, e.g. in my QuarkusMain class.
quarkus:
camel:
routes-discovery:
enabled: false
I think it is best way. Quarkus has properties for include and exclude route as pattern. this properties is List You can add one to N
quarkus.camel.routes-discovery.exclude-patterns=tes.Comp,tes.package.MyRoute
quarkus.camel.routes-discovery.include-patterns=test.mypackage.XX
I had this same problem I ended up doing something like the following:
#QuarkusMain
public class Main implements QuarkusApplication {
#Inject
OrderService orderService;
#Override
public int run(String... args) throws Exception {
CamelRuntime runtime = Arc.container().instance(CamelRuntime.class).get();
runtime.start(new String[]{});
orderService.handleOrders(args[0]); //this would inject the camelContext and start the route.
return 0;
}
Related
I am using camel-cdi and it is injecting the CamelContext, detecting all the routes in project.
But I want a CamelContext with a registry because I have some components that I use in camel routes like shown below.
SimpleRegistry registry = new SimpleRegistry();
registry.put("actionProcessor", actionProcessor);
registry.put("jpa", jpaComponent);
registry.put("jtaTransactionManager", platformTransactionManager);
CamelContext camelContext = new DefaultCamelContext(registry);
When I inject CamelContext the components like actionProcess, jpa are not recognized. when in my Route I have
.to("bean:actionProcessor?method=myMethod(${body})")
but my bean does not get executed.
I documentation I read use # before components name which are in registry but still it is not working.
Please suggest how can I achieve this using camel-cdi.
Did you already try with creating a CdiCamelContext (a subclass of DefaultCamelContext) ?
Otherwise, a more elegant would be to annotate your various classes, eg:
#Named("actionProcessor")
public class MyActionProcessor{
...
}
We have been using this for years without any problem
public class ContextFactory {
#Produces
#ApplicationScoped
#ContextName("Demo")
static final CamelContext createContext() {
CdiCamelContext context = new CdiCamelContext();
context.setStreamCaching(true);
context.disableJMX();
return context;
}
}
#ContextName("Demo")
public class MyRouteBuilder extends RouteBuilder {
from("...")
.to("bean:actionProcessor?method=myMethod")
}
#Named("actionProcessor")
public class MyActionProcessor{
public void myMethod(#Body String body) {}
}
Of course, in order to work, you need to activate the JEE bean discovery (=add a "beans.xml" file in META-INF or WEB-INF) !
It is possible to pass parameters to a Camel route?, for instance, in the next code snippet:
public class MyRoute extends RouteBuilder {
public void configure() throws Exception {
from("direct:start")
.to("cxf:bean:inventoryEndpoint?dataFormat=PAYLOAD");
}
}
The value for dataFormat is in hard code, but, what if I want set it dynamically?, passing a value from the code where route is called. I know this is possible adding a constructor and passing parameters in it, like this:
public class MyRoute extends RouteBuilder {
private String type;
public MyRoute(String type){
this.type = type;
}
public void configure() throws Exception {
from("direct:start")
.to("cxf:bean:inventoryEndpoint?dataFormat=" + type);
}
}
There is another way?
Thanks so much!
As you mentioned, you can use a constructor (or setters or any other Java/Framework instruments) if the parameters are static from a Camel point of view.
The parameters are configurable in the application, but after the application is started they do no more change. So, every message processed by the Camel route uses the same value.
In contrast, when the parameters are dynamic - i.e. they can change for every processed message, you can use the dynamic endpoint toD() of Camel. These endpoint addresses can contain expressions that are computed on runtime. For example the route
from("direct:start")
.toD("${header.foo}");
sends messages to a dynamic endpoint and takes the value from the message header named foo.
Or to use your example
.toD("cxf:bean:inventoryEndpoint?dataFormat=${header.dataFormat}");
This way you can set the dataformat for every message individually through a header.
You can find more about dynamic endpoints on this Camel documentation page
I have a web application from which I'm calling around 50-60 rest/soap apis. For this, I've created routes in JAVA DSL. Now, to have default application level timeout settings, I've done configuration like this-
public class DefaultHttpClientConfig implements HttpClientConfigurer { // http4
#Override
public void configureHttpClient(HttpClientBuilder clientBuilder) {
clientBuilder.setDefaultRequestConfig(
RequestConfig.custom()
.setConnectTimeout(1000)
.setSocketTimeout(1000).build());
}
}
and I've set this in camel context like this-
static CamelContext ctx = new DefaultCamelContext();
static {
try {
HttpComponent httpComponent = ctx.getComponent("http4", HttpComponent.class);
httpComponent.setConnectionTimeToLive(10);
httpComponent.setHttpClientConfigurer(new DefaultHttpClientConfig());
ctx.addRoutes(new DirectRestRouteBuilder());
ctx.start();
} catch (Exception e) {
e.printStackTrace();
}
}
Now when creating individual routes, I want to override these configuration, so I'm trying this as shown below-
from("direct:success")
.to("http4://localhost:8089/mockcarrier/success?httpClient.socketTimeout=8000");
However, it seems that the direct configuration in JAVA DSL is not picked up. Where am I going wrong?
Add DefaultHttpClientConfig to the Camel registry and set it on the route with the httpClientConfigurer parameter (Camel documentation).
Like this:
.to("http4://localhost:8089/mockcarrier/success?httpClientConfigurer=yourCustomConfigurerNameInTheRegistry");
I'm trying to verify my Camel routes I need to prevent the endpoints from starting, the XMPP in particular as it contains concrete host information in their URI. Unfortunately I don't seem to figure out how.
My test class is as follows:
#RunWith(CamelSpringJUnit4ClassRunner.class)
#ContextConfiguration(
classes = {
ApplicationConfig.class
},
loader = CamelSpringDelegatingTestContextLoader.class)
#UseAdviceWith
#MockEndpointsAndSkip
public class XMPPRouteBuilderTest {
#Autowired
ApplicationContext applicationContext;
#Autowired
CamelContext camelContext;
#Test
public void testConfigure() throws Exception {
camelContext.start();
Collection<Endpoint> endpoints = camelContext.getEndpoints();
}
}
Whenever I call start() the actual endpoints are started which causes the XMPP routes to fail with host not found exceptions; I was expecting the mocks to replace the real ones.
Can anyone suggest what am I doing wrong?
Best,
Edoardo
#MockEndpointsAndSkip is only for producers (eg not consumers) so all the route from endpoints is not mocked.
You can use the replaceFromWith with the advice-with builder. See the section Replace from with another endpoint in the official Camel documentation for an example:
http://camel.apache.org/advicewith.html
In my application I have a generic Camel Route such as the following
from("direct:something").to("direct:outgoing")
and then dynamically in my code I deploy another route:
from("direct:outgoing").process(processor)
When flowing from route 1 to route 2 a new Exchange will be created. Is there an idiomatic way to correlate both? Should I set EXCHANGE.Correlation_ID header on the first route before sending it out?
This should definitely all be processed on the one exchange. Run this test and you'll see the same camel Exchange, with the same properties, etc.
public class CamelExchangeTest {
public static void main(String[] args) throws Exception {
final Processor showExchangeIdProcessor = new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println(exchange.getExchangeId());
}
};
Main camelMain = new Main();
camelMain.addRouteBuilder(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("timer:foo?period=1s&repeatCount=1")
.log("excgabge created!")
.process(showExchangeIdProcessor)
.to("direct:outgoing")
;
from("direct:outgoing")
.log("outgoing!")
.process(showExchangeIdProcessor)
;
}
});
camelMain.run();
}
}
Output:
ID-MYPC-55760-1411129552791-0-2
ID-MYPC-55760-1411129552791-0-2
So something else is going on. When you say "direct:outgoing", do you mean exactly that or is it something different - a different component perhaps?
When you say the route is created dynamically, how exactly is that done, and when (and why?)
From the Camel doc:
Some EIP patterns will spin off a sub message, and in those cases, Camel will add a correlation id on the Exchange as a property with they key Exchange.CORRELATION_ID, which links back to the source Exchange. For example the Splitter, Multicast, Recipient List, and Wire Tap EIP does this.
Thus, Exchange.CORRELATION_ID is set by Camel and should not be set by your application. But feel free to set a custom header or property if you need to such as:
exchange.getIn().setProperty("myProperty", myIdentifier);