This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit a897a114d7f4cffe08780ecad38eb7d37dd41b2b Author: Claus Ibsen <[email protected]> AuthorDate: Wed Feb 25 14:09:09 2026 +0100 CAMEL-16861: Update docs --- .../ROOT/pages/using-propertyplaceholder.adoc | 365 +++++++++++++++++---- 1 file changed, 309 insertions(+), 56 deletions(-) diff --git a/docs/user-manual/modules/ROOT/pages/using-propertyplaceholder.adoc b/docs/user-manual/modules/ROOT/pages/using-propertyplaceholder.adoc index ae7b806d6995..051d5d0aed27 100644 --- a/docs/user-manual/modules/ROOT/pages/using-propertyplaceholder.adoc +++ b/docs/user-manual/modules/ROOT/pages/using-propertyplaceholder.adoc @@ -18,7 +18,6 @@ from the core, which is responsible for handling and resolving the property plac See the xref:components::properties-component.adoc[Properties] documentation for how to configure Camel to known from which location(a) to load properties. - == Property placeholder syntax The value of a Camel property can be obtained by specifying its key name @@ -33,10 +32,54 @@ For example: where `file.uri` is the property key. -Property placeholders can be used to specify parts, or all, of an -endpoint's URI by embedding one or more placeholders in the URI's string +Property placeholders can for example be used to specify parts, or all, of an +xref:uris.adoc[endpoint uri] by embedding one or more placeholders in the URI's string definition. +For example as shown in the route below: + +[tabs] +==== + +Java:: ++ +[source,java] +---- +from("{{file.uri}}") + .to("kafka:{{orderTopic}}"); +---- + +XML:: ++ +[source,xml] +---- + <route> + <from uri="{{file.uri}}"/> + <to uri="kafka:{{orderTopic}}"/> + </route> +---- + +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: "{{file.uri}}" + steps: + - to: + uri: "kafka:{{orderTopic}}" +---- +==== + +Then the placeholder can be declared in `application.properties`: + +[source,properties] +---- +file.uri = file:/var/orders/inbox?recursive=true +---- + + === Using property placeholder with default value You can specify a default value to use if a @@ -52,7 +95,7 @@ In this case the default value is `/some/path`. === Using optional property placeholders Camel's elaborate property placeholder feature supports optional placeholders, -which is defined with the `?` (question mark) as prefix in the key name, as shown: +which is declared with the `?` (question mark) as prefix in the key name, as shown: [source,text] ---- @@ -60,7 +103,7 @@ which is defined with the `?` (question mark) as prefix in the key name, as show ---- If a value for the key exists then the value is used, however if the key does not exist, -then Camel understands this, such as when used in xref:endpoint.adoc[Endpoints]: +then Camel understands how to handle this. For example when used in xref:endpoint.adoc[Endpoints]: [source,text] ---- @@ -68,35 +111,80 @@ file:foo?bufferSize={{?myBufferSize}} ---- Then the `bufferSize` option will only be configured in the endpoint, if a placeholder exists. -Otherwise the option will not be set on the endpoint, meaning the endpoint would be _restructued_ as: +Otherwise, the option will not be set on the endpoint, meaning the endpoint would be _restructured_ as: [source,text] ---- file:foo ---- -Then the option `bufferSize` is not in specified at all, and this would allow Camel to -use the standard default value for `bufferSize` if any exists. +Then the option `bufferSize` is not declared, and this would allow Camel to +use the standard default value for `bufferSize` (if any exists). === Reverse a boolean value If a property placeholder is a boolean value, then it is possible to negate (reverse) the value by using `!` as prefix in the key. +For example given we have this property: + [source,properties] ---- integration.ftpEnabled=true ---- +Then this can be used to control which routes should be auto started. + +[tabs] +==== + +Java:: ++ [source,java] ---- from("ftp:....").autoStartup("{{integration.ftpEnabled}}") - .to("kafka:cheese") + .to("kafka:cheese"); from("jms:....").autoStartup("{{!integration.ftpEnabled}}") - .to("kafka:cheese") + .to("kafka:cheese"); ---- -In the example above then the FTP route or the JMS route should only be started. So if the FTP is enabled then JMS should be disable, and vise-versa. +XML:: ++ +[source,xml] +---- +<route autoStartup="{{integration.ftpEnabled}}"> + <from uri="ftp:...."/> + <to uri="kafka:cheese"/> +</route> + +<route autoStartup="{{!integration.ftpEnabled}}"> + <from uri="jms:...."/> + <to uri="kafka:cheese"/> +</route> +---- + +YAML:: ++ +[source,yaml] +---- +- route: + autoStartup: "{{integration.ftpEnabled}}" + from: + uri: ftp:.... + steps: + - to: + uri: kafka:cheese +- route: + autoStartup: "{{!integration.ftpEnabled}}" + from: + uri: jms:.... + steps: + - to: + uri: kafka:cheese +---- +==== + +In the example above then the FTP route or the JMS route should only be started. So if the FTP is enabled then JMS should be disabled, and vice versa. We can do this be negating the `autoStartup` in the JMS route, by using `!integration.ftpEnabled` as the key. @@ -110,16 +198,19 @@ cool.end = mock:result where = cheese ---- -And in Java DSL: +[tabs] +==== +Java:: ++ [source,java] ---- from("direct:start") .to("{{cool.end}}"); ---- -And in XML DSL: - +XML:: ++ [source,xml] ---- <route> @@ -128,7 +219,21 @@ And in XML DSL: </route> ---- +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:start + steps: + - to: + uri: "{{cool.end}}" +---- +==== + A property placeholder may also just be a one part in the endpoint URI. + A common use-case is to use a placeholder for an endpoint option such as the size of the write buffer in the file endpoint: @@ -137,14 +242,19 @@ as the size of the write buffer in the file endpoint: buf = 8192 ---- +[tabs] +==== + +Java:: ++ [source,java] ---- from("direct:start") .to("file:outbox?bufferSize={{buf}}"); ---- -And in XML DSL: - +XML:: ++ [source,xml] ---- <route> @@ -153,14 +263,55 @@ And in XML DSL: </route> ---- -However the placeholder can be anywhere, so it could also be the name of a mock endpoint +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:start + steps: + - to: + uri: "file:outbox?bufferSize={{buf}}" +---- +==== + +However, the placeholder can be anywhere, so it could also be the name of a mock endpoint + +[tabs] +==== +Java:: ++ [source,java] ---- from("direct:start") .to("mock:{{where}}"); ---- +XML:: ++ +[source,xml] +---- +<route> + <from uri="direct:start"/> + <to uri="mock:{{where}}"/> +</route> +---- + +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:start + steps: + - to: + uri: "mock:{{where}}" +---- +==== + In the example above the mock endpoint, is already hardcoded to start with `mock:`, and the `where` placeholder has the value `cheese` so the resolved uri becomes `mock:cheese`. @@ -174,39 +325,92 @@ cool.foo=result cool.concat=mock:{{cool.foo}} ---- -Notice how `cool.concat` refer to another property. +Notice how `cool.concat` refer to another property (above). + +You can then use the `cool.concat` placeholder in the Camel routes: -And the route in XML: +[tabs] +==== +Java:: ++ +[source,java] +---- +from("direct:start") + .to("{{cool.concat}}"); +---- + +XML:: ++ [source,xml] ---- <route> - <from uri="direct:start"/> - <to uri="{{cool.concat}}"/> + <from uri="direct:start"/> + <to uri="{{cool.concat}}"/> </route> ---- -==== Turning off nested placeholders +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:start + steps: + - to: + uri: "{{cool.concat}}" +---- +==== + + +==== Turning off nested placeholders (advanced) If the placeholder value contains data that interfere with the property placeholder syntax `{{` and `}}` (such as JSon data), you can be then explicit turn off nested placeholder by `?nested=false` in the key name, such as shown: +[tabs] +==== + +Java:: ++ +[source,java] +---- +from("direct:start") + .to("elasticsearch:foo?query={{myQuery?nested=false}}"); +---- + +XML:: ++ [source,xml] ---- <route> - <from uri="direct:start"/> - <to uri="elasticsearch:foo?query={{myQuery?nested=false}}"/> + <from uri="direct:start"/> + <to uri="elasticsearch:foo?query={{myQuery?nested=false}}"/> </route> ---- +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:start + steps: + - to: + uri: "elasticsearch:foo?query={{myQuery?nested=false}}" +---- +==== + In the example above the placeholder _myQuery_ placeholder value is as follows -[source,json] +[source,properties] ---- -{"query":{"match_all":{}}} +myQuery = {"query":{"match_all":{}}} ---- -Notice how the json query ends with `}}` which interfere with the Camel property placeholder syntax. +Notice how the JSon query ends with `}}` which interfere with the Camel property placeholder syntax. Nested placeholders can also be turned off globally on the xref:components::properties-component.adoc[Properties] component, such as: @@ -216,12 +420,22 @@ CamelContext context = ... context.getPropertiesComponent().setNestedPlaceholder(false); ---- -=== Escape a property placeholder +In the situation with the JSon query ending with `}}` which clashes with Camels property placeholder syntax, then its also possible +to use escaping as explained in the following section. + +==== Escaping a property placeholder The property placeholder can be problematic if the double curly brackets are used by a third party library like for example a query in ElasticSearch of type `{"query":{"match_all":{}}}`. To work around that it is possible to escape the double curly brackets with a backslash character like for example `\{{ property-name \}}`. This way, it won't be interpreted as a property placeholder to resolve and will be resolved as `{{ property-name }}`. +The previous example can then use escaping (see how the value ends with `\\}}`) + +[source,properties] +---- +myQuery = {"query":{"match_all":{}\\}} +---- + If for some reason, the backslash character before the double curly brackets must not be interpreted as an escape character, it is possible to add another backslash in front of it to escape it, it will then be seen as a backslash. === Using property placeholders multiple times @@ -237,6 +451,11 @@ cool.result=result And in this route we use `cool.start` two times: +[tabs] +==== + +Java:: ++ [source,java] ---- from("{{cool.start}}") @@ -244,7 +463,33 @@ from("{{cool.start}}") .to("mock:{{cool.result}}"); ---- -=== Using property placeholders with producer template +XML:: ++ +[source,xml] +---- +<route> + <from uri="{{cool.start}}"/> + <to uri="log:{{cool.start}}?showBodyType=false&showExchangeId={{cool.showid}}"/> + <to uri="mock:{{cool.result}}"/> +</route> +---- + +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:start + steps: + - to: + uri: "log:{{cool.start}}?showBodyType=false&showExchangeId={{cool.showid}}" + - to: + uri: "mock:{{cool.result}}" +---- +==== + +=== Using property placeholders with consumer and producer templates You can also your property placeholders when using xref:producertemplate.adoc[ProducerTemplate] for example: @@ -254,8 +499,6 @@ xref:producertemplate.adoc[ProducerTemplate] for example: template.sendBody("{{cool.start}}", "Hello World"); ---- -=== Using property placeholders with consumer template - This can also be done when using xref:consumertemplate.adoc[ConsumerTemplate], such as: [source,java] @@ -263,26 +506,6 @@ This can also be done when using xref:consumertemplate.adoc[ConsumerTemplate], s Object body = template.receiveBody("{{cool.start}}"); ---- -== Resolving property placeholders on cloud - -When you are running your Camel application on the cloud you may want to automatically scan any Configmap or Secret as it was an application properties. Given the following Secret: - ----- -apiVersion: v1 -data: - my-property: Q2FtZWwgNC44 -kind: Secret -metadata: - name: my-secret -type: Opaque ----- - -You can mount it in your Pod container, for instance, under `/etc/camel/conf.d/_secrets/my-secret`. Now, just make your Camel application be aware where to scan your configuration via `camel.main.cloud-properties-location = /etc/camel/conf.d/_secrets/my-secret` application properties. It's a comma separated value, so, you can add as many Secrets/Configmaps you need. - -At runtime, you will be able to read the configuration transparently as ```{{ my-property }}``` as you're doing with the rest of properties. - -NOTE: the same configuration works with Configmap. - == Resolving property placeholders from Java code If you need to resolve property placeholder(s) from some Java code, then Camel has two APIs for this: @@ -304,7 +527,7 @@ if (prop.isPresent()) { This API is to lookup a single property and returns a `java.util.Optional` type. The `CamelContext` have another API which is capable of resolving multiple placeholders, and interpolate placeholders from an input String. -Lets try with an example to explain this: +Let's try with an example to explain this: [source,java] ---- @@ -326,11 +549,38 @@ Will be resolved to: Hi Camel user, Camel is awesome dont you think? ---- -== Using property placeholders for any kind of attribute in Spring XML files +== Resolving property placeholders on cloud + +When you are running your Camel application on the cloud you may want to automatically scan any Configmap or Secret as it was an application properties. Given the following Secret: + +[source,yaml] +---- +apiVersion: v1 +data: + my-property: Q2FtZWwgNC44 +kind: Secret +metadata: + name: my-secret +type: Opaque +---- + +You can mount it in your Pod container, for instance, under `/etc/camel/conf.d/_secrets/my-secret`. Now, just make your Camel application be aware where to scan your configuration via `camel.main.cloud-properties-location = /etc/camel/conf.d/_secrets/my-secret` application properties. It's a comma separated value, so, you can add as many Secrets/Configmaps you need. + +At runtime, you will be able to read the configuration transparently as ```{{ my-property }}``` as you're doing with the rest of properties. + +NOTE: the same configuration works with Configmap. + + +== Special features for legacy Spring XML files + +Apache Camel started decade(s) ago when Spring Framework was heavily used with Spring XML files. +This means Camel has special features that apply only to Spring XML. + +=== Using property placeholders for any kind of attribute in Spring XML files Previously it was only the `xs:string` type attributes in the XML DSL that support placeholders. For example often a timeout attribute would -be a `xs:int` type and thus you cannot set a string value as the +be a `xs:int` type, and thus you cannot set a string value as the placeholder key. This is now possible using a special placeholder namespace. @@ -363,6 +613,7 @@ To configure the option we must then use the `prop:optionName` as shown below: The complete example is below: +.Spring XML [source,xml] ---- <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" @@ -397,8 +648,7 @@ In our properties file we have the value defined as: stop = true ---- - -== Bridging Camel property placeholders with Spring XML files +=== Bridging Camel property placeholders with Spring XML files NOTE: If you are using Spring Boot then this does not apply. This is only for legacy Camel and Spring applications which are using Spring XML files. @@ -414,6 +664,7 @@ type. To bridge Spring and Camel you must define a single bean as shown below: +.Spring XML [source,xml] ---- <!-- bridge spring property placeholder with Camel --> @@ -430,6 +681,7 @@ After declaring this bean, you can define property placeholders using both the Spring style, and the Camel style within the `<camelContext>` tag as shown below: +.Spring XML [source,xml] ---- <!-- a bean that uses Spring property placeholder --> @@ -452,6 +704,7 @@ Notice how the hello bean is using pure Spring property placeholders using the `${}` notation. And in the Camel routes we use the Camel placeholder notation with `{\{key}}`. + == Using property placeholder functions The xref:components::properties-component.adoc[Properties] component includes the following functions out of the box:
