|  | = Route Template | 
|  |  | 
|  | A Route template is as its name implies a template for a route, which is used | 
|  | to create routes from a set of input parameters. In other words, | 
|  | route templates are parameterized routes. | 
|  |  | 
|  | _Route template_ + _input parameters_ => _route_ | 
|  |  | 
|  | From a route template, you can create one or more routes. | 
|  |  | 
|  | == Defining route templates in the DSL | 
|  |  | 
|  | Route templates are to be defined in the DSL (just like routes) as shown in the following: | 
|  |  | 
|  | [tabs] | 
|  | ==== | 
|  | Java:: | 
|  | + | 
|  | [source,java] | 
|  | ---- | 
|  | public class MyRouteTemplates extends RouteBuilder { | 
|  |  | 
|  | @Override | 
|  | public void configure() throws Exception { | 
|  | // create a route template with the given name | 
|  | routeTemplate("myTemplate") | 
|  | // here we define the required input parameters (can have default values) | 
|  | .templateParameter("name") | 
|  | .templateParameter("greeting") | 
|  | .templateParameter("myPeriod", "3s") | 
|  | // here comes the route in the template | 
|  | // notice how we use {{name}} to refer to the template parameters | 
|  | // we can also use {{propertyName}} to refer to property placeholders | 
|  | .from("timer:{{name}}?period={{myPeriod}}") | 
|  | .setBody(simple("{{greeting}} ${body}")) | 
|  | .log("${body}"); | 
|  | } | 
|  | } | 
|  | ---- | 
|  |  | 
|  | Spring XML DSL:: | 
|  | + | 
|  | [source,xml] | 
|  | ---- | 
|  | <camelContext> | 
|  | <routeTemplate id="myTemplate"> | 
|  | <templateParameter name="name"/> | 
|  | <templateParameter name="greeting"/> | 
|  | <templateParameter name="myPeriod" defaultValue="3s"/> | 
|  | <route> | 
|  | <from uri="timer:{{name}}?period={{myPeriod}}"/> | 
|  | <setBody><simple>{{greeting}} ${body}</simple></setBody> | 
|  | <log message="${body}"/> | 
|  | </route> | 
|  | </routeTemplate> | 
|  | </camelContext> | 
|  | ---- | 
|  |  | 
|  | XML DSL:: | 
|  | + | 
|  | [source,xml] | 
|  | ---- | 
|  | <routeTemplates xmlns="http://camel.apache.org/schema/spring"> | 
|  | <routeTemplate id="myTemplate"> | 
|  | <templateParameter name="name"/> | 
|  | <templateParameter name="greeting"/> | 
|  | <templateParameter name="myPeriod" defaultValue="3s"/> | 
|  | <route> | 
|  | <from uri="timer:{{name}}?period={{myPeriod}}"/> | 
|  | <setBody><simple>{{greeting}} ${body}</simple></setBody> | 
|  | <log message="${body}"/> | 
|  | </route> | 
|  | </routeTemplate> | 
|  | </routeTemplates> | 
|  | ---- | 
|  | ==== | 
|  |  | 
|  | In the examples above, there was one route template, but you can define as many as you want. | 
|  | Each template must have a unique id. The template parameters are used for defining the parameters | 
|  | the template accepts. As you can see, there are three parameters: `_name_`, `_greeting_`, and `_myPeriod_`. The first two | 
|  | parameters are mandatory, whereas `_myPeriod_` is optional as it has a default value of 3s. | 
|  |  | 
|  | The template parameters are then used in the route as regular property placeholders with the `{{ }}` syntax. | 
|  | Notice how we use `{\{name}}` and `{\{greeting}}` in the timer endpoint and the simple language. | 
|  |  | 
|  | The route can, of course, use regular property placeholders as well. | 
|  | Now imagine there was a property placeholder with the name greeting: | 
|  |  | 
|  | [source,properties] | 
|  | ---- | 
|  | greeting = Davs | 
|  | ---- | 
|  |  | 
|  | Then Camel would normally have used this value `Davs` when creating the route. However, as the route template | 
|  | has defined a template parameter with the same name `greeting` then a value must be provided when | 
|  | creating routes from the template. | 
|  |  | 
|  | Template parameters take precedence over regular property placeholders. | 
|  |  | 
|  | == Creating a route from a route template | 
|  |  | 
|  | To create routes from route templates, then you should use `org.apache.camel.builder.TemplatedRouteBuilder`. | 
|  |  | 
|  | In the following code snippet, you can see how this is done with the builder: | 
|  |  | 
|  | [tabs] | 
|  | ==== | 
|  | Java builder:: | 
|  | + | 
|  | [source,java] | 
|  | ---- | 
|  | // create two routes from the template | 
|  | TemplatedRouteBuilder.builder(context, "myTemplate") | 
|  | .parameter("name", "one") | 
|  | .parameter("greeting", "Hello") | 
|  | .add(); | 
|  |  | 
|  | TemplatedRouteBuilder.builder(context, "myTemplate") | 
|  | .parameter("name", "two") | 
|  | .parameter("greeting", "Bonjour") | 
|  | .parameter("myPeriod", "5s") | 
|  | .add(); | 
|  | ---- | 
|  |  | 
|  | Java DSL:: | 
|  | + | 
|  | [source,java] | 
|  | ---- | 
|  | templatedRoute("myTemplate") | 
|  | .parameter("name", "one") | 
|  | .parameter("greeting", "Hello"); | 
|  | templatedRoute("myTemplate") | 
|  | .parameter("name", "two") | 
|  | .parameter("greeting", "Bonjour") | 
|  | .parameter("myPeriod", "5s"); | 
|  | ---- | 
|  |  | 
|  | Spring XML DSL:: | 
|  | + | 
|  | [source,xml] | 
|  | ---- | 
|  | <camelContext> | 
|  | <templatedRoute routeTemplateRef="myTemplate"> | 
|  | <parameter name="name" value="one"/> | 
|  | <parameter name="greeting" value="Hello"/> | 
|  | </templatedRoute> | 
|  | <templatedRoute routeTemplateRef="myTemplate"> | 
|  | <parameter name="name" value="two"/> | 
|  | <parameter name="greeting" value="Bonjour"/> | 
|  | <parameter name="myPeriod" value="5s"/> | 
|  | </templatedRoute> | 
|  | </camelContext> | 
|  | ---- | 
|  |  | 
|  | XML DSL:: | 
|  | + | 
|  | [source,xml] | 
|  | ---- | 
|  | <templatedRoutes xmlns="http://camel.apache.org/schema/spring"> | 
|  | <templatedRoute routeTemplateRef="myTemplate"> | 
|  | <parameter name="name" value="one"/> | 
|  | <parameter name="greeting" value="Hello"/> | 
|  | </templatedRoute> | 
|  | <templatedRoute routeTemplateRef="myTemplate"> | 
|  | <parameter name="name" value="two"/> | 
|  | <parameter name="greeting" value="Bonjour"/> | 
|  | <parameter name="myPeriod" value="5s"/> | 
|  | </templatedRoute> | 
|  | </templatedRoutes> | 
|  | ---- | 
|  |  | 
|  | YAML DSL:: | 
|  | + | 
|  | [source,yaml] | 
|  | ---- | 
|  | - templatedRoute: | 
|  | routeTemplateRef: "myTemplate" | 
|  | parameters: | 
|  | - name: "name" | 
|  | value: "one" | 
|  | - name: "greeting" | 
|  | value: "Hello" | 
|  | - templatedRoute: | 
|  | routeTemplateRef: "myTemplate" | 
|  | parameters: | 
|  | - name: "name" | 
|  | value: "two" | 
|  | - name: "greeting" | 
|  | value: "Bonjour" | 
|  | - name: "myPeriod" | 
|  | value: "5s" | 
|  | ---- | 
|  | ==== | 
|  |  | 
|  | The returned value from `add` is the route id of the new route that was added. | 
|  | However `null` is returned if the route is not yet created and added, which can happen if `CamelContext` is | 
|  | not started yet. | 
|  |  | 
|  | If no route id is provided, then Camel will auto assign a route id. In the example above then Camel would | 
|  | assign route ids such as `route1`, `route2` to these routes. | 
|  |  | 
|  | If you want to specify a route id, then use `routeId` as follows, where the id is set to myCoolRoute: | 
|  |  | 
|  | [tabs] | 
|  | ==== | 
|  | Java builder:: | 
|  | + | 
|  | [source,java] | 
|  | ---- | 
|  | TemplatedRouteBuilder.builder(context, "myTemplate") | 
|  | .routeId("myCoolRoute") | 
|  | .parameter("name", "one") | 
|  | .parameter("greeting", "hello") | 
|  | .parameter("myPeriod", "5s") | 
|  | .add(); | 
|  | ---- | 
|  |  | 
|  | Java DSL:: | 
|  | + | 
|  | [source,java] | 
|  | ---- | 
|  | templatedRoute("myTemplate") | 
|  | .routeId("myCoolRoute") | 
|  | .parameter("name", "one") | 
|  | .parameter("greeting", "hello") | 
|  | .parameter("myPeriod", "5s"); | 
|  | ---- | 
|  |  | 
|  | Spring XML DSL:: | 
|  | + | 
|  | [source,xml] | 
|  | ---- | 
|  | <camelContext> | 
|  | <templatedRoute routeTemplateRef="myTemplate" routeId="myCoolRoute"> | 
|  | <parameter name="name" value="one"/> | 
|  | <parameter name="greeting" value="hello"/> | 
|  | <parameter name="myPeriod" value="5s"/> | 
|  | </templatedRoute> | 
|  | </camelContext> | 
|  | ---- | 
|  |  | 
|  | XML DSL:: | 
|  | + | 
|  | [source,xml] | 
|  | ---- | 
|  | <templatedRoutes xmlns="http://camel.apache.org/schema/spring"> | 
|  | <templatedRoute routeTemplateRef="myTemplate" routeId="myCoolRoute"> | 
|  | <parameter name="name" value="one"/> | 
|  | <parameter name="greeting" value="hello"/> | 
|  | <parameter name="myPeriod" value="5s"/> | 
|  | </templatedRoute> | 
|  | </templatedRoutes> | 
|  | ---- | 
|  |  | 
|  | YAML DSL:: | 
|  | + | 
|  | [source,yaml] | 
|  | ---- | 
|  | - templatedRoute: | 
|  | routeTemplateRef: "myTemplate" | 
|  | route-id: "myCoolRoute" | 
|  | parameters: | 
|  | - name: "name" | 
|  | value: "one" | 
|  | - name: "greeting" | 
|  | value: "hello" | 
|  | - name: "myPeriod" | 
|  | value: "5s" | 
|  | ---- | 
|  | ==== | 
|  |  | 
|  | === Using template parameters with Java DSL simple builder | 
|  |  | 
|  | When using Java DSL and simple language, then beware that you should | 
|  | not use the _simple fluent builder_ when defining the simple expressions/predicates. | 
|  |  | 
|  | For example, given the following route template in Java DSL: | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | public class MyRouteTemplates extends RouteBuilder { | 
|  |  | 
|  | @Override | 
|  | public void configure() throws Exception { | 
|  | routeTemplate("myTemplate") | 
|  | .templateParameter("name") | 
|  | .templateParameter("color") | 
|  | .from("direct:{{name}}") | 
|  | .choice() | 
|  | .when(simple("{{color}}").isEqualTo("red")) | 
|  | .to("direct:red") | 
|  | .otherwise() | 
|  | .to("color:other") | 
|  | .end(); | 
|  | } | 
|  | } | 
|  | ---- | 
|  |  | 
|  | Then notice how the simple predicate is using _simple fluent builder_ `simple("{\{color}}").isEqualTo("red")`. | 
|  | This is **not supported** with route templates and would not work when creating multiple routes from the template. | 
|  |  | 
|  | Instead, the simple expression should be a literal String value _only_ as follows: | 
|  | ---- | 
|  | .when(simple("'{{color}}' == 'red'") | 
|  | ---- | 
|  |  | 
|  | === Using hardcoded node IDs in route templates | 
|  |  | 
|  | If route templates contain hardcoded node IDs, then routes created from templates will use the same IDs. | 
|  | Therefore, if two or more routes are created from the same template, you will have _duplicate id detected_ error. | 
|  |  | 
|  | Given the route template below, then it has hardcoded ID (`_new-order_`) in node calling the http services. | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | public class MyRouteTemplates extends RouteBuilder { | 
|  |  | 
|  | @Override | 
|  | public void configure() throws Exception { | 
|  | routeTemplate("orderTemplate") | 
|  | .templateParameter("queue") | 
|  | .from("jms:{{queue}}") | 
|  | .to("http:orderserver.acme.com/neworder").id("new-order") | 
|  | .log("Processing order"); | 
|  | } | 
|  | } | 
|  | ---- | 
|  |  | 
|  | When creating routes from templates, you can then provide a _prefix_ which is used for all node IDs. | 
|  | This allows to create 2 or more routes without _duplicate id_ errors. | 
|  |  | 
|  | For example in the following, we create a new route `_myCoolRoute_` from the `_myTemplate_` template, and | 
|  | use a prefix of `_web_`. | 
|  |  | 
|  | And in Java DSL | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | templatedRoute("orderTemplate") | 
|  | .routeId("webOrder") | 
|  | .prefixId("web") | 
|  | .parameter("queue", "order.web"); | 
|  | ---- | 
|  |  | 
|  | Then we can create a 2nd route: | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | templatedRoute("orderTemplate") | 
|  | .routeId("ftpOrder") | 
|  | .prefixId("ftp") | 
|  | .parameter("queue", "order.ftp"); | 
|  | ---- | 
|  |  | 
|  | And in Spring XML DSL: | 
|  |  | 
|  | [source,xml] | 
|  | ---- | 
|  | <camelContext> | 
|  | <templatedRoute routeTemplateRef="orderTemplate" routeId="webOrder" prefixId="web"> | 
|  | <parameter name="queue" value="web"/> | 
|  | </templatedRoute> | 
|  | </camelContext> | 
|  | ---- | 
|  |  | 
|  | And in XML DSL: | 
|  |  | 
|  | [source,xml] | 
|  | ---- | 
|  | <templatedRoutes xmlns="http://camel.apache.org/schema/spring"> | 
|  | <templatedRoute routeTemplateRef="orderTemplate" routeId="webOrder" prefixId="web"> | 
|  | <parameter name="queue" value="web"/> | 
|  | </templatedRoute> | 
|  | </templatedRoutes> | 
|  | ---- | 
|  |  | 
|  | And in YAML DSL: | 
|  |  | 
|  | [source,yaml] | 
|  | ---- | 
|  | - templatedRoute: | 
|  | routeTemplateRef: "orderTemplate" | 
|  | route-id: "webOrder" | 
|  | prefix-id: "web" | 
|  | parameters: | 
|  | - name: "queue" | 
|  | value: "web" | 
|  | ---- | 
|  |  | 
|  | == Binding beans to route template | 
|  |  | 
|  | The route template allows binding beans that are locally scoped and only used as part of creating routes from the template. | 
|  | This allows using the same template to create multiple routes, where beans are local (private) for each created route. | 
|  |  | 
|  | For example, given the following route template where we use `templateBean` to set up the local bean as shown: | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | routeTemplate("s3template") | 
|  | .templateParameter("region") | 
|  | .templateParameter("bucket") | 
|  | .templateBean("myClient", S3Client.class, rtc -> | 
|  | S3Client.builder().region(rtc.getProperty("region", Region.class)).build(); | 
|  | ) | 
|  | .from("direct:s3-store") | 
|  | // must refer to the bean with {{myClient}} | 
|  | .to("aws2-s3:{{bucket}}?amazonS3Client=#{{myClient}}") | 
|  | ---- | 
|  |  | 
|  | The template has two parameters to specify the AWS region and the S3 bucket. To connect to S3 | 
|  | then a `software.amazon.awssdk.services.s3.S3Client` bean is necessary. | 
|  |  | 
|  | To create this bean, we specify this with the `templateBean` DSL where we specify the bean id as `myClient`. | 
|  | The type of the bean can be specified (`S3Client.class`), however, it is optional | 
|  | (can be used if you need to let beans be discovered by type and not by name). | 
|  |  | 
|  | This ensures that the code creating the bean is executed later (when Camel is creating a route from the template), | 
|  | then the code must be specified as a _supplier_. Because we want during creation of the bean access to template parameters, | 
|  | we use a Camel `BeanSupplier` which gives access to `RouteTemplateContext` that is the `_rtc_` variable in the code above. | 
|  |  | 
|  | IMPORTANT: The local bean with id `myClient` *must* be referred to using Camel's property placeholder syntax, eg `{\{myClient}}` | 
|  | in the route template, as shown above with the _to_ endpoint. This is because the local | 
|  | bean must be made unique and Camel will internally re-assign the bean id to use a unique id instead of `myClient`. And this is done with the help | 
|  | of the property placeholder functionality. | 
|  |  | 
|  | If multiple routes are created from this template, then each of the created routes have their own | 
|  | `S3Client` bean created. | 
|  |  | 
|  | === Binding beans to route templates from template builder | 
|  |  | 
|  | The `TemplatedRouteBuilder` also allows to bind local beans (which allows specifying those beans) when | 
|  | creating routes from existing templates. | 
|  |  | 
|  | Suppose the route template below is defined in XML: | 
|  | [source,xml] | 
|  | ---- | 
|  | <camelContext> | 
|  | <routeTemplate id="s3template"> | 
|  | <templateParameter name="region"/> | 
|  | <templateParameter name="bucket"/> | 
|  | <route> | 
|  | <from uri="direct:s3-store"/> | 
|  | <to uri="aws2-s3:{{bucket}}?amazonS3Client=#{{myClient}}"/> | 
|  | </route> | 
|  | </routeTemplate> | 
|  | </camelContext> | 
|  | ---- | 
|  |  | 
|  | The template has no bean bindings for `#{\{myClient}}` which would be required for creating the template. | 
|  |  | 
|  | When creating routes form the template via `TemplatedRouteBuilder` then you can provide the bean binding | 
|  | if you desire the bean to be locally scoped (not shared with others): | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | TemplatedRouteBuilder.builder(context, "s3template") | 
|  | .parameter("region", "US-EAST-1") | 
|  | .parameter("bucket", "myBucket") | 
|  | .bean("myClient", S3Client.class, | 
|  | S3Client.builder() | 
|  | .region(rtc.getProperty("region", Region.class)) | 
|  | .build()) | 
|  | .routeId("mys3route") | 
|  | .add(); | 
|  | ---- | 
|  |  | 
|  | As you can see the binding is similar to when using `templateBean` directly in the route template. | 
|  |  | 
|  | And in Java DSL: | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | templatedRoute("s3template") | 
|  | .parameter("region", "US-EAST-1") | 
|  | .parameter("bucket", "myBucket") | 
|  | .bean("myClient", S3Client.class, | 
|  | rtc -> S3Client.builder() // <1> | 
|  | .region(rtc.getProperty("region", Region.class)) | 
|  | .build()) | 
|  | .routeId("mys3route"); | 
|  | ---- | 
|  | <1> Note that the third parameter of the `bean` method is not directly the bean but rather a factory method that will be used to create the bean, here we use a lambda expression as factory method. | 
|  |  | 
|  | And in XML DSL: | 
|  |  | 
|  | [source,xml] | 
|  | ---- | 
|  | <templatedRoute routeTemplateRef="s3template" routeId="mys3route"> | 
|  | <parameter name="region" value="US-EAST-1"/> | 
|  | <parameter name="bucket" value="myBucket"/> | 
|  | <bean name="myClient" type="software.amazon.awssdk.services.s3.S3Client" | 
|  | scriptLanguage="groovy"> <!--1--> | 
|  | <script> | 
|  | import software.amazon.awssdk.services.s3.S3Client | 
|  | S3Client.builder() | 
|  | .region(rtc.getProperty("region", Region.class)) | 
|  | .build() | 
|  | </script> | 
|  | </bean> | 
|  | </templatedRoute> | 
|  | ---- | 
|  | <1> For non-Java DSL, in case of a complex bean factory, you can still rely on a language like `groovy` to define your bean factory inside a `script` element. | 
|  |  | 
|  | And in YAML DSL: | 
|  |  | 
|  | [source,yaml] | 
|  | ---- | 
|  | - templatedRoute: | 
|  | routeTemplateRef: "s3template" | 
|  | routeId: "mys3route" | 
|  | parameters: | 
|  | - name: "region" | 
|  | value: "US-EAST-1" | 
|  | - name: "bucket" | 
|  | value: "myBucket" | 
|  | beans: | 
|  | - name: "myClient" | 
|  | type: "software.amazon.awssdk.services.s3.S3Client" | 
|  | scriptLanguage: "groovy" | 
|  | script: | # <1> | 
|  | import software.amazon.awssdk.services.s3.S3Client | 
|  | S3Client.builder() | 
|  | .region(rtc.getProperty("region", Region.class)) | 
|  | .build() | 
|  | ---- | 
|  | <1> For non-Java DSL, in case of a complex bean factory, you can still rely on a language like `groovy` to define your bean factory as value of the `script` key. | 
|  |  | 
|  | Instead of binding the beans from the template builder, you could also create the bean outside the template, | 
|  | and bind it by reference. | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  |  | 
|  | final S3Client myClient = S3Client.builder().region(Region.US_EAST_1).build(); | 
|  |  | 
|  | TemplatedRouteBuilder.builder(context, "s3template") | 
|  | .parameter("region", Region.US_EAST_1) | 
|  | .parameter("bucket", "myBucket") | 
|  | .bean("myClient", myClient) | 
|  | .routeId("mys3route") | 
|  | .add(); | 
|  | ---- | 
|  |  | 
|  | And in Java DSL: | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | templatedRoute("s3template") | 
|  | .parameter("region", "US-EAST-1") | 
|  | .parameter("bucket", "myBucket") | 
|  | .bean("myClient", S3Client.class, rtc -> myClient) | 
|  | .routeId("mys3route"); | 
|  | ---- | 
|  |  | 
|  | You should prefer to create the local beans directly from within the template (if possible) because this | 
|  | ensures the route template has this out of the box. Otherwise, the bean must be created or provided every time | 
|  | a new route is created from the route template. However, the latter gives freedom to create the bean in any other custom way. | 
|  |  | 
|  | === Binding beans to route templates using bean types | 
|  |  | 
|  | You can create a local bean by referring to a fully qualified class name which Camel will use to create | 
|  | a new local bean instance. When using this, the created bean is created via default constructor of the class. | 
|  |  | 
|  | The bean instance can be configured with properties via getter/setter style. | 
|  | The previous example with creating the AWS S3Client would not support this kind as this uses _fluent builder_ pattern (not getter/setter). | 
|  |  | 
|  | TIP: In *Camel 4.6* onwards, you can also use constructor arguments for beans | 
|  |  | 
|  | So suppose we have a class as follows: | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | public class MyBar { | 
|  | private String name; | 
|  | private String address; | 
|  |  | 
|  | // getter/setter omitted | 
|  |  | 
|  | public String location() { | 
|  | return "The bar " + name + " is located at " + address; | 
|  | } | 
|  | } | 
|  | ---- | 
|  |  | 
|  | Then we can use the `MyBar` class as a local bean in a route template as follows: | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | routeTemplate("barTemplate") | 
|  | .templateParameter("bar") | 
|  | .templateParameter("street") | 
|  | .templateBean("myBar") | 
|  | .typeClass("com.foo.MyBar") | 
|  | .property("name", "{{bar}}") | 
|  | .property("address", "{{street}}") | 
|  | .end() | 
|  | .from("direct:going-out") | 
|  | .to("bean:{{myBar}}") | 
|  | ---- | 
|  |  | 
|  | With Java DSL, you can also refer to the bean class using type safe way: | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | .templateBean("myBar") | 
|  | .typeClass(MyBar.class) | 
|  | .property("name", "{{bar}}") | 
|  | .property("address", "{{street}}") | 
|  | .end() | 
|  | ---- | 
|  |  | 
|  | In XML DSL you would do: | 
|  |  | 
|  | [source,xml] | 
|  | ---- | 
|  | <camelContext xmlns="http://camel.apache.org/schema/spring"> | 
|  | <routeTemplate id="myBar"> | 
|  | <templateParameter name="bar"/> | 
|  | <templateParameter name="street"/> | 
|  | <templateBean name="myBean" type="#class:com.foo.MyBar"> | 
|  | <properties> | 
|  | <property key="name" value="{{bar}}"/> | 
|  | <property key="address" value="{{street}}"/> | 
|  | </properties> | 
|  | </templateBean> | 
|  | <route> | 
|  | <from uri="direct:going-out"/> | 
|  | <to uri="bean:{{myBar}}"/> | 
|  | </route> | 
|  | </routeTemplate> | 
|  | </camelContext> | 
|  | ---- | 
|  |  | 
|  | === Binding beans to route templates using scripting languages | 
|  |  | 
|  | You can use scripting languages like groovy, java, mvel to create the bean. | 
|  | This allows defining route templates with the scripting language built-in (such as groovy). | 
|  |  | 
|  | For example, creating the AWS S3 client can be done as shown in Java (with inlined groovy code): | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | routeTemplate("s3template") | 
|  | .templateParameter("region") | 
|  | .templateParameter("bucket") | 
|  | .templateBean("myClient", "groovy", | 
|  | "software.amazon.awssdk.services.s3.S3Client.S3Client.builder() | 
|  | .region(rtc.getProperty("region", Region.class)) | 
|  | .build()" | 
|  | ) | 
|  | .from("direct:s3-store") | 
|  | // must refer to the bean with {{myClient}} | 
|  | .to("aws2-s3:{{bucket}}?amazonS3Client=#{{myClient}}") | 
|  | ---- | 
|  |  | 
|  | The groovy code can be externalized into a file on the classpath or file system, by using `resource:` as prefix, such as: | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | routeTemplate("s3template") | 
|  | .templateParameter("region") | 
|  | .templateParameter("bucket") | 
|  | .templateBean("myClient", "groovy", "resource:classpath:s3bean.groovy") | 
|  | .from("direct:s3-store") | 
|  | // must refer to the bean with {{myClient}} | 
|  | .to("aws2-s3:{{bucket}}?amazonS3Client=#{{myClient}}") | 
|  | ---- | 
|  |  | 
|  | Then create the file `s3bean.groovy` in the classpath root: | 
|  |  | 
|  | [source,groovy] | 
|  | ---- | 
|  | import software.amazon.awssdk.services.s3.S3Client | 
|  | S3Client.builder() | 
|  | .region(rtc.getProperty("region", Region.class)) | 
|  | .build() | 
|  | ---- | 
|  |  | 
|  | The route template in XML DSL can then also use groovy language to create the bean as follows: | 
|  |  | 
|  | [source,xml] | 
|  | ---- | 
|  | <camelContext> | 
|  | <routeTemplate id="s3template"> | 
|  | <templateParameter name="region"/> | 
|  | <templateParameter name="bucket"/> | 
|  | <templateBean name="myClient" type="groovy"> | 
|  | <script> | 
|  | import software.amazon.awssdk.services.s3.S3Client | 
|  | S3Client.builder() | 
|  | .region(rtc.getProperty("region", Region.class)) | 
|  | .build() | 
|  | </script> | 
|  | </templateBean> | 
|  | <route> | 
|  | <from uri="direct:s3-store"/> | 
|  | <to uri="aws2-s3:{{bucket}}?amazonS3Client=#{{myClient}}"/> | 
|  | </route> | 
|  | </routeTemplate> | 
|  | </camelContext> | 
|  | ---- | 
|  |  | 
|  | Notice how the groovy code can be inlined directly in the route template in XML also. Of course, you can also externalize | 
|  | the bean creation code to an external file, by using `resource:` as prefix: | 
|  |  | 
|  | [source,xml] | 
|  | ---- | 
|  | <camelContext> | 
|  | <routeTemplate id="s3template"> | 
|  | <templateParameter name="region"/> | 
|  | <templateParameter name="bucket"/> | 
|  | <templateBean name="myClient" type="groovy"> | 
|  | <script>resource:classpath:s3bean.groovy</script> | 
|  | </templateBean> | 
|  | <route> | 
|  | <from uri="direct:s3-store"/> | 
|  | <to uri="aws2-s3:{{bucket}}?amazonS3Client=#{{myClient}}"/> | 
|  | </route> | 
|  | </routeTemplate> | 
|  | </camelContext> | 
|  | ---- | 
|  |  | 
|  | The languages supported are: | 
|  |  | 
|  | [width="100%",cols="2s,8",options="header"] | 
|  | |=== | 
|  | | Type | Description | 
|  | | bean | Calling a method on a Java class to create the bean. | 
|  | | groovy | Using a groovy script to create the bean. | 
|  | | java | Java code which is runtime compiled (using jOOR library) to create the bean. | 
|  | | mvel | To use a Mvel template script to create the bean. | 
|  | | ognl | To use OGNL template script to create the bean. | 
|  | | _name_ | To use a third-party language by the given `_name_` to create the bean. | 
|  | |=== | 
|  |  | 
|  | Camel will bind `RouteTemplateContext` as the root object with name `rtc` when evaluating the script. | 
|  | This means you can get access to all the information from `RouteTemplateContext` and `CamelContext` via `rtc`. | 
|  |  | 
|  | This is what we have done in the scripts in the previous examples where we get hold of a template parameter with: | 
|  |  | 
|  | [source,groovy] | 
|  | ---- | 
|  | rtc.getProperty('region', String.class) | 
|  | ---- | 
|  |  | 
|  | To get access to `CamelContext` you can do: | 
|  |  | 
|  | [source,groovy] | 
|  | ---- | 
|  | var cn = rtc.getCamelContext().getName() | 
|  | ---- | 
|  |  | 
|  | The most powerful languages to use are groovy and java. The other languages are limited in flexibility | 
|  | as they are not complete programming languages, but are more suited for templating needs. | 
|  |  | 
|  | It is recommended to either use groovy or java, if creating the local bean requires coding, | 
|  | and the route templates are not defined using Java code. | 
|  |  | 
|  | The bean language can be used when creating the local bean from an existing Java method (static or not-static method), | 
|  | and the route templates are not defined using Java code. | 
|  |  | 
|  | For example suppose there is a class named `com.foo.MyAwsHelper` that has a method called `createS3Client` | 
|  | then you can call this method from the route template in XML DSL: | 
|  |  | 
|  | [source,xml] | 
|  | ---- | 
|  | <camelContext> | 
|  | <routeTemplate id="s3template"> | 
|  | <templateParameter name="region"/> | 
|  | <templateParameter name="bucket"/> | 
|  | <templateBean name="myClient" type="bean"> | 
|  | <script>com.foo.MyAwsHelper?method=createS3Client</script> | 
|  | </templateBean> | 
|  | <route> | 
|  | <from uri="direct:s3-store"/> | 
|  | <to uri="aws2-s3:{{bucket}}?amazonS3Client=#{{myClient}}"/> | 
|  | </route> | 
|  | </routeTemplate> | 
|  | </camelContext> | 
|  | ---- | 
|  |  | 
|  | The method signature of createS3Client must then have one parameter for the `RouteTemplateContext` as shown: | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | public static S3Client createS3Client(RouteTemplateContext rtc) { | 
|  | return S3Client.builder() | 
|  | .region(rtc.getProperty("region", Region.class)) | 
|  | .build(); | 
|  | } | 
|  | ---- | 
|  |  | 
|  | If you are using pure Java code (both template and creating local bean), | 
|  | then you can create the local bean using Java lambda style as previously documented. | 
|  |  | 
|  | ==== Configuring the type of the created bean | 
|  |  | 
|  | The `type` must be set to define what FQN class the created bean. | 
|  |  | 
|  | [tabs] | 
|  | ==== | 
|  | XML:: | 
|  | + | 
|  | [source,xml] | 
|  | ---- | 
|  | <camelContext> | 
|  | <routeTemplate id="s3template"> | 
|  | <templateParameter name="region"/> | 
|  | <templateParameter name="bucket"/> | 
|  | <templateBean name="myClient" scriptLanguage="bean" type="software.amazon.awssdk.services.s3.S3Client"> | 
|  | <script>com.foo.MyAwsHelper?method=createS3Client</script> | 
|  | </templateBean> | 
|  | <route> | 
|  | <from uri="direct:s3-store"/> | 
|  | <to uri="aws2-s3:{{bucket}}?amazonS3Client=#{{myClient}}"/> | 
|  | </route> | 
|  | </routeTemplate> | 
|  | </camelContext> | 
|  | ---- | 
|  |  | 
|  | Java:: | 
|  | + | 
|  | [source,java] | 
|  | ---- | 
|  | routeTemplate("s3template") | 
|  | .templateParameter("region") | 
|  | .templateParameter("bucket") | 
|  | .templateBean("myClient", S3Client.class, "bean", "com.foo.MyAwsHelper?method=createS3Client") | 
|  | .from("direct:s3-store") | 
|  | // must refer to the bean with {{myClient}} | 
|  | .to("aws2-s3:{{bucket}}?amazonS3Client=#{{myClient}}") | 
|  | ---- | 
|  | ==== | 
|  |  | 
|  | == Configuring route templates when creating route | 
|  |  | 
|  | There may be some special situations where you want to be able to do some custom configuration/code when | 
|  | a route is about to be created from a route template. To support this you can use the `configure` in the route template DSL | 
|  | where you can specify the code to execute as show: | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | routeTemplate("myTemplate") | 
|  | .templateParameter("myTopic") | 
|  | .configure((RouteTemplateContext rtc) -> | 
|  | // do some custom code here | 
|  | ) | 
|  | .from("direct:to-topic") | 
|  | .to("kafka:{{myTopic}}"); | 
|  | ---- | 
|  |  | 
|  | == JMX management | 
|  |  | 
|  | The route templates can be dumped as XML from the `ManagedCamelContextMBean` MBean via the `dumpRouteTemplatesAsXml` operation. | 
|  |  | 
|  | == Creating routes from a properties file | 
|  |  | 
|  | When using `camel-main` you can specify the parameters for route templates in `application.properties` file. | 
|  |  | 
|  | For example, given the route template below (from a `RouteBuilder` class): | 
|  |  | 
|  | [source,java] | 
|  | ---- | 
|  | routeTemplate("mytemplate") | 
|  | .templateParameter("input") | 
|  | .templateParameter("result") | 
|  | .from("direct:{{input}}") | 
|  | .to("mock:{{result}}"); | 
|  | ---- | 
|  |  | 
|  | Then we can create two routes from this template by configuring the values in the `application.properties` file: | 
|  |  | 
|  | [source,properties] | 
|  | ---- | 
|  | camel.route-template[0].template-id=mytemplate | 
|  | camel.route-template[0].input=foo | 
|  | camel.route-template[0].result=cheese | 
|  |  | 
|  | camel.route-template[1].template-id=mytemplate | 
|  | camel.route-template[1].input=bar | 
|  | camel.route-template[1].result=cheese | 
|  | ---- | 
|  |  | 
|  | == Creating routes from custom sources of template parameters | 
|  |  | 
|  | The SPI interface `org.apache.camel.spi.RouteTemplateParameterSource` can be used to implement custom sources that | 
|  | are used during startup of Camel to create routes via the templates with parameters from the custom source(s). | 
|  |  | 
|  | For example, a custom source can be implemented to read parameters from a shared database that Camel uses during startup | 
|  | to create routes. | 
|  | This allows externalizing these parameters and as well to easily add more routes with varying parameters. | 
|  |  | 
|  | To let Camel discover custom sources, then register the source into the Camel registry. | 
|  |  | 
|  | == See Also | 
|  |  | 
|  | See the example https://github.com/apache/camel-examples/tree/main/routetemplate[camel-examples/examples/routetemplate/]. |