blob: 69ef3b816ae47210dabdb2ee41428330cabde9e5 [file] [log] [blame]
= Route Configuration
Camel 3.12 introduces route configuration which is used for separating configurations
from the routes. This can be used in situations such as configuring different error handling across a set of routes.
In previous versions of Camel, this was more cumbersome to do, as you would either have
to copy the same configuration to a set of routes or rely on global error handling configuration.
Now you can configure a number of route configurations, and then specify on each route
which configuration to use (you can use match by ids, wildcards, and regular expression).
The route configuration is supported by all DSLs, so usable by: Java, XML, Groovy and so forth.
In the route configuration, you can set up common strategies for:
- xref:error-handler.adoc[Error Handler]
- xref:exception-clause.adoc[OnException]
- xref:oncompletion.adoc[OnCompletion]
- xref:components:eips:intercept.adoc[Intercept]
== Route Configuration Builder in Java DSL
With Java DSL you can use `RouteConfigurationBuilder` to specify the configuration as shown below.
The builder is similar to `RouteBuilder` so its use is familiar.
[source,java]
----
public class MyJavaErrorHandler extends RouteConfigurationBuilder {
@Override
public void configuration() throws Exception {
routeConfiguration("javaError")
.onException(Exception.class).handled(true)
.log("Java WARN: ${exception.message}");
}
}
----
NOTE: The `RouteConfigurationBuilder` uses `configuration` as the method where the configuration is coded.
This is on purpose, so as not to use the `configure` method which the regular Java DSL `RouteBuilder`
uses for coding Camel routes.
In the example above, then there is only one route configuration that has been assigned the ID `_javaError_`.
This ID allows us to refer to this configuration later when you want to assign which routes are using the configuration.
This configuration is a basic configuration that just catches and handles all exceptions and logs a WARN message.
=== Assigning route configurations to routes
To use this configuration in your routes, then you can assign it with `routeConfigurationId` as shown:
[source,java]
----
public class MyJavaRouteBuilder extends RouteBuilder {
@Override
public void configure() throws Exception {
from("timer:java?period=2s")
// refer to the route configuration by the id to use for this route
.routeConfigurationId("javaError")
.setBody(method(MyJavaRouteBuilder.class, "randomNumber"))
.log("Random number ${body}")
.filter(simple("${body} < 30"))
.throwException(new IllegalArgumentException("The number is too low"));
}
public static int randomNumber() {
return new Random().nextInt(100);
}
}
----
In the `routeConfigurationId` the configuration to use is specified by the ID, eg `_javaError_`.
Multiple configurations can be assigned (separated by comma), such as:
[source,java]
----
.routeConfigurationId("javaError,myAudit")
----
The route configuration supports matching by:
- exact ID name. This is the sample we have seen above.
- wildcard
- regular expression.
Wildcards are text ending with a `*`.
They are matched when the configuration ID starts with the specified text followed by any characters.
For instance, you can do:
[source,java]
----
.routeConfigurationId("java*,myAudit")
----
Here we use wildcard in `_java*_` which means any configuration whose ID starts with java is a match.
Match by regular expression is just like match by wildcard but using regex instead.
[source,java]
----
.routeConfigurationId(".*error.*")
----
Here we want to match any configuration whose ID contains `_error_`.
=== Adding route configurations to CamelContext
Because a `RouteConfigurationBuilder` is also a `RouteBuilder` then you add route configurations
the same way for `RouteBuilder` such as using the API on `CamelContext`
[source,java]
----
CamelContext context = ...
// add the route configuration
context.addRoutes(new MyJavaErrorHandler());
// add the regular route
context.addRoutes(new MyJavaRouteBuilder());
----
If you use Spring Boot, then your Camel routes and route configurations can be auto-discovered
by the spring boot component scanning. This requires adding the `@Component` annotation to the class.
See the example https://github.com/apache/camel-spring-boot-examples/tree/main/routes-configuration[camel-spring-boot-examples/routes-configuration].
=== Route configuration with Endpoint DSL
The xref:Endpoint-dsl.adoc[Endpoint DSL] can also be used for route configurations.
This requires adding `camel-endpointdsl` to the classpath, and then using
`org.apache.camel.builder.endpoint.EndpointRouteConfigurationBuilder`,
which offers the _type safe_ DSL for Camel endpoints.
== Default route configurations
Route configurations are either given an explicit unique ID, or the configuration is _nameless_.
A _nameless_ configuration is used as default/fallback configuration, for routes which have *NOT*
been explicitly assigned route configurations.
Suppose you have one _nameless_ configuration and another named `_retryError_`:
[source,java]
----
public class MyJavaErrorHandler extends RouteConfigurationBuilder {
@Override
public void configuration() throws Exception {
routeConfiguration()
.onException(Exception.class).handled(true)
.log("WARN: ${exception.message}");
routeConfiguration("retryError")
.onException(Exception.class).maximumRedeliveries(5);
}
}
----
And the following two routes:
[source,java]
----
from("file:cheese").routeId("cheese")
.to("kafka:cheese");
from("file:beer").routeId("beer")
.routeConfigurationId("retryError")
.to("jms:beer");
----
In the example above, the `_cheese_` route has no route configurations assigned, so the route
will use the default configuration, which in case of an exception will log a warning.
The `_beer_` route on the other hand has the route configuration `_retryError_` assigned, and this
configuration will in case of an exception retry up to five times and then if still an error
then fail and rollback.
If you add more routes, then those routes can also be assigned the `_retryError_` configuration
if they should also retry in case of error.
=== Route Configuration with Error Handler
Each route configuration can also have a specific error handler configured, as shown below:
[source,java]
----
public class MyJavaErrorHandler extends RouteConfigurationBuilder {
@Override
public void configuration() throws Exception {
routeConfiguration()
.errorHandler(deadLetterChannel("mock:dead"));
routeConfiguration("retryError")
.onException(Exception.class).maximumRedeliveries(5);
}
}
----
In the example above, the `_nameless_` configuration has an error handler with a dead letter queue.
And the route configuration with id `_retryError_` does not, and instead it will attempt
to retry the failing message up till five times before giving up (exhausted).
Because this route configuration does not have any error handler assigned, then Camel will use the default error handler.
IMPORTANT: Routes that have a local error handler defined, will always use this error handler,
instead of the error handler from route configurations. A route can only have one error handler.
== Route Configuration in XML
When using XML DSL, then you can code your route configurations in XML files as shown below:
[source,xml]
----
<routeConfiguration id="xmlError">
<onException>
<exception>java.lang.Exception</exception>
<handled><constant>true</constant></handled>
<log message="XML WARN: ${exception.message}"/>
</onException>
</routeConfiguration>
----
And in the XML routes you can assign which configurations to use:
[source,xml]
----
<route routeConfigurationId="xmlError">
<from uri="timer:xml?period=5s"/>
<log message="I am XML"/>
<throwException exceptionType="java.lang.Exception" message="Some kind of XML error"/>
</route>
----
In this example, the route is assigned the `_xmlError_` route configuration by the exact ID.
== Route Configuration in YAML
When using YAML DSL, then you can code your route configurations in YAML files as shown below:
[source,yaml]
----
- route-configuration:
id: "yamlError"
on-exception:
- on-exception:
handled:
constant: "true"
exception:
- "java.lang.Exception"
steps:
- log:
message: "YAML WARN ${exception.message}"
----
And in the YAML routes you can assign which configurations to use:
[source,yaml]
----
- route:
# refer to the route configuration by the id to use for this route
route-configuration-id: "yamlError"
from:
uri: "timer:yaml?period=3s"
steps:
- set-body:
simple: "Timer fired ${header.CamelTimerCounter} times"
- to:
uri: "log:yaml"
parameters:
show-body-type: false
show-exchange-pattern: false
- throw-exception:
exception-type: "java.lang.IllegalArgumentException"
message: "Error from yaml"
----
In this example, the route is assigned the `_yamlError_` route configuration by the exact ID.
== Mixing DSLs
Routes and route configuration are not required to use the same language. For example, you can code
route configurations in Java, and then use XML DSL for the routes, and they would work together.
== Route Configuration in classic Spring XML
When using XML DSL with `camel-spring-xml` then you can code your route configurations in `<routeConfigurationContext>` snippets
in separate XML files as shown below:
[source,xml]
----
<routeConfigurationContext id="myConf" xmlns="http://camel.apache.org/schema/spring">
<routeConfiguration id="xmlError">
<onException>
<exception>java.lang.Exception</exception>
<handled><constant>true</constant></handled>
<log message="XML WARN: ${exception.message}"/>
</onException>
</routeConfiguration>
</routeConfigurationContext>
----
Then from `<camelContext>` you can refer to these XML snippets by their ids:
[source,xml]
----
<camelContext id="myCamel" xmlns="http://camel.apache.org/schema/spring">
<!-- refer to the ID on the context that has the route configurations (see above) -->
<routeConfigurationContextRef ref="myConf"/>
<!-- routes can then assign which configuration to use -->
<route routeConfigurationId="xmlError">
<from uri="timer:xml?period=5s"/>
<log message="I am XML"/>
<throwException exceptionType="java.lang.Exception" message="Some kind of XML error"/>
</route>
</camelContext>
----
In this example, the route is assigned the `_xmlError_` route configuration by the exact ID.
== Packaging route configurations in reusable JARs
You can package common route configurations into JARs which you can then use together with
your Camel applications, by adding the JARs as dependencies to the classpath (such as in Maven pom.xml file).
This allows, for example, to use a _common practice_ among your Camel applications.
== Logging Summary
If you set `startup-summary-level=verbose` then Camel will log for each route which route configurations they have been assigned.
This option can be configured via Java API and also in `application.properties` for Camel on Spring Boot, Quarkus, and Camel standalone via `camel-main`
[source,java]
----
camelContext.setStartupSummaryLevel(StartupSummaryLevel.Verbose);
----
And with Spring Boot:
[source,properties]
----
camel.spring-boot.startup-summary-level = verbose
----
And in Camel Main / Quarkus:
[source,properties]
----
camel.main.startup-summary-level = verbose
----
== Route Precondition
The route configurations can be included or not according to the result of a test expressed in simple language that is evaluated only once during the initialization phase.
In the next example, the route configuration is only included if the parameter `activate` has been set to `true`.
[source,java]
----
routeConfiguration().precondition("{{activate}}")
.onException(IllegalArgumentException.class)
.handled(true)
.log("WARN: ${exception.message}");
----
And the same example using XML DSL:
[source,xml]
----
<routeConfiguration precondition="{{activate}}">
<onException>
<exception>java.lang.IllegalArgumentException</exception>
<handled>
<constant>true</constant>
</handled>
<log message="XML WARN: ${exception.message}"/>
</onException>
</routeConfiguration>
----
And in YAML DSL:
[source,yaml]
----
- route-configuration:
precondition: "{{activate}}"
on-exception:
- on-exception:
exception:
- "java.lang.IllegalArgumentException"
handled:
constant: "true"
steps:
- log:
message: "YAML WARN ${exception.message}"
----
== More Information
See these examples:
- https://github.com/apache/camel-examples/tree/main/routes-configuration[camel-examples/examples/routes-configuration]
- https://github.com/apache/camel-spring-boot-examples/tree/main/routes-configuration[camel-spring-boot-examples/routes-configuration/]