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 65746971ab65ca65d7ae6fec4b3d24a90d635325 Author: Claus Ibsen <[email protected]> AuthorDate: Wed Feb 25 19:06:34 2026 +0100 CAMEL-16861: Update docs --- .../ROOT/pages/using-propertyplaceholder.adoc | 446 ++++++++++++++++++--- docs/user-manual/modules/ROOT/pages/validator.adoc | 56 ++- 2 files changed, 430 insertions(+), 72 deletions(-) diff --git a/docs/user-manual/modules/ROOT/pages/using-propertyplaceholder.adoc b/docs/user-manual/modules/ROOT/pages/using-propertyplaceholder.adoc index 051d5d0aed27..126b76155e7c 100644 --- a/docs/user-manual/modules/ROOT/pages/using-propertyplaceholder.adoc +++ b/docs/user-manual/modules/ROOT/pages/using-propertyplaceholder.adoc @@ -719,29 +719,82 @@ The xref:components::properties-component.adoc[Properties] component includes th These functions are intended to make it easy to lookup values from the environment, as shown in the example below: +[tabs] +==== + +Java:: ++ +[source,java] +---- +from("direct:start") + .to("{{env:SOMENAME}}") + .to("{{sys:MyJvmPropertyName}}"); +---- + +XML:: ++ [source,xml] ---- -<camelContext> - <route> - <from uri="direct:start"/> - <to uri="{{env:SOMENAME}}"/> - <to uri="{{sys:MyJvmPropertyName}}"/> - </route> -</camelContext> +<route> + <from uri="direct:start"/> + <to uri="{{env:SOMENAME}}"/> + <to uri="{{sys:MyJvmPropertyName}}"/> +</route> ---- +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:start + steps: + - to: + uri: "{{env:SOMENAME}}" + - to: + uri: "{{sys:MyJvmPropertyName}}" +---- +==== + You can use default values as well, so if the property does not exist, you can define a default value as shown below, where the default value is a `log:foo` and `log:bar` value. +[tabs] +==== + +Java:: ++ +[source,java] +---- +from("direct:start") + .to("{{env:SOMENAME:log:foo}}") + .to("{{sys:MyJvmPropertyName:log:bar}}"); +---- + +XML:: ++ [source,xml] ---- -<camelContext> - <route> - <from uri="direct:start"/> - <to uri="{{env:SOMENAME:log:foo}}"/> - <to uri="{{sys:MyJvmPropertyName:log:bar}}"/> - </route> -</camelContext> +<route> + <from uri="direct:start"/> + <to uri="{{env:SOMENAME:log:foo}}"/> + <to uri="{{sys:MyJvmPropertyName:log:bar}}"/> +</route> ---- +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:start + steps: + - to: + uri: "{{env:SOMENAME:log:foo}}" + - to: + uri: "{{sys:MyJvmPropertyName:log:bar}}" +---- +==== The boolean function is intended for more flexibility when enabling or disabling EIP options. @@ -754,20 +807,59 @@ region = EMEA We can then configure EIPs whether they are disabled based on this condition as follows: +[tabs] +==== + +Java:: ++ +[source,java] +---- +from("direct:start") + .choice().disabled("{{boolean:region == 'EMEA'}}") + .when(simple("${header.RetryAttempts} == null")) + .setProperty("HttpMessageMethod", constant("SET")) + .process("SetOriginalMessageProcessor") + .end(); +---- + +XML:: ++ +[source,xml] +---- +<route> + <from uri="direct:start"/> + <choice disabled="{{boolean:region == 'EMEA'}}"> + <when> + <simple>${header.RetryAttempts} == null</simple> + <setProperty name="HttpMessageMethod"> + <constant>SET</constant> + </setProperty> + <process ref="SetOriginalMessageProcessor"/> + </when> + </choice> +</route> +---- + +YAML:: ++ [source,yaml] ---- - - choice: - disabled: "{{boolean:region == 'EMEA`}}" - when: - - simple: "${header.RetryAttempts} == null" - steps: - - setProperty: - name: "HttpMessageMethod" - constant: "SET" - - process: - ref: "SetOriginalMessageProcessor" - ... +- route: + from: + uri: direct:start + steps: + - choice: + disabled: "{{boolean:region == 'EMEA'}}" + when: + - simple: "${header.RetryAttempts} == null" + steps: + - setProperty: + name: "HttpMessageMethod" + constant: "SET" + - process: + ref: "SetOriginalMessageProcessor" ---- +==== TIP: The boolean function uses the xref:components:languages:simple-language.adoc[Simple] language which has many functions and operators to build the condition. @@ -787,42 +879,114 @@ export $FOO_SERVICE_PORT=8888 For example if the FOO service a remote HTTP service, then we can refer to the service in the Camel endpoint uri, and use the HTTP component to make the HTTP call: +[tabs] +==== + +Java:: ++ +[source,java] +---- +from("direct:start") + .to("http://{{service:FOO}}/myapp"); +---- + +XML:: ++ [source,xml] ---- -<camelContext> - <route> - <from uri="direct:start"/> - <to uri="http://{{service:FOO}}/myapp"/> - </route> -</camelContext> +<route> + <from uri="direct:start"/> + <to uri="http://{{service:FOO}}/myapp"/> +</route> ---- +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:start + steps: + - to: + uri: "http://{{service:FOO}}/myapp" +---- +==== + And we can use default values if the service has not been defined, for example to call a service on localhost, maybe for unit testing. +[tabs] +==== + +Java:: ++ +[source,java] +---- +from("direct:start") + .to("http://{{service:FOO:localhost:8080}}/myapp"); +---- + +XML:: ++ [source,xml] ---- -<camelContext> <route> <from uri="direct:start"/> <to uri="http://{{service:FOO:localhost:8080}}/myapp"/> </route> -</camelContext> ---- +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:start + steps: + - to: + uri: "http://{{service:FOO:localhost:8080}}/myapp" +---- +==== + The bean function (you need to have `camel-bean` JAR on classpath) is for looking up the property from the return value of bean's method. Assuming we have registered a bean named 'foo' that has a method called 'bar' that returns a directory name, then we can refer to the bean's method in the camel endpoint url, and use the file component to poll a directory: +[tabs] +==== + +Java:: ++ +[source,java] +---- +from("file:{{bean:foo.bar}}") + .to("direct:result"); +---- + +XML:: ++ [source,xml] ---- -<camelContext> <route> <from uri="file:{{bean:foo.bar}}"/> <to uri="direct:result"/> </route> -</camelContext> ---- +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: file:{{bean:foo.bar}} + steps: + - to: + uri: "direct:result" +---- +==== + IMPORTANT: The method must be a public no-arg method (i.e. no parameters) and return a value such as a String, boolean, int. === Using Kubernetes property placeholder functions @@ -836,7 +1000,7 @@ The `camel-kubernetes` component include the following functions: The syntax for both functions are: -[source] +[source,text] ---- configmap:name/key[:defaultValue] ---- @@ -844,21 +1008,21 @@ configmap:name/key[:defaultValue] Where the default value is optional, for example the following will lookup `myKey`, and fail if there is no such configmap. -[source] +[source,text] ---- configmap:mymap/mykey ---- In this example then it would not fail as a default value is provided: -[source] +[source,text] ---- configmap:mymap/mykey:123 ---- If the value stored in the configmap is in binary format, so it is stored as `Binary Data`, it will be downloaded in a file, and it returns the absolute path of the file -[source] +[source,text] ---- configmap-binary:mymap/mybinkey ---- @@ -876,8 +1040,7 @@ Camel will first use _mount paths_ (if configured) to lookup, and then fallback The configuration of the _mount path_ are used by the given order: -1. Reading configuration property with keys `camel.kubernetes-config.mount-path-configmaps` -and `camel.kubernetes-config.mount-path-secrets`. +1. Reading configuration property with keys `camel.kubernetes-config.mount-path-configmaps` and `camel.kubernetes-config.mount-path-secrets`. 2. Use JVM system property with key `camel.k.mount-path.configmaps` and `camel.k.mount-path.secrets` (Camel K compatible). 3. Use OS ENV variable with key `CAMEL_K_MOUNT_PATH_CONFIGMAPS` and `CAMEL_K_MOUNT_PATH_SECRETS` (Camel K compatible). @@ -908,7 +1071,7 @@ camel.kubernetes-config.client.masterUrl = https://127.0.0.1:50179/ camel.kubernetes-config.client.oauthToken = eyJhbGciOiJSUzI1NiIsImtpZCI... ---- -The `KubernetesClient` has many options, see the https://github.com/fabric8io/kubernetes-client documentation. +TIP: The `KubernetesClient` has many options, see the https://github.com/fabric8io/kubernetes-client[Kubernetes Client] documentation for more information for these options. If you only use _mount paths_, then it is good practice to disable `KubernetesClient` which can be done by setting enabled to false as show: @@ -935,23 +1098,83 @@ first = Carlsberg Then these values can be used in your Camel routes such as: +[tabs] +==== + +Java:: ++ +[source,java] +---- +from("direct:start") + .log("What {{configmap:myconfig/drink}} do you want?") + .log("I want {{configmap:myconfig/first}}"); +---- + +XML:: ++ [source,xml] ---- -<camelContext> <route> <from uri="direct:start"/> <log message="What {{configmap:myconfig/drink}} do you want?"/> <log message="I want {{configmap:myconfig/first}}"/> </route> -</camelContext> ---- -You can also provide a default value in case a key does not exist: +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:start + steps: + - log: + message: "What {{configmap:myconfig/drink}} do you want?" + - log: + message: "I want {{configmap:myconfig/first}}" +---- +==== + +You can also provide a default value in case a key does not exist, such as `Heiniken` being the default value: + +[tabs] +==== + +Java:: ++ +[source,java] +---- +from("direct:start") + .log("What {{configmap:myconfig/drink}} do you want?") + .log("I want {{configmap:myconfig/second:Heineken}}"); +---- +XML:: ++ [source,xml] ---- + <route> + <from uri="direct:start"/> + <log message="What {{configmap:myconfig/drink}} do you want?"/> <log message="I want {{configmap:myconfig/second:Heineken}}"/> + </route> +---- + +YAML:: ++ +[source,yaml] ---- +- route: + from: + uri: direct:start + steps: + - log: + message: "What {{configmap:myconfig/drink}} do you want?" + - log: + message: "I want {{configmap:myconfig/second:Heineken}}" +---- +==== ==== Using secrets with Kubernetes @@ -968,11 +1191,34 @@ myuser = scott mypass = tiger ---- -This can be used in Camel with for example the Postrgres Sink Kamelet: +This can be used in Camel with for example the Postgres Sink Kamelet: +[tabs] +==== + +Java:: ++ +[source,java] +---- +String sink = +""" + kamelet:postgresql-sink?serverName={{secret:mydb/myhost}}? + &serverPort={{secret:mydb/myport}} + &username={{secret:mydb/myuser}} + &password={{secret:mydb/mypass}} + &databaseName=cities + &query=INSERT INTO accounts (username,city) VALUES (:#username,:#city) +"""; + +from("direct:rome") + .setBody(constant("{ \"username\":\"oscerd\", \"city\":\"Rome\"}")) + .to(sink); +---- + +XML:: ++ [source,xml] ---- -<camelContext> <route> <from uri="direct:rome"/> <setBody> @@ -985,9 +1231,35 @@ This can be used in Camel with for example the Postrgres Sink Kamelet: &databaseName=cities &query=INSERT INTO accounts (username,city) VALUES (:#username,:#city)"/> </route> -</camelContext> ---- +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct + parameters: + name: rome + steps: + - setBody: + expression: + constant: + expression: "{ \"username\":\"oscerd\", \"city\":\"Rome\"}" + - to: + uri: kamelet + parameters: + templateId: postgresql-sink + serverName: "{{secret:mydb/myhost}}" + serverPort: "{{secret:mydb/myport}}" + username: "{{secret:mydb/myuser}}" + password: "{{secret:mydb/mypass}}" + databaseName: 'cities' + query: "INSERT INTO accounts (username,city) VALUES (:#username,:#city)" +---- +==== + The postgres-sink Kamelet can also be configured in `application.properties` which reduces the configuration in the route above: @@ -1001,9 +1273,22 @@ camel.component.kamelet.postgresql-sink.password={{secret:mydb/mypass}} Which reduces the route to: +[tabs] +==== + +Java:: ++ +[source,java] +---- +from("direct:rome") + .setBody(constant("{ \"username\":\"oscerd\", \"city\":\"Rome\"}")) + .to("kamelet:postgresql-sink?databaseName=cities&query=INSERT INTO accounts (username,city) VALUES (:#username,:#city)"); +---- + +XML:: ++ [source,xml] ---- -<camelContext> <route> <from uri="direct:rome"/> <setBody> @@ -1012,15 +1297,35 @@ Which reduces the route to: <to uri="kamelet:postgresql-sink?databaseName=cities &query=INSERT INTO accounts (username,city) VALUES (:#username,:#city)"/> </route> -</camelContext> ---- +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:rome + steps: + - setBody: + expression: + constant: + expression: "{ \"username\":\"oscerd\", \"city\":\"Rome\"}" + - to: + uri: kamelet + parameters: + templateId: postgresql-sink + databaseName: cities + query: "INSERT INTO accounts (username,city) VALUES (:#username,:#city)" +---- +==== + ==== Using configmap or secrets in local-mode -During development you may want to run in _local mode_ where you do not need acces to a Kubernetes cluster, to lookup the configmap. +During development, you may want to run in _local mode_ where you do not need acces to a Kubernetes cluster, to lookup the configmap. In the local mode, then Camel will lookup the configmap _keys_ from local properties, eg: -For example the example above with the postgresql kamelet, that was configured using a secret: +For example the example above with the Postgres kamelet, that was configured using a secret: [source,properties] ---- @@ -1030,7 +1335,7 @@ camel.component.kamelet.postgresql-sink.username={{secret:mydb/myuser}} camel.component.kamelet.postgresql-sink.password={{secret:mydb/mypass}} ---- -Now suppose we have a local Postrgres database we want to use, then we can turn on _local mode_ +Now suppose we have a local Postgres database we want to use, then we can turn on _local mode_ and specify the credentials in the same properties file: [source,properties] @@ -1045,6 +1350,7 @@ mydb/mypass=tiger NOTE: Notice how the key is prefixed with the name of the secret and a slash, eg `name/key`. This makes it easy to copy/paste from the actual use of the configmap/secret and into the `application.properties` file. + === Using custom property placeholder functions The xref:components::properties-component.adoc[Properties] component allow to plugin 3rd party functions which can be used during parsing of the property placeholders. @@ -1053,6 +1359,20 @@ The name of the function becomes the prefix used in the placeholder. This is best illustrated in the example route below, where we use `beer` as the prefix: +[tabs] +==== + +Java:: ++ +[source,java] +---- +from("direct:start") + .to("{{beer:FOO}}") + .to("{{beer:BAR}}"); +---- + +XML:: ++ [source,xml] ---- <route> @@ -1062,6 +1382,21 @@ This is best illustrated in the example route below, where we use `beer` as the </route> ---- +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:start + steps: + - to: + uri: "{{beer:FOO}}" + - to: + uri: "{{beer:BAR}}" +---- +==== + The implementation of the function is only two methods as shown below: [source,java] @@ -1086,7 +1421,7 @@ The method `getName` is the name of the function (beer). And the `apply` method is where we implement the custom logic to do. As the sample code is from a unit test, it just returns a value to refer to a mock endpoint. -You also need to have `camel-component-maven-plugin` as part of building the component will +You also need to have `camel-component-maven-plugin` Maven plugin as part of building the component will then ensure that this custom properties function has necessary source code generated that makes Camel able to automatically discover the function. @@ -1095,6 +1430,7 @@ and have this logic in `doStart` and `doStop` methods. TIP: For an example see the `camel-base64` component. + == Using third party property sources The properties component allows to plugin 3rd party sources to load and lookup properties via the `PropertySource` @@ -1113,7 +1449,7 @@ This is done by including the file `META-INF/services/org/apache/camel/property- See xref:components:others:microprofile-config.adoc[MicroProfile Config] component as an example. -You can also register 3rd-party property sources via Java API: +You can also register 3rd-party property sources via Java API on the `PropertiesComponent` as shown: [source,java] ---- diff --git a/docs/user-manual/modules/ROOT/pages/validator.adoc b/docs/user-manual/modules/ROOT/pages/validator.adoc index e4376bee5325..d9fe47eba8a6 100644 --- a/docs/user-manual/modules/ROOT/pages/validator.adoc +++ b/docs/user-manual/modules/ROOT/pages/validator.adoc @@ -27,8 +27,8 @@ data type name. | Custom Validator | Validate with using custom validator class. Validator must be a subclass of `org.apache.camel.spi.Validator` |=== - == Common Options + All validators have following common options to specify which data type is supported by the validator. `type` must be specified. @@ -38,7 +38,6 @@ All validators have following common options to specify which data type is suppo | type | Data type to validate |=== - == Predicate Validator Options [width="100%",cols="25%,75%",options="header",] @@ -49,8 +48,12 @@ All validators have following common options to specify which data type is suppo Here is an example to specify a validation predicate: -Java DSL: +[tabs] +==== + +Java:: ++ [source,java] ---- validator() @@ -58,14 +61,15 @@ validator() .withExpression(bodyAs(String.class).contains("{name:XOrder}")); ---- -XML DSL: - +Spring XML:: ++ [source,xml] ---- <predicateValidator Type="csv:CSVOrder"> <simple>${body} contains '{name:XOrder}'</simple> </predicateValidator> ---- +==== == Endpoint Validator Options @@ -78,6 +82,11 @@ XML DSL: Here is an example to specify endpoint URI in Java DSL: +[tabs] +==== + +Java:: ++ [source,java] ---- validator() @@ -85,12 +94,13 @@ validator() .withUri("validator:xsd/schema.xsd"); ---- -And here is an example to specify endpoint ref in XML DSL: - +Spring XML:: ++ [source,xml] ---- <endpointValidator uri="validator:xsd/schema.xsd" type="xml"/> ---- +==== Note that the Endpoint Validator just forwards the message to the specified endpoint. In above example, camel forwards the message to the `validator:` endpoint, which actually is a @@ -110,8 +120,11 @@ The validator must be an implementation of `org.apache.camel.spi.Validator` Here is an example to specify custom Validator class: -Java DSL: +[tabs] +==== +Java:: ++ [source,java] ---- validator() @@ -119,20 +132,24 @@ validator() .withJava(com.example.MyCustomValidator.class); ---- -XML DSL: - +Spring XML:: ++ [source,xml] ---- <customTransformer className="com.example.MyCustomValidator" type="json"/> ---- +==== == Examples For example to declare the Endpoint Validator which uses validator component to validate `xml:ABCOrder`, we can do as follows: -Java DSL: +[tabs] +==== +Java:: ++ [source,java] ---- validator() @@ -140,8 +157,8 @@ validator() .withUri("validator:xsd/schema.xsd"); ---- -And in XML DSL: - +Spring XML:: ++ [source,xml] ---- <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> @@ -150,13 +167,17 @@ And in XML DSL: </validators> </camelContext> ---- +==== -If you have following route definition, above validator will be applied when `direct:abc` endpoint +If you have the following route definition, above validator will be applied when `direct:abc` endpoint receives the message. Note that `inputTypeWithValidate` is used instead of `inputType` in Java DSL, and the `validate` attribute on the inputType declaration is set to `true` in XML DSL: -Java DSL: +[tabs] +==== +Java:: ++ [source,java] ---- from("direct:abc") @@ -164,8 +185,8 @@ from("direct:abc") .log("${body}"); ---- -XML DSL: - +Spring XML:: ++ [source,xml] ---- <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> @@ -176,6 +197,7 @@ XML DSL: </route> </camelContext> ---- +==== == See Also
