You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2023/12/31 12:06:53 UTC

(camel) branch main updated: CAMEL-19749: Introduce variables to Camel (#12624)

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


The following commit(s) were added to refs/heads/main by this push:
     new c4af3401066 CAMEL-19749: Introduce variables to Camel (#12624)
c4af3401066 is described below

commit c4af34010667d7bae92f5d42dda5de83dc9d2038
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Dec 31 13:06:47 2023 +0100

    CAMEL-19749: Introduce variables to Camel (#12624)
    
    CAMEL-19749: Add variables as concept to Camel
---
 .../org/apache/camel/catalog/components/log.json   |   5 +-
 .../apache/camel/catalog/components/thymeleaf.json |  14 +-
 .../org/apache/camel/catalog/models.properties     |   2 +
 .../org/apache/camel/catalog/models/aggregate.json |   2 +-
 .../camel/catalog/models/circuitBreaker.json       |   2 +-
 .../org/apache/camel/catalog/models/doCatch.json   |   2 +-
 .../org/apache/camel/catalog/models/doFinally.json |   2 +-
 .../org/apache/camel/catalog/models/doTry.json     |   2 +-
 .../org/apache/camel/catalog/models/filter.json    |   2 +-
 .../camel/catalog/models/idempotentConsumer.json   |   2 +-
 .../org/apache/camel/catalog/models/intercept.json |   2 +-
 .../apache/camel/catalog/models/interceptFrom.json |   2 +-
 .../catalog/models/interceptSendToEndpoint.json    |   2 +-
 .../org/apache/camel/catalog/models/kamelet.json   |   2 +-
 .../apache/camel/catalog/models/loadBalance.json   |   2 +-
 .../org/apache/camel/catalog/models/loop.json      |   2 +-
 .../org/apache/camel/catalog/models/multicast.json |   2 +-
 .../apache/camel/catalog/models/onCompletion.json  |   2 +-
 .../apache/camel/catalog/models/onException.json   |   2 +-
 .../apache/camel/catalog/models/onFallback.json    |   2 +-
 .../org/apache/camel/catalog/models/otherwise.json |   2 +-
 .../org/apache/camel/catalog/models/pipeline.json  |   2 +-
 .../camel/catalog/models/removeVariable.json       |  20 +++
 .../apache/camel/catalog/models/resequence.json    |   2 +-
 .../org/apache/camel/catalog/models/route.json     |   2 +-
 .../org/apache/camel/catalog/models/saga.json      |   2 +-
 .../apache/camel/catalog/models/setVariable.json   |  21 +++
 .../org/apache/camel/catalog/models/split.json     |   2 +-
 .../org/apache/camel/catalog/models/step.json      |   2 +-
 .../org/apache/camel/catalog/models/when.json      |   2 +-
 .../catalog/models/whenSkipSendToEndpoint.json     |   2 +-
 .../apache/camel/catalog/schemas/camel-spring.xsd  | 129 +++++++++++++++
 .../camel-bean/src/main/docs/bean-language.adoc    |   2 +-
 .../bean/AbstractCamelInvocationHandler.java       |  14 ++
 .../org/apache/camel/component/bean/BeanInfo.java  |   7 +
 .../camel-chunk/src/main/docs/chunk-component.adoc |   2 +
 .../src/main/docs/freemarker-component.adoc        |   2 +
 .../camel-jslt/src/main/docs/jslt-component.adoc   |   1 +
 .../apache/camel/component/jslt/JsltEndpoint.java  |   3 +
 .../camel/component/log/LogEndpointConfigurer.java |   6 +
 .../camel/component/log/LogEndpointUriFactory.java |   3 +-
 .../org/apache/camel/component/log/log.json        |   5 +-
 .../apache/camel/component/log/LogEndpoint.java    |  13 +-
 .../apache/camel/component/mock/MockEndpoint.java  |  90 +++++++++++
 .../src/main/docs/mustache-component.adoc          |   2 +
 .../camel-mvel/src/main/docs/mvel-component.adoc   |   1 +
 .../robotframework/RobotFrameworkCamelUtils.java   |   5 +
 .../spring/processor/SpringSetVariableTest.java    |  43 +++++
 .../processor/SpringSetVariableTest-context.xml    |  39 +++++
 .../src/main/docs/string-template-component.adoc   |  26 +++
 .../camel/component/thymeleaf/thymeleaf.json       |  14 +-
 .../component/thymeleaf/ThymeleafEndpoint.java     |  78 +--------
 .../src/main/docs/velocity-component.adoc          |   2 +
 .../main/java/org/apache/camel/CamelContext.java   |  28 ++++
 .../src/main/java/org/apache/camel/Exchange.java   |  59 +++++++
 .../java/org/apache/camel/ExchangeExtension.java   |   1 +
 .../src/main/java/org/apache/camel/Variable.java   |  39 +++++
 .../src/main/java/org/apache/camel/Variables.java  |  34 ++++
 .../camel/spi/BrowsableVariableRepository.java     |  52 ++++++
 .../org/apache/camel/spi/VariableRepository.java   |  55 +++++++
 .../camel/spi/VariableRepositoryFactory.java       |  37 +++++
 .../camel/impl/engine/AbstractCamelContext.java    |  37 +++++
 .../engine/DefaultVariableRepositoryFactory.java   | 107 +++++++++++++
 .../camel/impl/engine/SimpleCamelContext.java      |   6 +
 .../org/apache/camel/dev-console/variables         |   2 +
 .../camel/impl/console/VariablesDevConsole.java    |  82 ++++++++++
 .../modules/eips/examples/json/removeVariable.json |   1 +
 .../modules/eips/examples/json/setVariable.json    |   1 +
 .../src/main/docs/modules/eips/nav.adoc            |   2 +
 .../modules/eips/pages/removeVariable-eip.adoc     |  44 +++++
 .../docs/modules/eips/pages/setVariable-eip.adoc   | 104 ++++++++++++
 .../modules/languages/pages/simple-language.adoc   |  15 +-
 .../language/simple/SimpleExpressionBuilder.java   |  16 ++
 .../simple/ast/SimpleFunctionExpression.java       |  71 +++++++++
 .../services/org/apache/camel/model.properties     |   2 +
 .../org/apache/camel/model/aggregate.json          |   2 +-
 .../org/apache/camel/model/circuitBreaker.json     |   2 +-
 .../resources/org/apache/camel/model/doCatch.json  |   2 +-
 .../org/apache/camel/model/doFinally.json          |   2 +-
 .../resources/org/apache/camel/model/doTry.json    |   2 +-
 .../resources/org/apache/camel/model/filter.json   |   2 +-
 .../org/apache/camel/model/idempotentConsumer.json |   2 +-
 .../org/apache/camel/model/intercept.json          |   2 +-
 .../org/apache/camel/model/interceptFrom.json      |   2 +-
 .../camel/model/interceptSendToEndpoint.json       |   2 +-
 .../resources/org/apache/camel/model/jaxb.index    |   2 +
 .../resources/org/apache/camel/model/kamelet.json  |   2 +-
 .../org/apache/camel/model/loadBalance.json        |   2 +-
 .../resources/org/apache/camel/model/loop.json     |   2 +-
 .../org/apache/camel/model/multicast.json          |   2 +-
 .../org/apache/camel/model/onCompletion.json       |   2 +-
 .../org/apache/camel/model/onException.json        |   2 +-
 .../org/apache/camel/model/onFallback.json         |   2 +-
 .../org/apache/camel/model/otherwise.json          |   2 +-
 .../resources/org/apache/camel/model/pipeline.json |   2 +-
 .../org/apache/camel/model/removeVariable.json     |  20 +++
 .../org/apache/camel/model/resequence.json         |   2 +-
 .../resources/org/apache/camel/model/route.json    |   2 +-
 .../resources/org/apache/camel/model/saga.json     |   2 +-
 .../org/apache/camel/model/setVariable.json        |  21 +++
 .../resources/org/apache/camel/model/split.json    |   2 +-
 .../resources/org/apache/camel/model/step.json     |   2 +-
 .../resources/org/apache/camel/model/when.json     |   2 +-
 .../apache/camel/model/whenSkipSendToEndpoint.json |   2 +-
 .../org/apache/camel/builder/BuilderSupport.java   |  34 ++++
 .../apache/camel/model/ProcessorDefinition.java    |  57 ++++++-
 .../camel/model/RemoveVariableDefinition.java      |  69 ++++++++
 .../apache/camel/model/SetVariableDefinition.java  |  96 +++++++++++
 .../camel/processor/RemoveVariableProcessor.java   | 122 ++++++++++++++
 .../camel/processor/SetVariableProcessor.java      | 139 ++++++++++++++++
 .../org/apache/camel/reifier/ProcessorReifier.java |   6 +
 .../camel/reifier/RemoveVariableReifier.java       |  45 ++++++
 .../apache/camel/reifier/SetVariableReifier.java   |  48 ++++++
 .../java/org/apache/camel/ExchangeTestSupport.java |   1 +
 .../component/bean/BeanPipelineVariablesTest.java  |  96 +++++++++++
 ...eanWithPropertiesAndVariablesInjectionTest.java |  97 +++++++++++
 .../bean/BeanWithVariablesAndBodyInject3Test.java  |  87 ++++++++++
 .../BeanWithVariablesAndBodyInjectionTest.java     |  99 ++++++++++++
 .../log/DefaultExchangeFormatterTest.java          |   1 +
 .../org/apache/camel/impl/DefaultExchangeTest.java |  79 +++++++++
 .../apache/camel/language/simple/SimpleTest.java   | 110 ++++++++++++-
 .../camel/processor/CustomGlobalVariableTest.java  | 113 +++++++++++++
 .../camel/processor/MethodFilterVariableTest.java  |  74 +++++++++
 .../camel/processor/RemoveGlobalVariableTest.java  |  77 +++++++++
 .../apache/camel/processor/RemoveVariableTest.java |  78 +++++++++
 .../camel/processor/SetGlobalVariableTest.java     |  74 +++++++++
 .../apache/camel/processor/SetVariableTest.java    |  67 ++++++++
 .../org/apache/camel/util/ExchangeHelperTest.java  |  13 +-
 .../org/apache/camel/model/removeVariable.xml      |  29 ++++
 .../org/apache/camel/model/setVariable.xml         |  28 ++++
 .../org/apache/camel/main/BaseMainSupport.java     |  17 ++
 .../camel/main/DefaultConfigurationConfigurer.java |   5 +
 .../camel/main/MainSupportModelConfigurer.java     |  32 ++++
 .../org/apache/camel/main/MainVariableTest.java    |  85 ++++++++++
 core/camel-main/src/test/resources/random.json     |   3 +
 .../api/management/mbean/CamelOpenMBeanTypes.java  |  13 ++
 .../mbean/ManagedRemoveVariableMBean.java          |  26 +++
 .../management/mbean/ManagedSetVariableMBean.java  |  32 ++++
 .../mbean/ManagedVariableRepositoryMBean.java      |  43 +++++
 .../DefaultManagementObjectStrategy.java           |   9 ++
 .../management/JmxManagementLifecycleStrategy.java |   4 +
 .../management/mbean/ManagedRemoveVariable.java    |  38 +++++
 .../camel/management/mbean/ManagedSetVariable.java |  53 ++++++
 .../mbean/ManagedVariableRepository.java           | 106 ++++++++++++
 .../management/ManagedNonManagedServiceTest.java   |   2 +-
 ...edProducerRouteAddRemoveRegisterAlwaysTest.java |   2 +-
 .../management/ManagedRouteAddRemoveTest.java      |   2 +-
 ...ManagedSetAndRemoveHeaderAndPropertiesTest.java |  20 ++-
 .../DefaultExchangeFormatterConfigurer.java        |   6 +
 .../org/apache/camel/support/AbstractExchange.java |  66 +++++++-
 .../camel/support/DefaultPooledExchange.java       |   3 -
 .../org/apache/camel/support/ExchangeHelper.java   |   1 +
 .../camel/support/ExchangeVariableRepository.java  |  88 ++++++++++
 .../camel/support/ExtendedExchangeExtension.java   |   3 +-
 .../camel/support/GlobalVariableRepository.java    |  85 ++++++++++
 .../org/apache/camel/support/LanguageHelper.java   |  15 ++
 .../camel/support/builder/ExpressionBuilder.java   | 150 +++++++++++++++++
 .../processor/DefaultExchangeFormatter.java        |  25 ++-
 .../java/org/apache/camel/util/StringHelper.java   |  18 +++
 .../java/org/apache/camel/xml/in/ModelParser.java  |  20 +++
 .../java/org/apache/camel/xml/out/ModelWriter.java |  33 ++++
 .../org/apache/camel/yaml/out/ModelWriter.java     |  33 ++++
 .../components/modules/ROOT/examples/json/jte.json |   1 +
 docs/components/modules/ROOT/nav.adoc              |   1 +
 .../modules/ROOT/pages/jte-component.adoc          |   1 +
 .../working-with-camel-core/pages/index.adoc       |   1 +
 .../ROOT/pages/parameter-binding-annotations.adoc  |   9 +-
 docs/user-manual/modules/ROOT/pages/variables.adoc | 171 ++++++++++++++++++++
 .../camel/cli/connector/LocalCliConnector.java     |   7 +
 .../endpoint/dsl/LogEndpointBuilderFactory.java    |  31 ++++
 .../dsl/ThymeleafEndpointBuilderFactory.java       | 177 +++++++++++----------
 .../dsl/jbang/core/commands/CamelJBangMain.java    |   1 +
 .../jbang/core/commands/process/ListVariable.java  | 169 ++++++++++++++++++++
 .../dsl/yaml/deserializers/ModelDeserializers.java | 156 ++++++++++++++++++
 .../deserializers/ModelDeserializersResolver.java  |   6 +
 .../generated/resources/schema/camelYamlDsl.json   | 162 +++++++++++++++++++
 .../camel/dsl/yaml/RemoveVariableTest.groovy       |  73 +++++++++
 .../apache/camel/dsl/yaml/SetVariableTest.groovy   | 109 +++++++++++++
 178 files changed, 5084 insertions(+), 259 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/log.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/log.json
index 26bebc29b44..64f0087f0e7 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/log.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/log.json
@@ -60,7 +60,8 @@
     "showRouteId": { "index": 28, "kind": "parameter", "displayName": "Show Route Id", "group": "formatting", "label": "formatting", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Show route ID." },
     "showStackTrace": { "index": 29, "kind": "parameter", "displayName": "Show Stack Trace", "group": "formatting", "label": "formatting", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Show the stack trace, if an exchange has an exception. Only effective if one of showAll, showException or showCaughtException are enabled." },
     "showStreams": { "index": 30, "kind": "parameter", "displayName": "Show Streams", "group": "formatting", "label": "formatting", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether Camel should show stream bodies or not (eg such as java.io.InputStream). Beware if you enable this option then you may not be able later to access the message body as the stream have already bee [...]
-    "skipBodyLineSeparator": { "index": 31, "kind": "parameter", "displayName": "Skip Body Line Separator", "group": "formatting", "label": "formatting", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to skip line separators when logging the message body. This allows to log the message body in one line, setting this option to false will preserve any line separators from t [...]
-    "style": { "index": 32, "kind": "parameter", "displayName": "Style", "group": "formatting", "label": "formatting", "required": false, "type": "object", "javaType": "org.apache.camel.support.processor.DefaultExchangeFormatter.OutputStyle", "enum": [ "Default", "Tab", "Fixed" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "Default", "description": "Sets the outputs style to use." }
+    "showVariables": { "index": 31, "kind": "parameter", "displayName": "Show Variables", "group": "formatting", "label": "formatting", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Show the variables." },
+    "skipBodyLineSeparator": { "index": 32, "kind": "parameter", "displayName": "Skip Body Line Separator", "group": "formatting", "label": "formatting", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to skip line separators when logging the message body. This allows to log the message body in one line, setting this option to false will preserve any line separators from t [...]
+    "style": { "index": 33, "kind": "parameter", "displayName": "Style", "group": "formatting", "label": "formatting", "required": false, "type": "object", "javaType": "org.apache.camel.support.processor.DefaultExchangeFormatter.OutputStyle", "enum": [ "Default", "Tab", "Fixed" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "Default", "description": "Sets the outputs style to use." }
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/thymeleaf.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/thymeleaf.json
index ca54a5ade49..bcd8df3ac89 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/thymeleaf.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/thymeleaf.json
@@ -39,12 +39,12 @@
     "cacheTimeToLive": { "index": 3, "kind": "parameter", "displayName": "Cache Time To Live", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "description": "The cache Time To Live for templates, expressed in milliseconds." },
     "checkExistence": { "index": 4, "kind": "parameter", "displayName": "Check Existence", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "description": "Whether a template resources will be checked for existence before being returned." },
     "contentCache": { "index": 5, "kind": "parameter", "displayName": "Content Cache", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Sets whether to use resource content cache or not" },
-    "encoding": { "index": 6, "kind": "parameter", "displayName": "Encoding", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The character encoding to be used for reading template resources." },
-    "order": { "index": 7, "kind": "parameter", "displayName": "Order", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "description": "The order in which this template will be resolved as part of the resolver chain." },
-    "prefix": { "index": 8, "kind": "parameter", "displayName": "Prefix", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "An optional prefix added to template names to convert them into resource names." },
-    "resolver": { "index": 9, "kind": "parameter", "displayName": "Resolver", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.thymeleaf.ThymeleafResolverType", "enum": [ "CLASS_LOADER", "DEFAULT", "FILE", "STRING", "URL", "WEB_APP" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "CLASS_LOADER", "description": "The type of resolver to be used by the template engine." },
-    "suffix": { "index": 10, "kind": "parameter", "displayName": "Suffix", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "An optional suffix added to template names to convert them into resource names." },
-    "templateMode": { "index": 11, "kind": "parameter", "displayName": "Template Mode", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The template mode to be applied to templates." },
-    "lazyStartProducer": { "index": 12, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...]
+    "templateMode": { "index": 6, "kind": "parameter", "displayName": "Template Mode", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "enum": [ "HTML", "XML", "TEXT", "JAVASCRIPT", "CSS", "RAW" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "HTML", "description": "The template mode to be applied to templates." },
+    "lazyStartProducer": { "index": 7, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produc [...]
+    "encoding": { "index": 8, "kind": "parameter", "displayName": "Encoding", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The character encoding to be used for reading template resources." },
+    "order": { "index": 9, "kind": "parameter", "displayName": "Order", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "description": "The order in which this template will be resolved as part of the resolver chain." },
+    "prefix": { "index": 10, "kind": "parameter", "displayName": "Prefix", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "An optional prefix added to template names to convert them into resource names." },
+    "resolver": { "index": 11, "kind": "parameter", "displayName": "Resolver", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.thymeleaf.ThymeleafResolverType", "enum": [ "CLASS_LOADER", "DEFAULT", "FILE", "STRING", "URL", "WEB_APP" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "CLASS_LOADER", "description": "The type of resolver to be used by the template engine." },
+    "suffix": { "index": 12, "kind": "parameter", "displayName": "Suffix", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "An optional suffix added to template names to convert them into resource names." }
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties
index 21c43f99f83..6302c86936d 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties
@@ -128,6 +128,7 @@ removeHeader
 removeHeaders
 removeProperties
 removeProperty
+removeVariable
 resequence
 resilience4jConfiguration
 responseHeader
@@ -169,6 +170,7 @@ setExchangePattern
 setHeader
 setHeaders
 setProperty
+setVariable
 simple
 soap
 sort
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/aggregate.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/aggregate.json
index 3e6e98cc342..6411c8b6422 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/aggregate.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/aggregate.json
@@ -42,6 +42,6 @@
     "discardOnAggregationFailure": { "index": 27, "kind": "attribute", "displayName": "Discard On Aggregation Failure", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Discards the aggregated message when aggregation failed (an exception was thrown from AggregationStrategy . This means the partly aggregated message is dropped and not sent out of the [...]
     "forceCompletionOnStop": { "index": 28, "kind": "attribute", "displayName": "Force Completion On Stop", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Indicates to complete all current aggregated exchanges when the context is stopped" },
     "completeAllOnStop": { "index": 29, "kind": "attribute", "displayName": "Complete All On Stop", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Indicates to wait to complete all current and partial (pending) aggregated exchanges when the context is stopped. This also means that we will wait for all pending exchanges which are stored in the aggre [...]
-    "outputs": { "index": 30, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
+    "outputs": { "index": 30, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/circuitBreaker.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/circuitBreaker.json
index 656922f6098..9cd6e592cfc 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/circuitBreaker.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/circuitBreaker.json
@@ -19,6 +19,6 @@
     "resilience4jConfiguration": { "index": 4, "kind": "element", "displayName": "Resilience4j Configuration", "required": false, "type": "object", "javaType": "org.apache.camel.model.Resilience4jConfigurationDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Configures the circuit breaker to use Resilience4j with the given configuration." },
     "faultToleranceConfiguration": { "index": 5, "kind": "element", "displayName": "Fault Tolerance Configuration", "required": false, "type": "object", "javaType": "org.apache.camel.model.FaultToleranceConfigurationDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Configures the circuit breaker to use MicroProfile Fault Tolerance with the given configuration." },
     "onFallback": { "index": 6, "kind": "element", "displayName": "On Fallback", "required": false, "type": "object", "javaType": "org.apache.camel.model.OnFallbackDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "The fallback route path to execute that does not go over the network. This should be a static or cached result that can immediately be returned upon failure. If the fallback requires network connection then use onFallbackViaNetwork() ." },
-    "outputs": { "index": 7, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 7, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/doCatch.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/doCatch.json
index 75dbf6fdb12..adb84178cff 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/doCatch.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/doCatch.json
@@ -17,6 +17,6 @@
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "exception": { "index": 3, "kind": "element", "displayName": "Exception", "required": false, "type": "array", "javaType": "java.util.List<java.lang.String>", "deprecated": false, "autowired": false, "secret": false, "description": "The exception(s) to catch." },
     "onWhen": { "index": 4, "kind": "element", "displayName": "On When", "required": false, "type": "object", "javaType": "org.apache.camel.model.WhenDefinition", "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "description": "Sets an additional predicate that should be true before the onCatch is triggered. To be used for fine grained controlling whether a thrown exception should be intercepted by this exception type or not." },
-    "outputs": { "index": 5, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 5, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/doFinally.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/doFinally.json
index 05f4ea4d452..6eef88af181 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/doFinally.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/doFinally.json
@@ -15,6 +15,6 @@
     "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
-    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/doTry.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/doTry.json
index fa84687ca13..8ac3754360d 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/doTry.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/doTry.json
@@ -15,6 +15,6 @@
     "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
-    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/filter.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/filter.json
index 4b1dddcdf38..13eb266ab0d 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/filter.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/filter.json
@@ -17,6 +17,6 @@
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "expression": { "index": 3, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "java", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "sec [...]
     "statusPropertyName": { "index": 4, "kind": "attribute", "displayName": "Status Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of exchange property to use for storing the status of the filtering. Setting this allows to know if the filter predicate evaluated as true or false." },
-    "outputs": { "index": 5, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
+    "outputs": { "index": 5, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/idempotentConsumer.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/idempotentConsumer.json
index 468380ca51f..149004e15b2 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/idempotentConsumer.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/idempotentConsumer.json
@@ -21,6 +21,6 @@
     "completionEager": { "index": 6, "kind": "attribute", "displayName": "Completion Eager", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Sets whether to complete the idempotent consumer eager or when the exchange is done. If this option is true to complete eager, then the idempotent consumer will trigger its completion when the exchange reached  [...]
     "skipDuplicate": { "index": 7, "kind": "attribute", "displayName": "Skip Duplicate", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Sets whether to skip duplicates or not. The default behavior is to skip duplicates. A duplicate message would have the Exchange property org.apache.camel.Exchange#DUPLICATE_MESSAGE set to a Boolean#TRUE value. A non [...]
     "removeOnFailure": { "index": 8, "kind": "attribute", "displayName": "Remove On Failure", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Sets whether to remove or keep the key on failure. The default behavior is to remove the key on failure." },
-    "outputs": { "index": 9, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
+    "outputs": { "index": 9, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/intercept.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/intercept.json
index 674e1c33bac..e1063c592b5 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/intercept.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/intercept.json
@@ -15,6 +15,6 @@
     "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
-    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/interceptFrom.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/interceptFrom.json
index 725c74df389..2d90e3a6be8 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/interceptFrom.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/interceptFrom.json
@@ -16,6 +16,6 @@
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "uri": { "index": 3, "kind": "attribute", "displayName": "Uri", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Intercept incoming messages from the uri or uri pattern. If this option is not configured, then all incoming messages is intercepted." },
-    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/interceptSendToEndpoint.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/interceptSendToEndpoint.json
index 4574c9902c2..d2163bf0f37 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/interceptSendToEndpoint.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/interceptSendToEndpoint.json
@@ -18,6 +18,6 @@
     "uri": { "index": 3, "kind": "attribute", "displayName": "Uri", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Intercept sending to the uri or uri pattern." },
     "skipSendToOriginalEndpoint": { "index": 4, "kind": "attribute", "displayName": "Skip Send To Original Endpoint", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "If set to true then the message is not sent to the original endpoint. By default (false) the message is both intercepted and then sent to the original endpoint." },
     "afterUri": { "index": 5, "kind": "attribute", "displayName": "After Uri", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "After sending to the endpoint then send the message to this uri which allows to process its result." },
-    "outputs": { "index": 6, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 6, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/kamelet.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/kamelet.json
index d37e1c7c9a9..4bcc06c5bd0 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/kamelet.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/kamelet.json
@@ -16,6 +16,6 @@
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "name": { "index": 3, "kind": "attribute", "displayName": "Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of the Kamelet (templateId\/routeId) to call. Options for the kamelet can be specified using uri syntax, eg mynamecount=4&type=gold." },
-    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/loadBalance.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/loadBalance.json
index f5d8693cf4d..06f242f0554 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/loadBalance.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/loadBalance.json
@@ -16,7 +16,7 @@
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "loadBalancerType": { "index": 3, "kind": "element", "displayName": "Load Balancer Type", "required": true, "type": "object", "javaType": "org.apache.camel.model.LoadBalancerDefinition", "oneOf": [ "customLoadBalancer", "failover", "random", "roundRobin", "sticky", "topic", "weighted" ], "deprecated": false, "autowired": false, "secret": false, "description": "The load balancer to be used" },
-    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
     "inheritErrorHandler": { "index": 5, "kind": "attribute", "displayName": "Inherit Error Handler", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Sets whether or not to inherit the configured error handler. The default value is true. You can use this to disable using the inherited error handler for a given DSL such as a load balancer where you want to use a custom e [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/loop.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/loop.json
index 9eda3d0f43a..24ad0a7819a 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/loop.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/loop.json
@@ -19,6 +19,6 @@
     "copy": { "index": 4, "kind": "attribute", "displayName": "Copy", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If the copy attribute is true, a copy of the input Exchange is used for each iteration. That means each iteration will start from a copy of the same message. By default loop will loop the same exchange all over, so each iteration may [...]
     "doWhile": { "index": 5, "kind": "attribute", "displayName": "Do While", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enables the while loop that loops until the predicate evaluates to false or null." },
     "breakOnShutdown": { "index": 6, "kind": "attribute", "displayName": "Break On Shutdown", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If the breakOnShutdown attribute is true, then the loop will not iterate until it reaches the end when Camel is shut down." },
-    "outputs": { "index": 7, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
+    "outputs": { "index": 7, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/multicast.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/multicast.json
index 05b82097c68..6c6abaf464d 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/multicast.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/multicast.json
@@ -27,6 +27,6 @@
     "executorService": { "index": 12, "kind": "attribute", "displayName": "Executor Service", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.concurrent.ExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "Refers to a custom Thread Pool to be used for parallel processing. Notice if you set this option, then parallel processing is automatic implied, and you do not have to enable that option as well." },
     "onPrepare": { "index": 13, "kind": "attribute", "displayName": "On Prepare", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.Processor", "deprecated": false, "autowired": false, "secret": false, "description": "Uses the Processor when preparing the org.apache.camel.Exchange to be send. This can be used to deep-clone messages that should be send, or any custom logic needed before the exchange is send." },
     "shareUnitOfWork": { "index": 14, "kind": "attribute", "displayName": "Share Unit Of Work", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Shares the org.apache.camel.spi.UnitOfWork with the parent and each of the sub messages. Multicast will by default not share unit of work between the parent exchange and each multicasted exchange. This means [...]
-    "outputs": { "index": 15, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
+    "outputs": { "index": 15, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onCompletion.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onCompletion.json
index 48798e63088..0e4b42cfeec 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onCompletion.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onCompletion.json
@@ -22,6 +22,6 @@
     "executorService": { "index": 7, "kind": "attribute", "displayName": "Executor Service", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.concurrent.ExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom Thread Pool to be used for parallel processing. Notice if you set this option, then parallel processing is automatic implied, and you do not have to enable that option as well." },
     "useOriginalMessage": { "index": 8, "kind": "attribute", "displayName": "Use Original Message", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Will use the original input message body when an org.apache.camel.Exchange for this on completion. The original input message is defensively copied, and the copied message body is converted to org.apache [...]
     "onWhen": { "index": 9, "kind": "element", "displayName": "On When", "required": false, "type": "object", "javaType": "org.apache.camel.model.WhenDefinition", "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "description": "Sets an additional predicate that should be true before the onCompletion is triggered. To be used for fine grained controlling whether a completion callback should be invoked or not" },
-    "outputs": { "index": 10, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
+    "outputs": { "index": 10, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onException.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onException.json
index f1053577e6c..6de27e20851 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onException.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onException.json
@@ -26,6 +26,6 @@
     "onExceptionOccurredRef": { "index": 11, "kind": "attribute", "displayName": "On Exception Occurred Ref", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets a reference to a processor that should be processed just after an exception occurred. Can be used to perform custom logging about the occurred exception at the exact time it happened. Important: Any exception thro [...]
     "useOriginalMessage": { "index": 12, "kind": "attribute", "displayName": "Use Original Message", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Will use the original input org.apache.camel.Message (original body and headers) when an org.apache.camel.Exchange is moved to the dead letter queue. Notice: this only applies when all redeliveries atte [...]
     "useOriginalBody": { "index": 13, "kind": "attribute", "displayName": "Use Original Body", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Will use the original input org.apache.camel.Message body (original body only) when an org.apache.camel.Exchange is moved to the dead letter queue. Notice: this only applies when all redeliveries attempt have [...]
-    "outputs": { "index": 14, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
+    "outputs": { "index": 14, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onFallback.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onFallback.json
index bc5f671fd1b..1c1774c10a9 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onFallback.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onFallback.json
@@ -16,6 +16,6 @@
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "fallbackViaNetwork": { "index": 3, "kind": "attribute", "displayName": "Fallback Via Network", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the fallback goes over the network. If the fallback will go over the network it is another possible point of failure. It is important to execute the fallback command on a separate thread-pool, ot [...]
-    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
+    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/otherwise.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/otherwise.json
index 5b7ec14f5e4..cce4b703fe8 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/otherwise.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/otherwise.json
@@ -15,6 +15,6 @@
     "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
-    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/pipeline.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/pipeline.json
index 021a97f2224..85ccd199df1 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/pipeline.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/pipeline.json
@@ -15,6 +15,6 @@
     "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
-    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/removeVariable.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/removeVariable.json
new file mode 100644
index 00000000000..b5e9748bb20
--- /dev/null
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/removeVariable.json
@@ -0,0 +1,20 @@
+{
+  "model": {
+    "kind": "model",
+    "name": "removeVariable",
+    "title": "Remove Variable",
+    "description": "Removes a named variable",
+    "deprecated": false,
+    "label": "eip,transformation",
+    "javaType": "org.apache.camel.model.RemoveVariableDefinition",
+    "abstract": false,
+    "input": true,
+    "output": false
+  },
+  "properties": {
+    "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
+    "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
+    "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
+    "name": { "index": 3, "kind": "attribute", "displayName": "Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to remove." }
+  }
+}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/resequence.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/resequence.json
index 32332a238c4..4a12cdfaffe 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/resequence.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/resequence.json
@@ -17,6 +17,6 @@
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "expression": { "index": 3, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "java", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "sec [...]
     "resequencerConfig": { "index": 4, "kind": "element", "displayName": "Resequencer Config", "required": true, "type": "object", "javaType": "org.apache.camel.model.config.ResequencerConfig", "oneOf": [ "batchConfig", "streamConfig" ], "deprecated": false, "autowired": false, "secret": false, "description": "To configure the resequencer in using either batch or stream configuration. Will by default use batch configuration." },
-    "outputs": { "index": 5, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 5, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/route.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/route.json
index e1971051b24..d4b9c4b06b2 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/route.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/route.json
@@ -32,6 +32,6 @@
     "inputType": { "index": 17, "kind": "element", "displayName": "Input Type", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.InputTypeDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Declare the expected data type of the input message. If the actual message type is different at runtime, camel look for a required org.apache.camel.spi.Transformer and apply if exists. The type name consists of two parts,  [...]
     "outputType": { "index": 18, "kind": "element", "displayName": "Output Type", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.OutputTypeDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Declare the expected data type of the output message. If the actual message type is different at runtime, camel look for a required org.apache.camel.spi.Transformer and apply if exists. The type name consists of two par [...]
     "input": { "index": 19, "kind": "element", "displayName": "Input", "required": true, "type": "object", "javaType": "org.apache.camel.model.FromDefinition", "oneOf": [ "from" ], "deprecated": false, "autowired": false, "secret": false, "description": "Input to the route." },
-    "outputs": { "index": 20, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<?>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loo [...]
+    "outputs": { "index": 20, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<?>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loo [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/saga.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/saga.json
index 81221edf12c..2503f7defe6 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/saga.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/saga.json
@@ -22,6 +22,6 @@
     "compensation": { "index": 7, "kind": "element", "displayName": "Compensation", "required": false, "type": "object", "javaType": "org.apache.camel.model.SagaActionUriDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "The compensation endpoint URI that must be called to compensate all changes done in the route. The route corresponding to the compensation URI must perform compensation and complete without error. If errors occur during compensation, t [...]
     "completion": { "index": 8, "kind": "element", "displayName": "Completion", "required": false, "type": "object", "javaType": "org.apache.camel.model.SagaActionUriDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "The completion endpoint URI that will be called when the Saga is completed successfully. The route corresponding to the completion URI must perform completion tasks and terminate without error. If errors occur during completion, the saga s [...]
     "option": { "index": 9, "kind": "element", "displayName": "Option", "label": "advanced", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.PropertyExpressionDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Allows to save properties of the current exchange in order to re-use them in a compensation\/completion callback route. Options are usually helpful e.g. to store and retrieve identifiers of objects that sho [...]
-    "outputs": { "index": 10, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
+    "outputs": { "index": 10, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/setVariable.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/setVariable.json
new file mode 100644
index 00000000000..727ca75bd3b
--- /dev/null
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/setVariable.json
@@ -0,0 +1,21 @@
+{
+  "model": {
+    "kind": "model",
+    "name": "setVariable",
+    "title": "Set Variable",
+    "description": "Sets the value of a variable",
+    "deprecated": false,
+    "label": "eip,transformation",
+    "javaType": "org.apache.camel.model.SetVariableDefinition",
+    "abstract": false,
+    "input": true,
+    "output": false
+  },
+  "properties": {
+    "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
+    "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
+    "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
+    "name": { "index": 3, "kind": "attribute", "displayName": "Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to set a new value The simple language can be used to define a dynamic evaluated variable name to be used. Otherwise a constant name will be used." },
+    "expression": { "index": 4, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "java", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "sec [...]
+  }
+}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/split.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/split.json
index 63c0043e17e..395a1cb544a 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/split.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/split.json
@@ -29,6 +29,6 @@
     "executorService": { "index": 14, "kind": "attribute", "displayName": "Executor Service", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.concurrent.ExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom Thread Pool to be used for parallel processing. Notice if you set this option, then parallel processing is automatically implied, and you do not have to enable that option as well." },
     "onPrepare": { "index": 15, "kind": "attribute", "displayName": "On Prepare", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.Processor", "deprecated": false, "autowired": false, "secret": false, "description": "Uses the Processor when preparing the org.apache.camel.Exchange to be sent. This can be used to deep-clone messages that should be sent, or any custom logic needed before the exchange is sent." },
     "shareUnitOfWork": { "index": 16, "kind": "attribute", "displayName": "Share Unit Of Work", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Shares the org.apache.camel.spi.UnitOfWork with the parent and each of the sub messages. Splitter will by default not share unit of work between the parent exchange and each split exchange. This means each s [...]
-    "outputs": { "index": 17, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalanc [...]
+    "outputs": { "index": 17, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalanc [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/step.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/step.json
index 0ffc6be4510..2d47cf3b901 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/step.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/step.json
@@ -15,6 +15,6 @@
     "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
-    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/when.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/when.json
index bff35777dd3..c9278a4adae 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/when.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/when.json
@@ -16,6 +16,6 @@
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "expression": { "index": 3, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "java", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "sec [...]
-    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
+    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/whenSkipSendToEndpoint.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/whenSkipSendToEndpoint.json
index 0486ebb5f37..61cd7cd5fe9 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/whenSkipSendToEndpoint.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/whenSkipSendToEndpoint.json
@@ -16,6 +16,6 @@
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "expression": { "index": 3, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "java", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "sec [...]
-    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
+    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
index 938afd7e95e..ce99aff5108 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
@@ -1279,6 +1279,15 @@ Removes message exchange properties whose name matches a specified pattern
       <xs:documentation xml:lang="en">
 <![CDATA[
 Removes a named property from the message exchange
+]]>
+      </xs:documentation>
+    </xs:annotation>
+  </xs:element>
+  <xs:element name="removeVariable" type="tns:removeVariableDefinition">
+    <xs:annotation>
+      <xs:documentation xml:lang="en">
+<![CDATA[
+Removes a named variable
 ]]>
       </xs:documentation>
     </xs:annotation>
@@ -1703,6 +1712,15 @@ Allows to set multiple headers on the message at the same time.
       <xs:documentation xml:lang="en">
 <![CDATA[
 Sets a named property on the message exchange
+]]>
+      </xs:documentation>
+    </xs:annotation>
+  </xs:element>
+  <xs:element name="setVariable" type="tns:setVariableDefinition">
+    <xs:annotation>
+      <xs:documentation xml:lang="en">
+<![CDATA[
+Sets the value of a variable
 ]]>
       </xs:documentation>
     </xs:annotation>
@@ -3506,6 +3524,7 @@ will fallback to use the fixed value if the Expression result was null or 0.
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -3519,6 +3538,7 @@ will fallback to use the fixed value if the Expression result was null or 0.
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -4065,6 +4085,7 @@ controlling whether a thrown exception should be intercepted by this exception t
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -4078,6 +4099,7 @@ controlling whether a thrown exception should be intercepted by this exception t
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -4169,6 +4191,7 @@ controlling whether a thrown exception should be intercepted by this exception t
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -4182,6 +4205,7 @@ controlling whether a thrown exception should be intercepted by this exception t
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -4266,6 +4290,7 @@ during startup to keep at runtime only the branch that matched. Default value: f
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -4279,6 +4304,7 @@ during startup to keep at runtime only the branch that matched. Default value: f
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -4346,6 +4372,7 @@ during startup to keep at runtime only the branch that matched. Default value: f
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -4359,6 +4386,7 @@ during startup to keep at runtime only the branch that matched. Default value: f
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -4793,6 +4821,7 @@ References to a custom thread pool to use when bulkhead is enabled.
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -4806,6 +4835,7 @@ References to a custom thread pool to use when bulkhead is enabled.
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -5843,6 +5873,7 @@ Sets the logging level to use for logging transactional rollback. This option is
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -5856,6 +5887,7 @@ Sets the logging level to use for logging transactional rollback. This option is
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -5930,6 +5962,7 @@ predicate evaluated as true or false.
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -5943,6 +5976,7 @@ predicate evaluated as true or false.
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -6076,6 +6110,7 @@ Global option value.
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -6089,6 +6124,7 @@ Global option value.
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -6233,6 +6269,7 @@ Whether if validation is required for this input type. Default value: false
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -6246,6 +6283,7 @@ Whether if validation is required for this input type. Default value: false
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -6327,6 +6365,7 @@ intercepted.
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -6340,6 +6379,7 @@ intercepted.
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -6432,6 +6472,7 @@ After sending to the endpoint then send the message to this uri which allows to
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -6445,6 +6486,7 @@ After sending to the endpoint then send the message to this uri which allows to
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -6528,6 +6570,7 @@ mynamecount=4&type=gold.
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -6541,6 +6584,7 @@ mynamecount=4&type=gold.
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -6836,6 +6880,7 @@ To refer to a custom logger instance to lookup from the registry.
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -6849,6 +6894,7 @@ To refer to a custom logger instance to lookup from the registry.
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -10133,6 +10179,7 @@ maximum decompressed size. Default value: 1073741824
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -10146,6 +10193,7 @@ maximum decompressed size. Default value: 1073741824
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -10353,6 +10401,7 @@ controlling whether a completion callback should be invoked or not.
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -10366,6 +10415,7 @@ controlling whether a completion callback should be invoked or not.
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -10548,6 +10598,7 @@ its considered handled as well.
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -10561,6 +10612,7 @@ its considered handled as well.
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -10803,6 +10855,7 @@ one of the available events. Implementations should not assume the predicate to
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -10816,6 +10869,7 @@ one of the available events. Implementations should not assume the predicate to
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -10880,6 +10934,7 @@ one of the available events. Implementations should not assume the predicate to
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -10893,6 +10948,7 @@ one of the available events. Implementations should not assume the predicate to
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -11389,6 +11445,22 @@ Name or pattern of properties to not remove. The pattern is matched in the follo
             <xs:documentation xml:lang="en">
 <![CDATA[
 Name of property to remove.
+]]>
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="removeVariableDefinition">
+    <xs:complexContent>
+      <xs:extension base="tns:noOutputDefinition">
+        <xs:sequence/>
+        <xs:attribute name="name" type="xs:string" use="required">
+          <xs:annotation>
+            <xs:documentation xml:lang="en">
+<![CDATA[
+Name of variable to remove.
 ]]>
             </xs:documentation>
           </xs:annotation>
@@ -11470,6 +11542,7 @@ Name of property to remove.
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -11483,6 +11556,7 @@ Name of property to remove.
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -11815,6 +11889,7 @@ Reference to the routes in the xml dsl.
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -11828,6 +11903,7 @@ Reference to the routes in the xml dsl.
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -12245,6 +12321,7 @@ actions. Option values will be transformed into input headers of the compensatio
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -12258,6 +12335,7 @@ actions. Option values will be transformed into input headers of the compensatio
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -12514,6 +12592,49 @@ be used. Otherwise a constant name will be used.
 <![CDATA[
 Name of exchange property to set a new value. The simple language can be used to define a dynamic evaluated exchange
 property name to be used. Otherwise a constant name will be used.
+]]>
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="setVariableDefinition">
+    <xs:complexContent>
+      <xs:extension base="tns:processorDefinition">
+        <xs:choice>
+          <xs:element ref="tns:expressionDefinition"/>
+          <xs:element ref="tns:csimple"/>
+          <xs:element ref="tns:constant"/>
+          <xs:element ref="tns:datasonnet"/>
+          <xs:element ref="tns:exchangeProperty"/>
+          <xs:element ref="tns:groovy"/>
+          <xs:element ref="tns:header"/>
+          <xs:element ref="tns:hl7terser"/>
+          <xs:element ref="tns:java"/>
+          <xs:element ref="tns:js"/>
+          <xs:element ref="tns:joor"/>
+          <xs:element ref="tns:jq"/>
+          <xs:element ref="tns:jsonpath"/>
+          <xs:element ref="tns:language"/>
+          <xs:element ref="tns:method"/>
+          <xs:element ref="tns:mvel"/>
+          <xs:element ref="tns:ognl"/>
+          <xs:element ref="tns:python"/>
+          <xs:element ref="tns:ref"/>
+          <xs:element ref="tns:simple"/>
+          <xs:element ref="tns:spel"/>
+          <xs:element ref="tns:tokenize"/>
+          <xs:element ref="tns:xtokenize"/>
+          <xs:element ref="tns:xpath"/>
+          <xs:element ref="tns:xquery"/>
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string" use="required">
+          <xs:annotation>
+            <xs:documentation xml:lang="en">
+<![CDATA[
+Name of variable to set a new value The simple language can be used to define a dynamic evaluated variable name to be
+used. Otherwise a constant name will be used.
 ]]>
             </xs:documentation>
           </xs:annotation>
@@ -12633,6 +12754,7 @@ Sets the comparator to use for sorting.
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -12646,6 +12768,7 @@ Sets the comparator to use for sorting.
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -12860,6 +12983,7 @@ individual unit of work. Default value: false
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -12873,6 +12997,7 @@ individual unit of work. Default value: false
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -13413,6 +13538,7 @@ Whether to auto startup components when toD is starting up. Default value: true
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -13426,6 +13552,7 @@ Whether to auto startup components when toD is starting up. Default value: true
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
@@ -13550,6 +13677,7 @@ To type used as a target data type in the transformation.
             <xs:element ref="tns:removeHeaders"/>
             <xs:element ref="tns:removeProperties"/>
             <xs:element ref="tns:removeProperty"/>
+            <xs:element ref="tns:removeVariable"/>
             <xs:element ref="tns:resequence"/>
             <xs:element ref="tns:resumable"/>
             <xs:element ref="tns:rollback"/>
@@ -13563,6 +13691,7 @@ To type used as a target data type in the transformation.
             <xs:element ref="tns:setHeader"/>
             <xs:element ref="tns:setHeaders"/>
             <xs:element ref="tns:setProperty"/>
+            <xs:element ref="tns:setVariable"/>
             <xs:element ref="tns:sort"/>
             <xs:element ref="tns:split"/>
             <xs:element ref="tns:step"/>
diff --git a/components/camel-bean/src/main/docs/bean-language.adoc b/components/camel-bean/src/main/docs/bean-language.adoc
index 85996a113ab..f7138e4e5ce 100644
--- a/components/camel-bean/src/main/docs/bean-language.adoc
+++ b/components/camel-bean/src/main/docs/bean-language.adoc
@@ -76,7 +76,7 @@ public boolean isGoldCustomer(String body) {...}
 === Using Annotations for bean integration
 
 You can also use the xref:manual::bean-integration.adoc[Bean Integration]
-annotations, such as `@Header`, `@Body` etc
+annotations, such as `@Header`, `@Body`, `@Variable` etc
 
 [source,java]
 ----
diff --git a/components/camel-bean/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java b/components/camel-bean/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java
index b7cc688765e..4cd04ab2b37 100644
--- a/components/camel-bean/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java
+++ b/components/camel-bean/src/main/java/org/apache/camel/component/bean/AbstractCamelInvocationHandler.java
@@ -43,6 +43,8 @@ import org.apache.camel.Headers;
 import org.apache.camel.InvalidPayloadException;
 import org.apache.camel.Producer;
 import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.Variable;
+import org.apache.camel.Variables;
 import org.apache.camel.support.DefaultExchange;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.StringHelper;
@@ -109,6 +111,8 @@ public abstract class AbstractCamelInvocationHandler implements InvocationHandle
             for (Parameter parameter : method.getParameters()) {
                 if (parameter.isAnnotationPresent(Header.class)
                         || parameter.isAnnotationPresent(Headers.class)
+                        || parameter.isAnnotationPresent(Variable.class)
+                        || parameter.isAnnotationPresent(Variables.class)
                         || parameter.isAnnotationPresent(ExchangeProperty.class)
                         || parameter.isAnnotationPresent(Body.class)) {
                     canUseBinding = true;
@@ -139,6 +143,16 @@ public abstract class AbstractCamelInvocationHandler implements InvocationHandle
                             if (map != null) {
                                 exchange.getIn().getHeaders().putAll(map);
                             }
+                        } else if (ann.annotationType().isAssignableFrom(Variable.class)) {
+                            Variable variable = (Variable) ann;
+                            String name = variable.value();
+                            exchange.setVariable(name, value);
+                        } else if (ann.annotationType().isAssignableFrom(Variables.class)) {
+                            Map<String, Object> map
+                                    = exchange.getContext().getTypeConverter().tryConvertTo(Map.class, exchange, value);
+                            if (map != null) {
+                                exchange.getVariables().putAll(map);
+                            }
                         } else if (ann.annotationType().isAssignableFrom(ExchangeProperty.class)) {
                             ExchangeProperty ep = (ExchangeProperty) ann;
                             String name = ep.value();
diff --git a/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java b/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java
index 5e0a27b908f..99b646dcaa3 100644
--- a/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java
+++ b/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java
@@ -42,6 +42,8 @@ import org.apache.camel.Header;
 import org.apache.camel.Headers;
 import org.apache.camel.Message;
 import org.apache.camel.PropertyInject;
+import org.apache.camel.Variable;
+import org.apache.camel.Variables;
 import org.apache.camel.support.ObjectHelper;
 import org.apache.camel.support.builder.ExpressionBuilder;
 import org.apache.camel.support.language.AnnotationExpressionFactory;
@@ -1012,6 +1014,11 @@ public class BeanInfo {
             return ExpressionBuilder.headerExpression(headerAnnotation.value());
         } else if (annotation instanceof Headers) {
             return ExpressionBuilder.headersExpression();
+        } else if (annotation instanceof Variable) {
+            Variable variableAnnotation = (Variable) annotation;
+            return ExpressionBuilder.variableExpression(variableAnnotation.value());
+        } else if (annotation instanceof Variables) {
+            return ExpressionBuilder.variablesExpression();
         } else if (annotation instanceof ExchangeException) {
             return ExpressionBuilder.exchangeExceptionExpression(CastUtils.cast(parameterType, Exception.class));
         } else if (annotation instanceof PropertyInject) {
diff --git a/components/camel-chunk/src/main/docs/chunk-component.adoc b/components/camel-chunk/src/main/docs/chunk-component.adoc
index 811fdec8bec..56a056fdeec 100644
--- a/components/camel-chunk/src/main/docs/chunk-component.adoc
+++ b/components/camel-chunk/src/main/docs/chunk-component.adoc
@@ -66,6 +66,8 @@ a `Map`). The `Exchange` is transferred as:
 
 |`exchange.properties` |The `Exchange` properties.
 
+|`variables` |The variables
+
 |`headers` |The headers of the In message.
 
 |`camelContext` |The Camel Context.
diff --git a/components/camel-freemarker/src/main/docs/freemarker-component.adoc b/components/camel-freemarker/src/main/docs/freemarker-component.adoc
index f7e9a5fbf83..675b5ed4c78 100644
--- a/components/camel-freemarker/src/main/docs/freemarker-component.adoc
+++ b/components/camel-freemarker/src/main/docs/freemarker-component.adoc
@@ -83,6 +83,8 @@ a `Map`). The `Exchange` is transferred as:
 
 |`exchange.properties` |The `Exchange` properties.
 
+|`variables` |The variables
+
 |`headers` |The headers of the In message.
 
 |`camelContext` |The Camel Context.
diff --git a/components/camel-jslt/src/main/docs/jslt-component.adoc b/components/camel-jslt/src/main/docs/jslt-component.adoc
index c848ce745e4..78cd3e0b397 100644
--- a/components/camel-jslt/src/main/docs/jslt-component.adoc
+++ b/components/camel-jslt/src/main/docs/jslt-component.adoc
@@ -67,6 +67,7 @@ Camel can supply exchange information as variables when applying a JSLT expressi
 |===
 | name | value
 | headers | The headers of the In message as a json object
+| variables |The variables
 | exchange.properties | The *Exchange* properties as a json object. _exchange_ is the name of the variable and _properties_ is the path to the exchange properties. Available if _allowContextMapAll_ option is true.
 |===
 
diff --git a/components/camel-jslt/src/main/java/org/apache/camel/component/jslt/JsltEndpoint.java b/components/camel-jslt/src/main/java/org/apache/camel/component/jslt/JsltEndpoint.java
index 281710c173c..0c7e99f1e15 100644
--- a/components/camel-jslt/src/main/java/org/apache/camel/component/jslt/JsltEndpoint.java
+++ b/components/camel-jslt/src/main/java/org/apache/camel/component/jslt/JsltEndpoint.java
@@ -231,6 +231,9 @@ public class JsltEndpoint extends ResourceEndpoint {
         if (variableMap.containsKey("headers")) {
             serializedVariableMap.put("headers", serializeMapToJsonNode((Map<String, Object>) variableMap.get("headers")));
         }
+        if (variableMap.containsKey("variables")) {
+            serializedVariableMap.put("variables", serializeMapToJsonNode((Map<String, Object>) variableMap.get("variables")));
+        }
         if (variableMap.containsKey("exchange")) {
             Exchange ex = (Exchange) variableMap.get("exchange");
             ObjectNode exchangeNode = OBJECT_MAPPER.createObjectNode();
diff --git a/components/camel-log/src/generated/java/org/apache/camel/component/log/LogEndpointConfigurer.java b/components/camel-log/src/generated/java/org/apache/camel/component/log/LogEndpointConfigurer.java
index dc4d54ae626..c7588165c03 100644
--- a/components/camel-log/src/generated/java/org/apache/camel/component/log/LogEndpointConfigurer.java
+++ b/components/camel-log/src/generated/java/org/apache/camel/component/log/LogEndpointConfigurer.java
@@ -75,6 +75,8 @@ public class LogEndpointConfigurer extends PropertyConfigurerSupport implements
         case "showStackTrace": target.setShowStackTrace(property(camelContext, boolean.class, value)); return true;
         case "showstreams":
         case "showStreams": target.setShowStreams(property(camelContext, boolean.class, value)); return true;
+        case "showvariables":
+        case "showVariables": target.setShowVariables(property(camelContext, boolean.class, value)); return true;
         case "skipbodylineseparator":
         case "skipBodyLineSeparator": target.setSkipBodyLineSeparator(property(camelContext, boolean.class, value)); return true;
         case "sourcelocationloggername":
@@ -141,6 +143,8 @@ public class LogEndpointConfigurer extends PropertyConfigurerSupport implements
         case "showStackTrace": return boolean.class;
         case "showstreams":
         case "showStreams": return boolean.class;
+        case "showvariables":
+        case "showVariables": return boolean.class;
         case "skipbodylineseparator":
         case "skipBodyLineSeparator": return boolean.class;
         case "sourcelocationloggername":
@@ -208,6 +212,8 @@ public class LogEndpointConfigurer extends PropertyConfigurerSupport implements
         case "showStackTrace": return target.isShowStackTrace();
         case "showstreams":
         case "showStreams": return target.isShowStreams();
+        case "showvariables":
+        case "showVariables": return target.isShowVariables();
         case "skipbodylineseparator":
         case "skipBodyLineSeparator": return target.isSkipBodyLineSeparator();
         case "sourcelocationloggername":
diff --git a/components/camel-log/src/generated/java/org/apache/camel/component/log/LogEndpointUriFactory.java b/components/camel-log/src/generated/java/org/apache/camel/component/log/LogEndpointUriFactory.java
index dd892a15624..b263d4463c1 100644
--- a/components/camel-log/src/generated/java/org/apache/camel/component/log/LogEndpointUriFactory.java
+++ b/components/camel-log/src/generated/java/org/apache/camel/component/log/LogEndpointUriFactory.java
@@ -21,7 +21,7 @@ public class LogEndpointUriFactory extends org.apache.camel.support.component.En
     private static final Set<String> SECRET_PROPERTY_NAMES;
     private static final Set<String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(33);
+        Set<String> props = new HashSet<>(34);
         props.add("exchangeFormatter");
         props.add("groupActiveOnly");
         props.add("groupDelay");
@@ -52,6 +52,7 @@ public class LogEndpointUriFactory extends org.apache.camel.support.component.En
         props.add("showRouteId");
         props.add("showStackTrace");
         props.add("showStreams");
+        props.add("showVariables");
         props.add("skipBodyLineSeparator");
         props.add("sourceLocationLoggerName");
         props.add("style");
diff --git a/components/camel-log/src/generated/resources/org/apache/camel/component/log/log.json b/components/camel-log/src/generated/resources/org/apache/camel/component/log/log.json
index 26bebc29b44..64f0087f0e7 100644
--- a/components/camel-log/src/generated/resources/org/apache/camel/component/log/log.json
+++ b/components/camel-log/src/generated/resources/org/apache/camel/component/log/log.json
@@ -60,7 +60,8 @@
     "showRouteId": { "index": 28, "kind": "parameter", "displayName": "Show Route Id", "group": "formatting", "label": "formatting", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Show route ID." },
     "showStackTrace": { "index": 29, "kind": "parameter", "displayName": "Show Stack Trace", "group": "formatting", "label": "formatting", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Show the stack trace, if an exchange has an exception. Only effective if one of showAll, showException or showCaughtException are enabled." },
     "showStreams": { "index": 30, "kind": "parameter", "displayName": "Show Streams", "group": "formatting", "label": "formatting", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether Camel should show stream bodies or not (eg such as java.io.InputStream). Beware if you enable this option then you may not be able later to access the message body as the stream have already bee [...]
-    "skipBodyLineSeparator": { "index": 31, "kind": "parameter", "displayName": "Skip Body Line Separator", "group": "formatting", "label": "formatting", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to skip line separators when logging the message body. This allows to log the message body in one line, setting this option to false will preserve any line separators from t [...]
-    "style": { "index": 32, "kind": "parameter", "displayName": "Style", "group": "formatting", "label": "formatting", "required": false, "type": "object", "javaType": "org.apache.camel.support.processor.DefaultExchangeFormatter.OutputStyle", "enum": [ "Default", "Tab", "Fixed" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "Default", "description": "Sets the outputs style to use." }
+    "showVariables": { "index": 31, "kind": "parameter", "displayName": "Show Variables", "group": "formatting", "label": "formatting", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Show the variables." },
+    "skipBodyLineSeparator": { "index": 32, "kind": "parameter", "displayName": "Skip Body Line Separator", "group": "formatting", "label": "formatting", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to skip line separators when logging the message body. This allows to log the message body in one line, setting this option to false will preserve any line separators from t [...]
+    "style": { "index": 33, "kind": "parameter", "displayName": "Style", "group": "formatting", "label": "formatting", "required": false, "type": "object", "javaType": "org.apache.camel.support.processor.DefaultExchangeFormatter.OutputStyle", "enum": [ "Default", "Tab", "Fixed" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "Default", "description": "Sets the outputs style to use." }
   }
 }
diff --git a/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java b/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java
index 8f12cd45f43..f0e2d508cb9 100644
--- a/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java
+++ b/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java
@@ -87,6 +87,8 @@ public class LogEndpoint extends ProcessorEndpoint implements LineNumberAware {
     private boolean showProperties;
     @UriParam(label = "formatting", description = "Show all of the exchange properties (both internal and custom).")
     private boolean showAllProperties;
+    @UriParam(label = "formatting", description = "Show the variables.")
+    private boolean showVariables;
     @UriParam(label = "formatting", description = "Show the message headers.")
     private boolean showHeaders;
     @UriParam(label = "formatting", defaultValue = "true",
@@ -163,7 +165,7 @@ public class LogEndpoint extends ProcessorEndpoint implements LineNumberAware {
             boolean changed = showExchangePattern || !skipBodyLineSeparator || !showBody || !showBodyType || maxChars != 10000
                     || style != DefaultExchangeFormatter.OutputStyle.Default || plain;
             changed |= showRouteId || showRouteGroup;
-            changed |= showExchangeId || showProperties || showAllProperties || showHeaders || showException
+            changed |= showExchangeId || showProperties || showAllProperties || showVariables || showHeaders || showException
                     || showCaughtException
                     || showStackTrace;
             changed |= showAll || multiline || showFuture || !showCachedStreams || showStreams || showFiles;
@@ -183,6 +185,7 @@ public class LogEndpoint extends ProcessorEndpoint implements LineNumberAware {
                 def.setShowFiles(showFiles);
                 def.setShowFuture(showFuture);
                 def.setShowHeaders(showHeaders);
+                def.setShowVariables(showVariables);
                 def.setShowProperties(showProperties);
                 def.setShowAllProperties(showAllProperties);
                 def.setShowStackTrace(showStackTrace);
@@ -495,6 +498,14 @@ public class LogEndpoint extends ProcessorEndpoint implements LineNumberAware {
         this.showAllProperties = showAllProperties;
     }
 
+    public boolean isShowVariables() {
+        return showVariables;
+    }
+
+    public void setShowVariables(boolean showVariables) {
+        this.showVariables = showVariables;
+    }
+
     public boolean isShowHeaders() {
         return showHeaders;
     }
diff --git a/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java b/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java
index 1d005376211..51e53977bd2 100644
--- a/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java
+++ b/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java
@@ -116,6 +116,7 @@ public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint,
     private volatile Map<String, Object> expectedHeaderValues;
     private volatile Map<String, Object> actualHeaderValues;
     private volatile Map<String, Object> expectedPropertyValues;
+    private volatile Map<String, Object> expectedVariableValues;
 
     private final AtomicInteger counter = new AtomicInteger();
 
@@ -328,6 +329,7 @@ public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint,
         expectedHeaderValues = null;
         actualHeaderValues = null;
         expectedPropertyValues = null;
+        expectedVariableValues = null;
         retainFirst = -1;
         retainLast = -1;
     }
@@ -690,6 +692,94 @@ public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint,
         expectedHeaderValuesReceivedInAnyOrder(name, valueList);
     }
 
+    /**
+     * Sets an expectation that the given variable name & value are received by this endpoint
+     * <p/>
+     * You can set multiple expectations for different variable names. If you set a value of <tt>null</tt> that means we
+     * accept either the variable is absent, or its value is <tt>null</tt>
+     */
+    public void expectedVariableReceived(final String name, final Object value) {
+        if (expectedVariableValues == null) {
+            expectedVariableValues = new HashMap<>();
+        }
+        expectedVariableValues.put(name, value);
+
+        expects(new AssertionTask() {
+            @Override
+            public void assertOnIndex(int i) {
+                Exchange exchange = getReceivedExchange(i);
+                for (Map.Entry<String, Object> entry : expectedVariableValues.entrySet()) {
+                    String key = entry.getKey();
+                    Object expectedValue = entry.getValue();
+
+                    // we accept that an expectedValue of null also means that the variable may be absent
+                    Object actualValue = null;
+                    if (expectedValue != null) {
+                        actualValue = exchange.getVariable(key);
+                        boolean hasKey = actualValue != null;
+                        assertTrue("No variable with name " + key + " found for message: " + i, hasKey);
+                    }
+
+                    actualValue = extractActualValue(exchange, actualValue, expectedValue);
+                    assertEquals("Variable with name " + key + " for message: " + i, expectedValue, actualValue);
+                }
+            }
+
+            public void run() {
+                for (int i = 0; i < getReceivedExchanges().size(); i++) {
+                    assertOnIndex(i);
+                }
+            }
+        });
+    }
+
+    /**
+     * Adds an expectation that this endpoint receives the given variable values in any order.
+     * <p/>
+     * <b>Important:</b> The number of variable must match the expected number of messages, so if you expect 3 messages,
+     * then there must be 3 values.
+     * <p/>
+     * <b>Important:</b> This overrides any previous set value using {@link #expectedMessageCount(int)}
+     */
+    public void expectedVariableValuesReceivedInAnyOrder(final String name, final List<?> values) {
+        expectedMessageCount(values.size());
+
+        expects(() -> {
+            // these are the expected values to find
+            final Set<Object> actualVariableValues = new CopyOnWriteArraySet<>(values);
+
+            for (int i = 0; i < getReceivedExchanges().size(); i++) {
+                Exchange exchange = getReceivedExchange(i);
+
+                Object actualValue = exchange.getVariable(name);
+                for (Object expectedValue : actualVariableValues) {
+                    actualValue = extractActualValue(exchange, actualValue, expectedValue);
+                    // remove any found values
+                    actualVariableValues.remove(actualValue);
+                }
+            }
+
+            // should be empty, as we should find all the values
+            assertTrue("Expected " + values.size() + " variables with key[" + name + "], received "
+                       + (values.size() - actualVariableValues.size())
+                       + " variables. Expected variable values: " + actualVariableValues,
+                    actualVariableValues.isEmpty());
+        });
+    }
+
+    /**
+     * Adds an expectation that this endpoint receives the given variable values in any order
+     * <p/>
+     * <b>Important:</b> The number of values must match the expected number of messages, so if you expect 3 messages,
+     * then there must be 3 values.
+     * <p/>
+     * <b>Important:</b> This overrides any previous set value using {@link #expectedMessageCount(int)}
+     */
+    public void expectedVariableValuesReceivedInAnyOrder(String name, Object... values) {
+        List<Object> valueList = new ArrayList<>(Arrays.asList(values));
+        expectedVariableValuesReceivedInAnyOrder(name, valueList);
+    }
+
     /**
      * Sets an expectation that the given property name & value are received by this endpoint
      * <p/>
diff --git a/components/camel-mustache/src/main/docs/mustache-component.adoc b/components/camel-mustache/src/main/docs/mustache-component.adoc
index 211872f771b..6f4ec3d9c1a 100644
--- a/components/camel-mustache/src/main/docs/mustache-component.adoc
+++ b/components/camel-mustache/src/main/docs/mustache-component.adoc
@@ -69,6 +69,8 @@ Camel will provide exchange information in the Mustache context (just a
 
 |`exchange.properties` |The `Exchange` properties.
 
+|`variables` |The variables
+
 |`headers` |The headers of the In message.
 
 |`camelContext` |The Camel Context.
diff --git a/components/camel-mvel/src/main/docs/mvel-component.adoc b/components/camel-mvel/src/main/docs/mvel-component.adoc
index b9b078d5372..239b603b457 100644
--- a/components/camel-mvel/src/main/docs/mvel-component.adoc
+++ b/components/camel-mvel/src/main/docs/mvel-component.adoc
@@ -65,6 +65,7 @@ Camel will provide exchange information in the MVEL context (just a
 |key |value
 |exchange |The `Exchange` itself
 |exchange.properties |The `Exchange` properties
+|variables |The variables
 |headers |The headers of the message
 |camelContext |The `CamelContext`
 |request |The message
diff --git a/components/camel-robotframework/src/main/java/org/apache/camel/component/robotframework/RobotFrameworkCamelUtils.java b/components/camel-robotframework/src/main/java/org/apache/camel/component/robotframework/RobotFrameworkCamelUtils.java
index 350927f7ab7..d6b6da290f5 100644
--- a/components/camel-robotframework/src/main/java/org/apache/camel/component/robotframework/RobotFrameworkCamelUtils.java
+++ b/components/camel-robotframework/src/main/java/org/apache/camel/component/robotframework/RobotFrameworkCamelUtils.java
@@ -31,6 +31,7 @@ public final class RobotFrameworkCamelUtils {
     private static final String ROBOT_CAMEL_EXCHANGE_NAME = "exchange";
     private static final String ROBOT_VAR_CAMEL_BODY = "body";
     private static final String ROBOT_VAR_CAMEL_HEADERS = "headers";
+    private static final String ROBOT_VAR_CAMEL_VARIABLES = "variables";
     private static final String ROBOT_VAR_CAMEL_PROPERTIES = "properties";
     private static final String ROBOT_VAR_FIELD_SEPERATOR = ":";
     private static final String ROBOT_VAR_NESTING_SEPERATOR = ".";
@@ -57,6 +58,10 @@ public final class RobotFrameworkCamelUtils {
                 createStringValueOfVariablesFromMap(variableKeyValuePairList,
                         ObjectHelper.cast(Map.class, variableEntry.getValue()), exchange, new StringBuilder(),
                         ROBOT_VAR_CAMEL_HEADERS, true);
+            } else if (ROBOT_VAR_CAMEL_VARIABLES.equals(variableEntry.getKey())) {
+                // here the param is the headers map
+                createStringValueOfVariablesFromMap(variableKeyValuePairList, exchange.getVariables(),
+                        exchange, new StringBuilder(), ROBOT_VAR_CAMEL_VARIABLES, true);
             } else if (ROBOT_CAMEL_EXCHANGE_NAME.equals(variableEntry.getKey())) {
                 // here the param is camel exchange
                 createStringValueOfVariablesFromMap(variableKeyValuePairList, exchange.getProperties(),
diff --git a/components/camel-spring-xml/src/test/java/org/apache/camel/spring/processor/SpringSetVariableTest.java b/components/camel-spring-xml/src/test/java/org/apache/camel/spring/processor/SpringSetVariableTest.java
new file mode 100644
index 00000000000..2bb53395621
--- /dev/null
+++ b/components/camel-spring-xml/src/test/java/org/apache/camel/spring/processor/SpringSetVariableTest.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.spring.processor;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.camel.spring.processor.SpringTestHelper.createSpringCamelContext;
+
+public class SpringSetVariableTest extends ContextTestSupport {
+
+    @Test
+    public void testSetVariableWithExpression() throws Exception {
+        MockEndpoint resultEndpoint = getMockEndpoint("mock:b");
+        resultEndpoint.expectedBodiesReceived("World");
+        resultEndpoint.expectedVariableReceived("myVar", "Hello World");
+
+        sendBody("seda:a", "World");
+
+        resultEndpoint.assertIsSatisfied();
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        return createSpringCamelContext(this, "org/apache/camel/spring/processor/SpringSetVariableTest-context.xml");
+    }
+}
diff --git a/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/processor/SpringSetVariableTest-context.xml b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/processor/SpringSetVariableTest-context.xml
new file mode 100644
index 00000000000..dc46a22bc82
--- /dev/null
+++ b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/processor/SpringSetVariableTest-context.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+    ">
+
+  <!-- START SNIPPET: example -->
+  <camelContext xmlns="http://camel.apache.org/schema/spring">
+    <jmxAgent id="jmx" disabled="true"/>
+    <route>
+      <from uri="seda:a"/>
+      <setVariable name="myVar">
+        <simple>Hello ${body}</simple>
+      </setVariable>
+      <to uri="mock:b"/>     
+    </route>
+  </camelContext>
+  <!-- END SNIPPET: example -->
+</beans>
diff --git a/components/camel-stringtemplate/src/main/docs/string-template-component.adoc b/components/camel-stringtemplate/src/main/docs/string-template-component.adoc
index 68afe26140e..ad2dd46388d 100644
--- a/components/camel-stringtemplate/src/main/docs/string-template-component.adoc
+++ b/components/camel-stringtemplate/src/main/docs/string-template-component.adoc
@@ -65,6 +65,32 @@ Camel will store a reference to the resource in the message header with
 key, `org.apache.camel.stringtemplate.resource`. The Resource is an
 `org.springframework.core.io.Resource` object.
 
+== String Template Context
+
+Camel will provide exchange information in the String Template context (just a
+`Map`). The `Exchange` is transferred as:
+
+[width="100%",cols="10%,90%",options="header",]
+|=======================================================================
+|key |value
+
+|`exchange` |The `Exchange` itself.
+
+|`exchange.properties` |The `Exchange` properties.
+
+|`variables` |The variables
+
+|`headers` |The headers of the In message.
+
+|`camelContext` |The Camel Context.
+
+|`request` |The In message.
+
+|`body` |The In message body.
+
+|`response` |The Out message (only for InOut message exchange pattern).
+|=======================================================================
+
 == Hot reloading
 
 The string template resource is by default hot-reloadable for both file
diff --git a/components/camel-thymeleaf/src/generated/resources/org/apache/camel/component/thymeleaf/thymeleaf.json b/components/camel-thymeleaf/src/generated/resources/org/apache/camel/component/thymeleaf/thymeleaf.json
index ca54a5ade49..bcd8df3ac89 100644
--- a/components/camel-thymeleaf/src/generated/resources/org/apache/camel/component/thymeleaf/thymeleaf.json
+++ b/components/camel-thymeleaf/src/generated/resources/org/apache/camel/component/thymeleaf/thymeleaf.json
@@ -39,12 +39,12 @@
     "cacheTimeToLive": { "index": 3, "kind": "parameter", "displayName": "Cache Time To Live", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "description": "The cache Time To Live for templates, expressed in milliseconds." },
     "checkExistence": { "index": 4, "kind": "parameter", "displayName": "Check Existence", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "description": "Whether a template resources will be checked for existence before being returned." },
     "contentCache": { "index": 5, "kind": "parameter", "displayName": "Content Cache", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Sets whether to use resource content cache or not" },
-    "encoding": { "index": 6, "kind": "parameter", "displayName": "Encoding", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The character encoding to be used for reading template resources." },
-    "order": { "index": 7, "kind": "parameter", "displayName": "Order", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "description": "The order in which this template will be resolved as part of the resolver chain." },
-    "prefix": { "index": 8, "kind": "parameter", "displayName": "Prefix", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "An optional prefix added to template names to convert them into resource names." },
-    "resolver": { "index": 9, "kind": "parameter", "displayName": "Resolver", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.thymeleaf.ThymeleafResolverType", "enum": [ "CLASS_LOADER", "DEFAULT", "FILE", "STRING", "URL", "WEB_APP" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "CLASS_LOADER", "description": "The type of resolver to be used by the template engine." },
-    "suffix": { "index": 10, "kind": "parameter", "displayName": "Suffix", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "An optional suffix added to template names to convert them into resource names." },
-    "templateMode": { "index": 11, "kind": "parameter", "displayName": "Template Mode", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The template mode to be applied to templates." },
-    "lazyStartProducer": { "index": 12, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...]
+    "templateMode": { "index": 6, "kind": "parameter", "displayName": "Template Mode", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "enum": [ "HTML", "XML", "TEXT", "JAVASCRIPT", "CSS", "RAW" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "HTML", "description": "The template mode to be applied to templates." },
+    "lazyStartProducer": { "index": 7, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produc [...]
+    "encoding": { "index": 8, "kind": "parameter", "displayName": "Encoding", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The character encoding to be used for reading template resources." },
+    "order": { "index": 9, "kind": "parameter", "displayName": "Order", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "description": "The order in which this template will be resolved as part of the resolver chain." },
+    "prefix": { "index": 10, "kind": "parameter", "displayName": "Prefix", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "An optional prefix added to template names to convert them into resource names." },
+    "resolver": { "index": 11, "kind": "parameter", "displayName": "Resolver", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.thymeleaf.ThymeleafResolverType", "enum": [ "CLASS_LOADER", "DEFAULT", "FILE", "STRING", "URL", "WEB_APP" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "CLASS_LOADER", "description": "The type of resolver to be used by the template engine." },
+    "suffix": { "index": 12, "kind": "parameter", "displayName": "Suffix", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "An optional suffix added to template names to convert them into resource names." }
   }
 }
diff --git a/components/camel-thymeleaf/src/main/java/org/apache/camel/component/thymeleaf/ThymeleafEndpoint.java b/components/camel-thymeleaf/src/main/java/org/apache/camel/component/thymeleaf/ThymeleafEndpoint.java
index 865ff437f78..4dd4d1dae8f 100644
--- a/components/camel-thymeleaf/src/main/java/org/apache/camel/component/thymeleaf/ThymeleafEndpoint.java
+++ b/components/camel-thymeleaf/src/main/java/org/apache/camel/component/thymeleaf/ThymeleafEndpoint.java
@@ -47,62 +47,47 @@ import org.thymeleaf.web.servlet.JakartaServletWebApplication;
 public class ThymeleafEndpoint extends ResourceEndpoint {
 
     private TemplateEngine templateEngine;
-
     private String template;
-
     private JakartaServletWebApplication jakartaServletWebApplication;
 
-    @UriParam(defaultValue = "CLASS_LOADER", description = "The type of resolver to be used by the template engine.",
+    @UriParam(label = "advanced", defaultValue = "CLASS_LOADER", description = "The type of resolver to be used by the template engine.",
               javaType = "org.apache.camel.component.thymeleaf.ThymeleafResolverType")
     private ThymeleafResolverType resolver = ThymeleafResolverType.CLASS_LOADER;
-
-    @UriParam(description = "The template mode to be applied to templates.")
+    @UriParam(description = "The template mode to be applied to templates.", defaultValue = "HTML", enums = "HTML,XML,TEXT,JAVASCRIPT,CSS,RAW")
     private String templateMode;
-
-    @UriParam(description = "An optional prefix added to template names to convert them into resource names.")
+    @UriParam(label = "advanced", description = "An optional prefix added to template names to convert them into resource names.")
     private String prefix;
-
-    @UriParam(description = "An optional suffix added to template names to convert them into resource names.")
+    @UriParam(label = "advanced", description = "An optional suffix added to template names to convert them into resource names.")
     private String suffix;
-
-    @UriParam(description = "The character encoding to be used for reading template resources.")
+    @UriParam(label = "advanced", description = "The character encoding to be used for reading template resources.")
     private String encoding;
-
-    @UriParam(description = "The order in which this template will be resolved as part of the resolver chain.")
+    @UriParam(label = "advanced", description = "The order in which this template will be resolved as part of the resolver chain.")
     private Integer order;
-
     @UriParam(description = "Whether a template resources will be checked for existence before being returned.")
     private Boolean checkExistence;
-
     @UriParam(description = "The cache Time To Live for templates, expressed in milliseconds.")
     private Long cacheTimeToLive;
-
     @UriParam(description = "Whether templates have to be considered cacheable or not.")
     private Boolean cacheable;
 
     public ThymeleafEndpoint() {
-
     }
 
     public ThymeleafEndpoint(String endpointURI, Component component, String resourceURI) {
-
         super(endpointURI, component, resourceURI);
     }
 
     @Override
     public ExchangePattern getExchangePattern() {
-
         return ExchangePattern.InOut;
     }
 
     @Override
     protected String createEndpointUri() {
-
         return "thymeleaf:" + getResourceUri();
     }
 
     public String getTemplateMode() {
-
         return templateMode;
     }
 
@@ -122,12 +107,10 @@ public class ThymeleafEndpoint extends ResourceEndpoint {
      * @param templateMode the template mode.
      */
     public void setTemplateMode(String templateMode) {
-
         this.templateMode = templateMode;
     }
 
     public ThymeleafResolverType getResolver() {
-
         return resolver;
     }
 
@@ -138,12 +121,10 @@ public class ThymeleafEndpoint extends ResourceEndpoint {
      * </p>
      */
     public void setResolver(ThymeleafResolverType resolver) {
-
         this.resolver = resolver;
     }
 
     public String getPrefix() {
-
         return prefix;
     }
 
@@ -156,12 +137,10 @@ public class ThymeleafEndpoint extends ResourceEndpoint {
      * @param prefix the prefix to be set.
      */
     public void setPrefix(String prefix) {
-
         this.prefix = prefix;
     }
 
     public String getSuffix() {
-
         return suffix;
     }
 
@@ -179,104 +158,79 @@ public class ThymeleafEndpoint extends ResourceEndpoint {
      * @param suffix the suffix to be set.
      */
     public void setSuffix(String suffix) {
-
         this.suffix = suffix;
     }
 
     public String getEncoding() {
-
         return encoding;
     }
 
     /**
-     * <p>
      * Sets a new character encoding for reading template resources.
-     * </p>
      *
      * @param encoding the character encoding to be used.
      */
     public void setEncoding(String encoding) {
-
         this.encoding = encoding;
     }
 
     public Integer getOrder() {
-
         return order;
     }
 
     /**
-     * <p>
      * Sets a new order for the template engine in the chain. Order should start with 1.
-     * </p>
      *
      * @param order the new order.
      */
     public void setOrder(Integer order) {
-
         this.order = order;
     }
 
     public Boolean getCheckExistence() {
-
         return checkExistence;
     }
 
     /**
-     * <p>
      * Sets whether template resources will be checked for existence before being returned or not.
-     * </p>
-     * <p>
      * Default value is {@code FALSE}.
-     * </p>
      *
      * @param checkExistence {@code true} if resource existence should be checked, {@code false} if not
      */
     public void setCheckExistence(Boolean checkExistence) {
-
         this.checkExistence = checkExistence;
     }
 
     public Long getCacheTimeToLive() {
-
         return cacheTimeToLive;
     }
 
     /**
-     * <p>
      * Sets a new value for the cache TTL for resolved templates.
-     * </p>
-     * <p>
+     *
      * If a template is resolved as <i>cacheable</i> but cache TTL is null, this means the template will live in cache
      * until evicted by LRU (Least Recently Used) algorithm for being the oldest entry in cache.
-     * </p>
      *
      * @param cacheTimeToLive the new cache TTL in milliseconds, or null for using natural LRU eviction.
      */
     public void setCacheTimeToLive(Long cacheTimeToLive) {
-
         this.cacheTimeToLive = cacheTimeToLive;
     }
 
     public Boolean getCacheable() {
-
         return cacheable;
     }
 
     /**
-     * <p>
      * Sets a new value for the <i>cacheable</i> flag.
-     * </p>
      *
      * @param cacheable whether resolved patterns should be considered cacheable or not.
      */
     public void setCacheable(Boolean cacheable) {
-
         this.cacheable = cacheable;
     }
 
     protected synchronized TemplateEngine getTemplateEngine() {
-
         if (templateEngine == null) {
             ITemplateResolver templateResolver;
 
@@ -284,27 +238,21 @@ public class ThymeleafEndpoint extends ResourceEndpoint {
                 case CLASS_LOADER -> {
                     templateResolver = classLoaderTemplateResolver();
                 }
-
                 case DEFAULT -> {
                     templateResolver = defaultTemplateResolver();
                 }
-
                 case FILE -> {
                     templateResolver = fileTemplateResolver();
                 }
-
                 case STRING -> {
                     templateResolver = stringTemplateResolver();
                 }
-
                 case URL -> {
                     templateResolver = urlTemplateResolver();
                 }
-
                 case WEB_APP -> {
                     templateResolver = webApplicationTemplateResolver();
                 }
-
                 default -> {
                     throw new RuntimeCamelException("cannot determine TemplateResolver for type " + resolver);
                 }
@@ -321,30 +269,25 @@ public class ThymeleafEndpoint extends ResourceEndpoint {
      * To use the {@link TemplateEngine} otherwise a new engine is created
      */
     public void setTemplateEngine(TemplateEngine templateEngine) {
-
         this.templateEngine = templateEngine;
     }
 
     public void setJakartaServletWebApplication(JakartaServletWebApplication jakartaServletWebApplication) {
-
         this.jakartaServletWebApplication = jakartaServletWebApplication;
     }
 
     public void setTemplate(String template) {
-
         this.template = template;
     }
 
     @Override
     public void clearContentCache() {
-
         if (templateEngine != null) {
             templateEngine.clearTemplateCache();
         }
     }
 
     public ThymeleafEndpoint findOrCreateEndpoint(String uri, String newResourceUri) {
-
         String newUri = uri.replace(getResourceUri(), newResourceUri);
         log.debug("Getting endpoint with URI: {}", newUri);
         return getCamelContext().getEndpoint(newUri, ThymeleafEndpoint.class);
@@ -352,7 +295,6 @@ public class ThymeleafEndpoint extends ResourceEndpoint {
 
     @Override
     protected void onExchange(Exchange exchange) throws Exception {
-
         String path = getResourceUri();
         ObjectHelper.notNull(path, "resourceUri");
 
@@ -401,7 +343,6 @@ public class ThymeleafEndpoint extends ResourceEndpoint {
     }
 
     private ITemplateResolver classLoaderTemplateResolver() {
-
         ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
         if (cacheable != null) {
             resolver.setCacheable(cacheable);
@@ -435,7 +376,6 @@ public class ThymeleafEndpoint extends ResourceEndpoint {
     }
 
     private ITemplateResolver defaultTemplateResolver() {
-
         DefaultTemplateResolver resolver = new DefaultTemplateResolver();
         if (checkExistence != null) {
             resolver.setCheckExistence(checkExistence);
@@ -456,7 +396,6 @@ public class ThymeleafEndpoint extends ResourceEndpoint {
     }
 
     private ITemplateResolver fileTemplateResolver() {
-
         FileTemplateResolver resolver = new FileTemplateResolver();
         if (cacheable != null) {
             resolver.setCacheable(cacheable);
@@ -490,7 +429,6 @@ public class ThymeleafEndpoint extends ResourceEndpoint {
     }
 
     private ITemplateResolver stringTemplateResolver() {
-
         StringTemplateResolver resolver = new StringTemplateResolver();
         if (cacheable != null) {
             resolver.setCacheable(cacheable);
@@ -515,7 +453,6 @@ public class ThymeleafEndpoint extends ResourceEndpoint {
     }
 
     private ITemplateResolver urlTemplateResolver() {
-
         UrlTemplateResolver resolver = new UrlTemplateResolver();
         if (cacheable != null) {
             resolver.setCacheable(cacheable);
@@ -546,7 +483,6 @@ public class ThymeleafEndpoint extends ResourceEndpoint {
     }
 
     private ITemplateResolver webApplicationTemplateResolver() {
-
         WebApplicationTemplateResolver resolver = new WebApplicationTemplateResolver(jakartaServletWebApplication);
 
         if (cacheable != null) {
diff --git a/components/camel-velocity/src/main/docs/velocity-component.adoc b/components/camel-velocity/src/main/docs/velocity-component.adoc
index 6a4aa0c9931..aed0345e900 100644
--- a/components/camel-velocity/src/main/docs/velocity-component.adoc
+++ b/components/camel-velocity/src/main/docs/velocity-component.adoc
@@ -88,6 +88,8 @@ Camel will provide exchange information in the Velocity context (just a
 
 |`exchange.properties` |The `Exchange` properties.
 
+|`variables` |The variables
+
 |`headers` |The headers of the In message.
 
 |`camelContext` |The Camel Context instance.
diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
index 22cfc3ed793..a3cb4bcf99b 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
@@ -806,6 +806,34 @@ public interface CamelContext extends CamelContextLifecycle, RuntimeConfiguratio
      */
     String resolvePropertyPlaceholders(String text);
 
+    /**
+     * To get a variable by name.
+     *
+     * @param  name the variable name. Can be prefixed with repo-id:name to lookup the variable from a specific
+     *              repository. If no repo-id is provided, then global repository will be used.
+     * @return      the variable, or <tt>null</tt> if not found.
+     */
+    Object getVariable(String name);
+
+    /**
+     * To get a variable by name and covert to the given type.
+     *
+     * @param  name the variable name. Can be prefixed with repo-id:name to lookup the variable from a specific
+     *              repository. If no repo-id is provided, then global repository will be used.
+     * @param  type the type to convert the variable to
+     * @return      the variable, or <tt>null</tt> if not found.
+     */
+    <T> T getVariable(String name, Class<T> type);
+
+    /**
+     * Sets a variable
+     *
+     * @param name  the variable name. Can be prefixed with repo-id:name to lookup the variable from a specific
+     *              repository. If no repo-id is provided, then global repository will be used.
+     * @param value the value of the variable
+     */
+    void setVariable(String name, Object value);
+
     /**
      * Returns the configured properties component or create one if none has been configured.
      *
diff --git a/core/camel-api/src/main/java/org/apache/camel/Exchange.java b/core/camel-api/src/main/java/org/apache/camel/Exchange.java
index 9e7abd83ad0..3aa5175e076 100644
--- a/core/camel-api/src/main/java/org/apache/camel/Exchange.java
+++ b/core/camel-api/src/main/java/org/apache/camel/Exchange.java
@@ -419,6 +419,65 @@ public interface Exchange {
      */
     boolean hasProperties();
 
+    /**
+     * Returns a variable by name
+     *
+     * @param  name the name of the variable
+     * @return      the value of the given variable or <tt>null</tt> if there is no variable for the given name
+     */
+    Object getVariable(String name);
+
+    /**
+     * Returns a variable by name and specifying the type required
+     *
+     * @param  name the name of the variable
+     * @param  type the type of the variable
+     * @return      the value of the given variable or <tt>null</tt> if there is no variable for the given name or
+     *              <tt>null</tt> if it cannot be converted to the given type
+     */
+    <T> T getVariable(String name, Class<T> type);
+
+    /**
+     * Returns a variable by name and specifying the type required
+     *
+     * @param  name         the name of the variable
+     * @param  defaultValue the default value to return if variable was absent
+     * @param  type         the type of the variable
+     * @return              the value of the given variable or <tt>defaultValue</tt> if there is no variable for the
+     *                      given name or <tt>null</tt> if it cannot be converted to the given type
+     */
+    <T> T getVariable(String name, Object defaultValue, Class<T> type);
+
+    /**
+     * Sets a variable on the exchange
+     *
+     * @param name  of the variable
+     * @param value the value of the variable
+     */
+    void setVariable(String name, Object value);
+
+    /**
+     * Removes the given variable
+     *
+     * @param  name of the variable, or use * to remove all variables
+     * @return      the old value of the variable, or <tt>null</tt> if there was no variable for the given name
+     */
+    Object removeVariable(String name);
+
+    /**
+     * Returns the variables
+     *
+     * @return the variables in a Map.
+     */
+    Map<String, Object> getVariables();
+
+    /**
+     * Returns whether any variables have been set
+     *
+     * @return <tt>true</tt> if any variables has been set
+     */
+    boolean hasVariables();
+
     /**
      * Returns the inbound request message
      *
diff --git a/core/camel-api/src/main/java/org/apache/camel/ExchangeExtension.java b/core/camel-api/src/main/java/org/apache/camel/ExchangeExtension.java
index 7ea4a144193..f076041c70c 100644
--- a/core/camel-api/src/main/java/org/apache/camel/ExchangeExtension.java
+++ b/core/camel-api/src/main/java/org/apache/camel/ExchangeExtension.java
@@ -272,4 +272,5 @@ public interface ExchangeExtension {
      * @return         A new Exchange instance
      */
     Exchange createCopyWithProperties(CamelContext context);
+
 }
diff --git a/core/camel-api/src/main/java/org/apache/camel/Variable.java b/core/camel-api/src/main/java/org/apache/camel/Variable.java
new file mode 100644
index 00000000000..e91a29b749a
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/Variable.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a parameter as being a variable
+ *
+ * @see Exchange#getVariable(String)
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Target({ ElementType.PARAMETER })
+public @interface Variable {
+
+    /**
+     * Name of variable
+     */
+    String value();
+}
diff --git a/core/camel-api/src/main/java/org/apache/camel/Variables.java b/core/camel-api/src/main/java/org/apache/camel/Variables.java
new file mode 100644
index 00000000000..30e9ccfd7f2
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/Variables.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a parameter as being an injection point of the variables
+ *
+ * @see Exchange#getVariables()
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Target({ ElementType.PARAMETER })
+public @interface Variables {
+}
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/BrowsableVariableRepository.java b/core/camel-api/src/main/java/org/apache/camel/spi/BrowsableVariableRepository.java
new file mode 100644
index 00000000000..2de29f5881a
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/BrowsableVariableRepository.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.spi;
+
+import java.util.Map;
+import java.util.stream.Stream;
+
+/**
+ * A {@link VariableRepository} that can browse the variables.
+ */
+public interface BrowsableVariableRepository extends VariableRepository {
+
+    /**
+     * Are there any variables in the repository.
+     */
+    boolean hasVariables();
+
+    /**
+     * Number of variables
+     */
+    int size();
+
+    /**
+     * The variable names
+     */
+    Stream<String> names();
+
+    /**
+     * Gets all the variables in a Map
+     */
+    Map<String, Object> getVariables();
+
+    /**
+     * Removes all variables
+     */
+    void clear();
+
+}
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/VariableRepository.java b/core/camel-api/src/main/java/org/apache/camel/spi/VariableRepository.java
new file mode 100644
index 00000000000..91d78bfa52f
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/VariableRepository.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.spi;
+
+import org.apache.camel.StaticService;
+
+/**
+ * Repository for storing and accessing variables.
+ */
+public interface VariableRepository extends StaticService {
+
+    /**
+     * The id of this repository.
+     */
+    String getId();
+
+    /**
+     * Returns a variable by name
+     *
+     * @param  name the name of the variable
+     * @return      the value of the given variable or <tt>null</tt> if there is no variable for the given name
+     */
+    Object getVariable(String name);
+
+    /**
+     * Sets a variable
+     *
+     * @param name  of the variable
+     * @param value the value of the variable
+     */
+    void setVariable(String name, Object value);
+
+    /**
+     * Removes the given variable
+     *
+     * @param  name of the variable
+     * @return      the old value of the variable, or <tt>null</tt> if there was no variable for the given name
+     */
+    Object removeVariable(String name);
+
+}
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/VariableRepositoryFactory.java b/core/camel-api/src/main/java/org/apache/camel/spi/VariableRepositoryFactory.java
new file mode 100644
index 00000000000..00344d23f3c
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/VariableRepositoryFactory.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.spi;
+
+/**
+ * Factory for {@link VariableRepository}.
+ */
+public interface VariableRepositoryFactory {
+
+    /**
+     * Registry bean id for global {@link VariableRepository}.
+     */
+    String GLOBAL_VARIABLE_REPOSITORY_ID = "global-variable-repository";
+
+    /**
+     * Gets the {@link VariableRepository} for the given id
+     *
+     * @param  id the repository id
+     * @return    the repository or <tt>null</tt> if none found
+     */
+    VariableRepository getVariableRepository(String id);
+
+}
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index 5f2060182d7..4e8c9f31c19 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -166,6 +166,8 @@ import org.apache.camel.spi.UriFactoryResolver;
 import org.apache.camel.spi.UuidGenerator;
 import org.apache.camel.spi.Validator;
 import org.apache.camel.spi.ValidatorRegistry;
+import org.apache.camel.spi.VariableRepository;
+import org.apache.camel.spi.VariableRepositoryFactory;
 import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.EndpointHelper;
 import org.apache.camel.support.EventHelper;
@@ -340,6 +342,7 @@ public abstract class AbstractCamelContext extends BaseService
         camelContextExtension.addContextPlugin(FactoryFinderResolver.class, createFactoryFinderResolver());
         camelContextExtension.addContextPlugin(PackageScanClassResolver.class, createPackageScanClassResolver());
         camelContextExtension.addContextPlugin(PackageScanResourceResolver.class, createPackageScanResourceResolver());
+        camelContextExtension.addContextPlugin(VariableRepositoryFactory.class, createVariableRepositoryFactory());
         camelContextExtension.lazyAddContextPlugin(ModelineFactory.class, this::createModelineFactory);
         camelContextExtension.lazyAddContextPlugin(ModelJAXBContextFactory.class, this::createModelJAXBContextFactory);
         camelContextExtension.addContextPlugin(DataFormatResolver.class, createDataFormatResolver());
@@ -1557,6 +1560,38 @@ public abstract class AbstractCamelContext extends BaseService
         return camelContextExtension.resolvePropertyPlaceholders(text, false);
     }
 
+    @Override
+    public Object getVariable(String name) {
+        String id = StringHelper.before(name, ":", "global");
+        name = StringHelper.after(name, ":", name);
+        VariableRepository repo
+                = camelContextExtension.getContextPlugin(VariableRepositoryFactory.class).getVariableRepository(id);
+        if (repo != null) {
+            return repo.getVariable(name);
+        }
+        return null;
+    }
+
+    @Override
+    public <T> T getVariable(String name, Class<T> type) {
+        Object value = getVariable(name);
+        if (value != null) {
+            return getTypeConverter().convertTo(type, value);
+        }
+        return null;
+    }
+
+    @Override
+    public void setVariable(String name, Object value) {
+        String id = StringHelper.before(name, ":", "global");
+        name = StringHelper.after(name, ":", name);
+        VariableRepository repo
+                = camelContextExtension.getContextPlugin(VariableRepositoryFactory.class).getVariableRepository(id);
+        if (repo != null) {
+            repo.setVariable(name, value);
+        }
+    }
+
     @Override
     public TypeConverter getTypeConverter() {
         return camelContextExtension.getTypeConverter();
@@ -3996,6 +4031,8 @@ public abstract class AbstractCamelContext extends BaseService
 
     protected abstract ValidatorRegistry<ValidatorKey> createValidatorRegistry();
 
+    protected abstract VariableRepositoryFactory createVariableRepositoryFactory();
+
     protected RestConfiguration createRestConfiguration() {
         // lookup a global which may have been on a container such spring-boot / CDI / etc.
         RestConfiguration conf
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultVariableRepositoryFactory.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultVariableRepositoryFactory.java
new file mode 100644
index 00000000000..2e982f43f51
--- /dev/null
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultVariableRepositoryFactory.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.impl.engine;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.StaticService;
+import org.apache.camel.spi.FactoryFinder;
+import org.apache.camel.spi.VariableRepository;
+import org.apache.camel.spi.VariableRepositoryFactory;
+import org.apache.camel.support.CamelContextHelper;
+import org.apache.camel.support.GlobalVariableRepository;
+import org.apache.camel.support.service.ServiceSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Default {@link VariableRepositoryFactory}.
+ */
+public class DefaultVariableRepositoryFactory extends ServiceSupport implements VariableRepositoryFactory, StaticService {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultVariableRepositoryFactory.class);
+
+    public static final String RESOURCE_PATH = "META-INF/services/org/apache/camel/variable-repository/";
+
+    private final CamelContext camelContext;
+    private VariableRepository global;
+    private FactoryFinder factoryFinder;
+
+    public DefaultVariableRepositoryFactory(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    @Override
+    public VariableRepository getVariableRepository(String id) {
+        // ensure we are started if in use
+        if (!isStarted()) {
+            start();
+        }
+
+        if (global != null && "global".equals(id)) {
+            return global;
+        }
+
+        VariableRepository repo = CamelContextHelper.lookup(camelContext, id, VariableRepository.class);
+        if (repo == null) {
+            repo = CamelContextHelper.lookup(camelContext, id + "-variable-repository", VariableRepository.class);
+        }
+        if (repo == null) {
+            // try via factory finder
+            Class<?> clazz = factoryFinder.findClass(id).orElse(null);
+            if (clazz != null && VariableRepository.class.isAssignableFrom(clazz)) {
+                repo = (VariableRepository) camelContext.getInjector().newInstance(clazz, true);
+                camelContext.getRegistry().bind(id, repo);
+                try {
+                    camelContext.addService(repo);
+                } catch (Exception e) {
+                    throw RuntimeCamelException.wrapRuntimeException(e);
+                }
+            }
+        }
+
+        return repo;
+    }
+
+    @Override
+    protected void doBuild() throws Exception {
+        super.doBuild();
+        this.factoryFinder = camelContext.getCamelContextExtension().getBootstrapFactoryFinder(RESOURCE_PATH);
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+
+        // let's see if there is a custom global repo
+        VariableRepository repo = getVariableRepository("global");
+        if (repo != null) {
+            if (!(repo instanceof GlobalVariableRepository)) {
+                LOG.info("Using VariableRepository: {} as global repository", repo.getId());
+            }
+            global = repo;
+        } else {
+            global = new GlobalVariableRepository();
+            camelContext.getRegistry().bind(GLOBAL_VARIABLE_REPOSITORY_ID, global);
+        }
+
+        if (!camelContext.hasService(global)) {
+            camelContext.addService(global);
+        }
+    }
+
+}
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
index 04bc7c475f0..4b013e81e81 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
@@ -91,6 +91,7 @@ import org.apache.camel.spi.UnitOfWorkFactory;
 import org.apache.camel.spi.UriFactoryResolver;
 import org.apache.camel.spi.UuidGenerator;
 import org.apache.camel.spi.ValidatorRegistry;
+import org.apache.camel.spi.VariableRepositoryFactory;
 import org.apache.camel.support.DefaultRegistry;
 import org.apache.camel.support.DefaultUuidGenerator;
 import org.apache.camel.support.NormalizedUri;
@@ -720,6 +721,11 @@ public class SimpleCamelContext extends AbstractCamelContext {
         return new DefaultValidatorRegistry(getCamelContextReference());
     }
 
+    @Override
+    protected VariableRepositoryFactory createVariableRepositoryFactory() {
+        return new DefaultVariableRepositoryFactory(getCamelContextReference());
+    }
+
     @Override
     protected TransformerRegistry<TransformerKey> createTransformerRegistry() {
         return new DefaultTransformerRegistry(getCamelContextReference());
diff --git a/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/variables b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/variables
new file mode 100644
index 00000000000..09e0f310219
--- /dev/null
+++ b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/variables
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.impl.console.VariablesDevConsole
diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/VariablesDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/VariablesDevConsole.java
new file mode 100644
index 00000000000..4f1e95415ac
--- /dev/null
+++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/VariablesDevConsole.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.impl.console;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.camel.spi.BrowsableVariableRepository;
+import org.apache.camel.spi.annotations.DevConsole;
+import org.apache.camel.support.console.AbstractDevConsole;
+import org.apache.camel.util.json.JsonObject;
+
+@DevConsole("variables")
+public class VariablesDevConsole extends AbstractDevConsole {
+
+    public VariablesDevConsole() {
+        super("camel", "variables", "Variables", "Displays variables");
+    }
+
+    @Override
+    protected String doCallText(Map<String, Object> options) {
+        StringBuilder sb = new StringBuilder();
+
+        Set<BrowsableVariableRepository> repos = getCamelContext().getRegistry().findByType(BrowsableVariableRepository.class);
+        for (BrowsableVariableRepository repo : repos) {
+            sb.append(String.format("Repository: %s (size: %d)", repo.getId(), repo.size()));
+            sb.append("\n");
+            for (Map.Entry<String, Object> entry : repo.getVariables().entrySet()) {
+                String k = entry.getKey();
+                Object v = entry.getValue();
+                String t = v != null ? v.getClass().getName() : "<null>";
+                sb.append(String.format("\n    %s (%s) = %s", k, t, v));
+            }
+            sb.append("\n");
+        }
+
+        return sb.toString();
+    }
+
+    @Override
+    protected JsonObject doCallJson(Map<String, Object> options) {
+        JsonObject root = new JsonObject();
+
+        Set<BrowsableVariableRepository> repos = getCamelContext().getRegistry().findByType(BrowsableVariableRepository.class);
+        for (BrowsableVariableRepository repo : repos) {
+            List<JsonObject> arr = new ArrayList<>();
+            for (Map.Entry<String, Object> entry : repo.getVariables().entrySet()) {
+                String k = entry.getKey();
+                Object v = entry.getValue();
+                String t = v != null ? v.getClass().getName() : null;
+                JsonObject e = new JsonObject();
+                e.put("key", k);
+                e.put("value", v);
+                if (t != null) {
+                    e.put("className", t);
+                }
+                arr.add(e);
+            }
+            if (!arr.isEmpty()) {
+                root.put(repo.getId(), arr);
+            }
+        }
+
+        return root;
+    }
+}
diff --git a/core/camel-core-engine/src/main/docs/modules/eips/examples/json/removeVariable.json b/core/camel-core-engine/src/main/docs/modules/eips/examples/json/removeVariable.json
new file mode 120000
index 00000000000..1d130e5c3d8
--- /dev/null
+++ b/core/camel-core-engine/src/main/docs/modules/eips/examples/json/removeVariable.json
@@ -0,0 +1 @@
+../../../../../../../../camel-core-model/src/generated/resources/org/apache/camel/model/removeVariable.json
\ No newline at end of file
diff --git a/core/camel-core-engine/src/main/docs/modules/eips/examples/json/setVariable.json b/core/camel-core-engine/src/main/docs/modules/eips/examples/json/setVariable.json
new file mode 120000
index 00000000000..050c17ccc46
--- /dev/null
+++ b/core/camel-core-engine/src/main/docs/modules/eips/examples/json/setVariable.json
@@ -0,0 +1 @@
+../../../../../../../../camel-core-model/src/generated/resources/org/apache/camel/model/setVariable.json
\ No newline at end of file
diff --git a/core/camel-core-engine/src/main/docs/modules/eips/nav.adoc b/core/camel-core-engine/src/main/docs/modules/eips/nav.adoc
index b6a179681c8..4bca724bdb5 100644
--- a/core/camel-core-engine/src/main/docs/modules/eips/nav.adoc
+++ b/core/camel-core-engine/src/main/docs/modules/eips/nav.adoc
@@ -67,6 +67,7 @@
 ** xref:removeHeaders-eip.adoc[Remove Headers]
 ** xref:removeProperties-eip.adoc[Remove Properties]
 ** xref:removeProperty-eip.adoc[Remove Property]
+** xref:removeVariable-eip.adoc[Remove Variable]
 ** xref:requestReply-eip.adoc[Request Reply]
 ** xref:resequence-eip.adoc[Resequence]
 ** xref:resilience4jConfiguration-eip.adoc[Resilience4j Configuration]
@@ -87,6 +88,7 @@
 ** xref:setHeader-eip.adoc[Set Header]
 ** xref:setHeaders-eip.adoc[Set Headers]
 ** xref:setProperty-eip.adoc[Set Property]
+** xref:setVariable-eip.adoc[Set Variable]
 ** xref:sort-eip.adoc[Sort]
 ** xref:split-eip.adoc[Split]
 ** xref:step-eip.adoc[Step]
diff --git a/core/camel-core-engine/src/main/docs/modules/eips/pages/removeVariable-eip.adoc b/core/camel-core-engine/src/main/docs/modules/eips/pages/removeVariable-eip.adoc
new file mode 100644
index 00000000000..f14e3ecec65
--- /dev/null
+++ b/core/camel-core-engine/src/main/docs/modules/eips/pages/removeVariable-eip.adoc
@@ -0,0 +1,44 @@
+= Remove Variable EIP
+:doctitle: Remove Variable
+:shortname: removeVariable
+:description: Removes a named variable
+:since: 
+:supportlevel: Stable
+:tabs-sync-option:
+
+The Remove Variable EIP allows you to remove a single variable.
+
+== Options
+
+// eip options: START
+include::partial$eip-options.adoc[]
+// eip options: END
+
+== Example
+
+We want to remove a variable with key "myVar" from the exchange:
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("seda:b")
+  .removeVariable("myVar")
+  .to("mock:result");
+----
+
+XML::
++
+[source,xml]
+----
+<route>
+  <from uri="seda:b"/>
+  <removeVariable name="myVar"/>
+  <to uri="mock:result"/>
+</route>
+----
+====
+
+TIP: If you want to remove all variables from the `Exchange` then use `*` as the name.
diff --git a/core/camel-core-engine/src/main/docs/modules/eips/pages/setVariable-eip.adoc b/core/camel-core-engine/src/main/docs/modules/eips/pages/setVariable-eip.adoc
new file mode 100644
index 00000000000..85b6735fcb3
--- /dev/null
+++ b/core/camel-core-engine/src/main/docs/modules/eips/pages/setVariable-eip.adoc
@@ -0,0 +1,104 @@
+= Set Variable EIP
+:doctitle: Set Variable
+:shortname: setVariable
+:description: Sets the value of a variable
+:since: 
+:supportlevel: Stable
+:tabs-sync-option:
+
+The SetVariable EIP is used for setting a xref:manual:ROOT:exchange.adoc[Exchange] variable.
+
+== Options
+
+// eip options: START
+include::partial$eip-options.adoc[]
+// eip options: END
+
+The following example shows how to set a variable on the exchange in a Camel route:
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("direct:a")
+    .setVariable("myVar", constant("test"))
+    .to("direct:b");
+----
+
+XML::
++
+[source,xml]
+----
+<route>
+    <from uri="direct:a"/>
+    <setVariable name="myVar">
+        <constant>test</constant>
+    </setVariable>
+    <to uri="direct:b"/>
+</route>
+----
+====
+
+=== Setting an variable from a message header
+
+You can also set a variable with the value from a message header.
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("direct:a")
+    .setVariable("foo", header("bar"))
+    .to("direct:b");
+----
+
+XML::
++
+[source,xml]
+----
+<route>
+    <from uri="direct:a"/>
+    <setVariable name="foo">
+        <header>bar</header>
+    </setVariable>
+    <to uri="direct:b"/>
+</route>
+----
+====
+
+=== Setting variable with the current message body
+
+It is of course also possible to set an variable with a value
+from anything on the `Exchange` such as the message body:
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("direct:a")
+    .setVariable("myBody", body())
+    .to("direct:b");
+----
+
+XML::
++
+We use the xref:components:languages:simple-language.adoc[Simple] language
+to refer to the message body:
++
+[source,xml]
+----
+<route>
+    <from uri="direct:a"/>
+    <setVariable name="myBody">
+        <simple>${body}</simple>
+    </setVariable>
+    <to uri="direct:b"/>
+</route>
+----
+====
diff --git a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
index 4789404a6cb..9a663faf367 100644
--- a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
+++ b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
@@ -127,6 +127,18 @@ classname
 
 |headers |Map |refer to the headers
 
+|variable.foo |Object |refer to the foo variable
+
+|variable[foo] |Object |refer to the foo variable
+
+|variable.foo.*OGNL* |Object |refer to the foo variable and invoke its
+value using a Camel OGNL expression.
+
+|variableAs(_key_,_type_) |Type |converts the variable to the given type determined by its
+classname
+
+|variables |Map |refer to the variables
+
 |exchangeProperty.foo |Object |refer to the foo property on the exchange
 
 |exchangeProperty[foo] |Object |refer to the foo property on the exchange
@@ -165,7 +177,8 @@ exceptions (`Exchange.EXCEPTION_CAUGHT`) if the Exchange has any.
 |date:_command_ |Date |evaluates to a Date object.
 Supported commands are: *now* for current timestamp,
 *exchangeCreated* for the timestamp when the current exchange was created,
-*header.xxx* to use the Long/Date object header with the key xxx.
+*header.xxx* to use the Long/Date object in the header with the key xxx.
+*variable.xxx* to use the Long/Date in the variable with the key xxx.
 *exchangeProperty.xxx* to use the Long/Date object in the exchange property with the key xxx.
 *file* for the last modified timestamp of the file (available with a File consumer).
 Command accepts offsets such as: *now-24h* or *header.xxx+1h* or even *now+1h30m-100*.
diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
index 0be12c475a1..9ec436ae6ec 100644
--- a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
+++ b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
@@ -76,6 +76,20 @@ public final class SimpleExpressionBuilder {
                 });
     }
 
+    /**
+     * Returns the expression for the variable invoking methods defined in a simple OGNL notation
+     *
+     * @param ognl methods to invoke on the variable in a simple OGNL syntax
+     */
+    public static Expression variablesOgnlExpression(final String ognl) {
+        return new KeyedOgnlExpressionAdapter(
+                ognl, "variableOgnl(" + ognl + ")",
+                (exchange, exp) -> {
+                    String text = exp.evaluate(exchange, String.class);
+                    return exchange.getVariable(text);
+                });
+    }
+
     /**
      * Returns the message history (including exchange details or not)
      */
@@ -596,6 +610,8 @@ public final class SimpleExpressionBuilder {
             date = LanguageHelper.dateFromExchangeCreated(exchange);
         } else if (command.startsWith("header.")) {
             date = LanguageHelper.dateFromHeader(exchange, command, (e, o) -> tryConvertingAsDate(e, o, command));
+        } else if (command.startsWith("variable.")) {
+            date = LanguageHelper.dateFromVariable(exchange, command, (e, o) -> tryConvertingAsDate(e, o, command));
         } else if (command.startsWith("exchangeProperty.")) {
             date = LanguageHelper.dateFromExchangeProperty(exchange, command, (e, o) -> tryConvertingAsDate(e, o, command));
         } else if ("file".equals(command)) {
diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
index ddc8fd13425..fb04db0eefa 100644
--- a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
+++ b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
@@ -88,6 +88,11 @@ public class SimpleFunctionExpression extends LiteralExpression {
         if (answer != null) {
             return answer;
         }
+        // variables
+        answer = createSimpleExpressionVariables(function, strict);
+        if (answer != null) {
+            return answer;
+        }
         // custom languages
         answer = createSimpleCustomLanguage(function, strict);
         if (answer != null) {
@@ -451,6 +456,63 @@ public class SimpleFunctionExpression extends LiteralExpression {
         return null;
     }
 
+    private Expression createSimpleExpressionVariables(String function, boolean strict) {
+        // variableAs
+        String remainder = ifStartsWithReturnRemainder("variableAs(", function);
+        if (remainder != null) {
+            String keyAndType = StringHelper.before(remainder, ")");
+            if (keyAndType == null) {
+                throw new SimpleParserException("Valid syntax: ${variableAs(key, type)} was: " + function, token.getIndex());
+            }
+
+            String key = StringHelper.before(keyAndType, ",");
+            String type = StringHelper.after(keyAndType, ",");
+            remainder = StringHelper.after(remainder, ")");
+            if (ObjectHelper.isEmpty(key) || ObjectHelper.isEmpty(type) || ObjectHelper.isNotEmpty(remainder)) {
+                throw new SimpleParserException("Valid syntax: ${variableAs(key, type)} was: " + function, token.getIndex());
+            }
+            key = StringHelper.removeQuotes(key);
+            type = StringHelper.removeQuotes(type);
+            return ExpressionBuilder.variableExpression(key, type);
+        }
+
+        // variables function
+        if ("variables".equals(function)) {
+            return ExpressionBuilder.variablesExpression();
+        }
+
+        // variable function
+        remainder = parseVariable(function);
+        if (remainder != null) {
+            // remove leading character (dot, colon or ?)
+            if (remainder.startsWith(".") || remainder.startsWith(":") || remainder.startsWith("?")) {
+                remainder = remainder.substring(1);
+            }
+            // remove starting and ending brackets
+            if (remainder.startsWith("[") && remainder.endsWith("]")) {
+                remainder = remainder.substring(1, remainder.length() - 1);
+            }
+            // remove quotes from key
+            String key = StringHelper.removeLeadingAndEndingQuotes(remainder);
+
+            // validate syntax
+            boolean invalid = OgnlHelper.isInvalidValidOgnlExpression(key);
+            if (invalid) {
+                throw new SimpleParserException("Valid syntax: ${variable.name[key]} was: " + function, token.getIndex());
+            }
+
+            if (OgnlHelper.isValidOgnlExpression(key)) {
+                // ognl based variable
+                return SimpleExpressionBuilder.variablesOgnlExpression(key);
+            } else {
+                // regular variable
+                return ExpressionBuilder.variableExpression(key);
+            }
+        }
+
+        return null;
+    }
+
     private Expression createSimpleCustomLanguage(String function, boolean strict) {
         // jq
         String remainder = ifStartsWithReturnRemainder("jq(", function);
@@ -1271,6 +1333,15 @@ public class SimpleFunctionExpression extends LiteralExpression {
         return remainder;
     }
 
+    private String parseVariable(String function) {
+        String remainder;
+        remainder = ifStartsWithReturnRemainder("variables", function);
+        if (remainder == null) {
+            remainder = ifStartsWithReturnRemainder("variable", function);
+        }
+        return remainder;
+    }
+
     private String createCodeExchangeProperty(final String function) {
         // exchangePropertyAsIndex
         String remainder = ifStartsWithReturnRemainder("exchangePropertyAsIndex(", function);
diff --git a/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties b/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
index b2c692f52ab..dd1f1353425 100644
--- a/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
+++ b/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
@@ -129,6 +129,7 @@ removeHeader
 removeHeaders
 removeProperties
 removeProperty
+removeVariable
 resequence
 resilience4jConfiguration
 responseHeader
@@ -170,6 +171,7 @@ setExchangePattern
 setHeader
 setHeaders
 setProperty
+setVariable
 simple
 soap
 sort
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/aggregate.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/aggregate.json
index 3e6e98cc342..6411c8b6422 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/aggregate.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/aggregate.json
@@ -42,6 +42,6 @@
     "discardOnAggregationFailure": { "index": 27, "kind": "attribute", "displayName": "Discard On Aggregation Failure", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Discards the aggregated message when aggregation failed (an exception was thrown from AggregationStrategy . This means the partly aggregated message is dropped and not sent out of the [...]
     "forceCompletionOnStop": { "index": 28, "kind": "attribute", "displayName": "Force Completion On Stop", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Indicates to complete all current aggregated exchanges when the context is stopped" },
     "completeAllOnStop": { "index": 29, "kind": "attribute", "displayName": "Complete All On Stop", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Indicates to wait to complete all current and partial (pending) aggregated exchanges when the context is stopped. This also means that we will wait for all pending exchanges which are stored in the aggre [...]
-    "outputs": { "index": 30, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
+    "outputs": { "index": 30, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/circuitBreaker.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/circuitBreaker.json
index 656922f6098..9cd6e592cfc 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/circuitBreaker.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/circuitBreaker.json
@@ -19,6 +19,6 @@
     "resilience4jConfiguration": { "index": 4, "kind": "element", "displayName": "Resilience4j Configuration", "required": false, "type": "object", "javaType": "org.apache.camel.model.Resilience4jConfigurationDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Configures the circuit breaker to use Resilience4j with the given configuration." },
     "faultToleranceConfiguration": { "index": 5, "kind": "element", "displayName": "Fault Tolerance Configuration", "required": false, "type": "object", "javaType": "org.apache.camel.model.FaultToleranceConfigurationDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Configures the circuit breaker to use MicroProfile Fault Tolerance with the given configuration." },
     "onFallback": { "index": 6, "kind": "element", "displayName": "On Fallback", "required": false, "type": "object", "javaType": "org.apache.camel.model.OnFallbackDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "The fallback route path to execute that does not go over the network. This should be a static or cached result that can immediately be returned upon failure. If the fallback requires network connection then use onFallbackViaNetwork() ." },
-    "outputs": { "index": 7, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 7, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/doCatch.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/doCatch.json
index 75dbf6fdb12..adb84178cff 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/doCatch.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/doCatch.json
@@ -17,6 +17,6 @@
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "exception": { "index": 3, "kind": "element", "displayName": "Exception", "required": false, "type": "array", "javaType": "java.util.List<java.lang.String>", "deprecated": false, "autowired": false, "secret": false, "description": "The exception(s) to catch." },
     "onWhen": { "index": 4, "kind": "element", "displayName": "On When", "required": false, "type": "object", "javaType": "org.apache.camel.model.WhenDefinition", "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "description": "Sets an additional predicate that should be true before the onCatch is triggered. To be used for fine grained controlling whether a thrown exception should be intercepted by this exception type or not." },
-    "outputs": { "index": 5, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 5, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/doFinally.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/doFinally.json
index 05f4ea4d452..6eef88af181 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/doFinally.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/doFinally.json
@@ -15,6 +15,6 @@
     "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
-    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/doTry.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/doTry.json
index fa84687ca13..8ac3754360d 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/doTry.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/doTry.json
@@ -15,6 +15,6 @@
     "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
-    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/filter.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/filter.json
index 4b1dddcdf38..13eb266ab0d 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/filter.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/filter.json
@@ -17,6 +17,6 @@
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "expression": { "index": 3, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "java", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "sec [...]
     "statusPropertyName": { "index": 4, "kind": "attribute", "displayName": "Status Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of exchange property to use for storing the status of the filtering. Setting this allows to know if the filter predicate evaluated as true or false." },
-    "outputs": { "index": 5, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
+    "outputs": { "index": 5, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/idempotentConsumer.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/idempotentConsumer.json
index 468380ca51f..149004e15b2 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/idempotentConsumer.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/idempotentConsumer.json
@@ -21,6 +21,6 @@
     "completionEager": { "index": 6, "kind": "attribute", "displayName": "Completion Eager", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Sets whether to complete the idempotent consumer eager or when the exchange is done. If this option is true to complete eager, then the idempotent consumer will trigger its completion when the exchange reached  [...]
     "skipDuplicate": { "index": 7, "kind": "attribute", "displayName": "Skip Duplicate", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Sets whether to skip duplicates or not. The default behavior is to skip duplicates. A duplicate message would have the Exchange property org.apache.camel.Exchange#DUPLICATE_MESSAGE set to a Boolean#TRUE value. A non [...]
     "removeOnFailure": { "index": 8, "kind": "attribute", "displayName": "Remove On Failure", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Sets whether to remove or keep the key on failure. The default behavior is to remove the key on failure." },
-    "outputs": { "index": 9, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
+    "outputs": { "index": 9, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/intercept.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/intercept.json
index 674e1c33bac..e1063c592b5 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/intercept.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/intercept.json
@@ -15,6 +15,6 @@
     "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
-    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/interceptFrom.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/interceptFrom.json
index 725c74df389..2d90e3a6be8 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/interceptFrom.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/interceptFrom.json
@@ -16,6 +16,6 @@
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "uri": { "index": 3, "kind": "attribute", "displayName": "Uri", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Intercept incoming messages from the uri or uri pattern. If this option is not configured, then all incoming messages is intercepted." },
-    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/interceptSendToEndpoint.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/interceptSendToEndpoint.json
index 4574c9902c2..d2163bf0f37 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/interceptSendToEndpoint.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/interceptSendToEndpoint.json
@@ -18,6 +18,6 @@
     "uri": { "index": 3, "kind": "attribute", "displayName": "Uri", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Intercept sending to the uri or uri pattern." },
     "skipSendToOriginalEndpoint": { "index": 4, "kind": "attribute", "displayName": "Skip Send To Original Endpoint", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "If set to true then the message is not sent to the original endpoint. By default (false) the message is both intercepted and then sent to the original endpoint." },
     "afterUri": { "index": 5, "kind": "attribute", "displayName": "After Uri", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "After sending to the endpoint then send the message to this uri which allows to process its result." },
-    "outputs": { "index": 6, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 6, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index b/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index
index c3cf0aa2cd8..72031091516 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index
@@ -57,6 +57,7 @@ RemoveHeaderDefinition
 RemoveHeadersDefinition
 RemovePropertiesDefinition
 RemovePropertyDefinition
+RemoveVariableDefinition
 ResequenceDefinition
 Resilience4jConfigurationDefinition
 RestContextRefDefinition
@@ -85,6 +86,7 @@ SetExchangePatternDefinition
 SetHeaderDefinition
 SetHeadersDefinition
 SetPropertyDefinition
+SetVariableDefinition
 SortDefinition
 SplitDefinition
 StepDefinition
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/kamelet.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/kamelet.json
index d37e1c7c9a9..4bcc06c5bd0 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/kamelet.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/kamelet.json
@@ -16,6 +16,6 @@
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "name": { "index": 3, "kind": "attribute", "displayName": "Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of the Kamelet (templateId\/routeId) to call. Options for the kamelet can be specified using uri syntax, eg mynamecount=4&type=gold." },
-    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/loadBalance.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/loadBalance.json
index f5d8693cf4d..06f242f0554 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/loadBalance.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/loadBalance.json
@@ -16,7 +16,7 @@
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "loadBalancerType": { "index": 3, "kind": "element", "displayName": "Load Balancer Type", "required": true, "type": "object", "javaType": "org.apache.camel.model.LoadBalancerDefinition", "oneOf": [ "customLoadBalancer", "failover", "random", "roundRobin", "sticky", "topic", "weighted" ], "deprecated": false, "autowired": false, "secret": false, "description": "The load balancer to be used" },
-    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
     "inheritErrorHandler": { "index": 5, "kind": "attribute", "displayName": "Inherit Error Handler", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Sets whether or not to inherit the configured error handler. The default value is true. You can use this to disable using the inherited error handler for a given DSL such as a load balancer where you want to use a custom e [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/loop.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/loop.json
index 9eda3d0f43a..24ad0a7819a 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/loop.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/loop.json
@@ -19,6 +19,6 @@
     "copy": { "index": 4, "kind": "attribute", "displayName": "Copy", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If the copy attribute is true, a copy of the input Exchange is used for each iteration. That means each iteration will start from a copy of the same message. By default loop will loop the same exchange all over, so each iteration may [...]
     "doWhile": { "index": 5, "kind": "attribute", "displayName": "Do While", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enables the while loop that loops until the predicate evaluates to false or null." },
     "breakOnShutdown": { "index": 6, "kind": "attribute", "displayName": "Break On Shutdown", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If the breakOnShutdown attribute is true, then the loop will not iterate until it reaches the end when Camel is shut down." },
-    "outputs": { "index": 7, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
+    "outputs": { "index": 7, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/multicast.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/multicast.json
index 05b82097c68..6c6abaf464d 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/multicast.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/multicast.json
@@ -27,6 +27,6 @@
     "executorService": { "index": 12, "kind": "attribute", "displayName": "Executor Service", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.concurrent.ExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "Refers to a custom Thread Pool to be used for parallel processing. Notice if you set this option, then parallel processing is automatic implied, and you do not have to enable that option as well." },
     "onPrepare": { "index": 13, "kind": "attribute", "displayName": "On Prepare", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.Processor", "deprecated": false, "autowired": false, "secret": false, "description": "Uses the Processor when preparing the org.apache.camel.Exchange to be send. This can be used to deep-clone messages that should be send, or any custom logic needed before the exchange is send." },
     "shareUnitOfWork": { "index": 14, "kind": "attribute", "displayName": "Share Unit Of Work", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Shares the org.apache.camel.spi.UnitOfWork with the parent and each of the sub messages. Multicast will by default not share unit of work between the parent exchange and each multicasted exchange. This means [...]
-    "outputs": { "index": 15, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
+    "outputs": { "index": 15, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/onCompletion.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/onCompletion.json
index 48798e63088..0e4b42cfeec 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/onCompletion.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/onCompletion.json
@@ -22,6 +22,6 @@
     "executorService": { "index": 7, "kind": "attribute", "displayName": "Executor Service", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.concurrent.ExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom Thread Pool to be used for parallel processing. Notice if you set this option, then parallel processing is automatic implied, and you do not have to enable that option as well." },
     "useOriginalMessage": { "index": 8, "kind": "attribute", "displayName": "Use Original Message", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Will use the original input message body when an org.apache.camel.Exchange for this on completion. The original input message is defensively copied, and the copied message body is converted to org.apache [...]
     "onWhen": { "index": 9, "kind": "element", "displayName": "On When", "required": false, "type": "object", "javaType": "org.apache.camel.model.WhenDefinition", "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "description": "Sets an additional predicate that should be true before the onCompletion is triggered. To be used for fine grained controlling whether a completion callback should be invoked or not" },
-    "outputs": { "index": 10, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
+    "outputs": { "index": 10, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/onException.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/onException.json
index f1053577e6c..6de27e20851 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/onException.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/onException.json
@@ -26,6 +26,6 @@
     "onExceptionOccurredRef": { "index": 11, "kind": "attribute", "displayName": "On Exception Occurred Ref", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets a reference to a processor that should be processed just after an exception occurred. Can be used to perform custom logging about the occurred exception at the exact time it happened. Important: Any exception thro [...]
     "useOriginalMessage": { "index": 12, "kind": "attribute", "displayName": "Use Original Message", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Will use the original input org.apache.camel.Message (original body and headers) when an org.apache.camel.Exchange is moved to the dead letter queue. Notice: this only applies when all redeliveries atte [...]
     "useOriginalBody": { "index": 13, "kind": "attribute", "displayName": "Use Original Body", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Will use the original input org.apache.camel.Message body (original body only) when an org.apache.camel.Exchange is moved to the dead letter queue. Notice: this only applies when all redeliveries attempt have [...]
-    "outputs": { "index": 14, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
+    "outputs": { "index": 14, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/onFallback.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/onFallback.json
index bc5f671fd1b..1c1774c10a9 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/onFallback.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/onFallback.json
@@ -16,6 +16,6 @@
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "fallbackViaNetwork": { "index": 3, "kind": "attribute", "displayName": "Fallback Via Network", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the fallback goes over the network. If the fallback will go over the network it is another possible point of failure. It is important to execute the fallback command on a separate thread-pool, ot [...]
-    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
+    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/otherwise.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/otherwise.json
index 5b7ec14f5e4..cce4b703fe8 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/otherwise.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/otherwise.json
@@ -15,6 +15,6 @@
     "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
-    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/pipeline.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/pipeline.json
index 021a97f2224..85ccd199df1 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/pipeline.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/pipeline.json
@@ -15,6 +15,6 @@
     "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
-    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/removeVariable.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/removeVariable.json
new file mode 100644
index 00000000000..b5e9748bb20
--- /dev/null
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/removeVariable.json
@@ -0,0 +1,20 @@
+{
+  "model": {
+    "kind": "model",
+    "name": "removeVariable",
+    "title": "Remove Variable",
+    "description": "Removes a named variable",
+    "deprecated": false,
+    "label": "eip,transformation",
+    "javaType": "org.apache.camel.model.RemoveVariableDefinition",
+    "abstract": false,
+    "input": true,
+    "output": false
+  },
+  "properties": {
+    "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
+    "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
+    "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
+    "name": { "index": 3, "kind": "attribute", "displayName": "Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to remove." }
+  }
+}
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/resequence.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/resequence.json
index 32332a238c4..4a12cdfaffe 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/resequence.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/resequence.json
@@ -17,6 +17,6 @@
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "expression": { "index": 3, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "java", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "sec [...]
     "resequencerConfig": { "index": 4, "kind": "element", "displayName": "Resequencer Config", "required": true, "type": "object", "javaType": "org.apache.camel.model.config.ResequencerConfig", "oneOf": [ "batchConfig", "streamConfig" ], "deprecated": false, "autowired": false, "secret": false, "description": "To configure the resequencer in using either batch or stream configuration. Will by default use batch configuration." },
-    "outputs": { "index": 5, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 5, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/route.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/route.json
index e1971051b24..d4b9c4b06b2 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/route.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/route.json
@@ -32,6 +32,6 @@
     "inputType": { "index": 17, "kind": "element", "displayName": "Input Type", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.InputTypeDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Declare the expected data type of the input message. If the actual message type is different at runtime, camel look for a required org.apache.camel.spi.Transformer and apply if exists. The type name consists of two parts,  [...]
     "outputType": { "index": 18, "kind": "element", "displayName": "Output Type", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.model.OutputTypeDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Declare the expected data type of the output message. If the actual message type is different at runtime, camel look for a required org.apache.camel.spi.Transformer and apply if exists. The type name consists of two par [...]
     "input": { "index": 19, "kind": "element", "displayName": "Input", "required": true, "type": "object", "javaType": "org.apache.camel.model.FromDefinition", "oneOf": [ "from" ], "deprecated": false, "autowired": false, "secret": false, "description": "Input to the route." },
-    "outputs": { "index": 20, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<?>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loo [...]
+    "outputs": { "index": 20, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<?>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loo [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/saga.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/saga.json
index 81221edf12c..2503f7defe6 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/saga.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/saga.json
@@ -22,6 +22,6 @@
     "compensation": { "index": 7, "kind": "element", "displayName": "Compensation", "required": false, "type": "object", "javaType": "org.apache.camel.model.SagaActionUriDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "The compensation endpoint URI that must be called to compensate all changes done in the route. The route corresponding to the compensation URI must perform compensation and complete without error. If errors occur during compensation, t [...]
     "completion": { "index": 8, "kind": "element", "displayName": "Completion", "required": false, "type": "object", "javaType": "org.apache.camel.model.SagaActionUriDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "The completion endpoint URI that will be called when the Saga is completed successfully. The route corresponding to the completion URI must perform completion tasks and terminate without error. If errors occur during completion, the saga s [...]
     "option": { "index": 9, "kind": "element", "displayName": "Option", "label": "advanced", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.PropertyExpressionDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Allows to save properties of the current exchange in order to re-use them in a compensation\/completion callback route. Options are usually helpful e.g. to store and retrieve identifiers of objects that sho [...]
-    "outputs": { "index": 10, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
+    "outputs": { "index": 10, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "on [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/setVariable.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/setVariable.json
new file mode 100644
index 00000000000..727ca75bd3b
--- /dev/null
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/setVariable.json
@@ -0,0 +1,21 @@
+{
+  "model": {
+    "kind": "model",
+    "name": "setVariable",
+    "title": "Set Variable",
+    "description": "Sets the value of a variable",
+    "deprecated": false,
+    "label": "eip,transformation",
+    "javaType": "org.apache.camel.model.SetVariableDefinition",
+    "abstract": false,
+    "input": true,
+    "output": false
+  },
+  "properties": {
+    "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
+    "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
+    "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
+    "name": { "index": 3, "kind": "attribute", "displayName": "Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to set a new value The simple language can be used to define a dynamic evaluated variable name to be used. Otherwise a constant name will be used." },
+    "expression": { "index": 4, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "java", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "sec [...]
+  }
+}
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/split.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/split.json
index 63c0043e17e..395a1cb544a 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/split.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/split.json
@@ -29,6 +29,6 @@
     "executorService": { "index": 14, "kind": "attribute", "displayName": "Executor Service", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.concurrent.ExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "To use a custom Thread Pool to be used for parallel processing. Notice if you set this option, then parallel processing is automatically implied, and you do not have to enable that option as well." },
     "onPrepare": { "index": 15, "kind": "attribute", "displayName": "On Prepare", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.Processor", "deprecated": false, "autowired": false, "secret": false, "description": "Uses the Processor when preparing the org.apache.camel.Exchange to be sent. This can be used to deep-clone messages that should be sent, or any custom logic needed before the exchange is sent." },
     "shareUnitOfWork": { "index": 16, "kind": "attribute", "displayName": "Share Unit Of Work", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Shares the org.apache.camel.spi.UnitOfWork with the parent and each of the sub messages. Splitter will by default not share unit of work between the parent exchange and each split exchange. This means each s [...]
-    "outputs": { "index": 17, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalanc [...]
+    "outputs": { "index": 17, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalanc [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/step.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/step.json
index 0ffc6be4510..2d47cf3b901 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/step.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/step.json
@@ -15,6 +15,6 @@
     "id": { "index": 0, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
-    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
+    "outputs": { "index": 3, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onE [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/when.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/when.json
index bff35777dd3..c9278a4adae 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/when.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/when.json
@@ -16,6 +16,6 @@
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "expression": { "index": 3, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "java", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "sec [...]
-    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
+    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/whenSkipSendToEndpoint.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/whenSkipSendToEndpoint.json
index 0486ebb5f37..61cd7cd5fe9 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/whenSkipSendToEndpoint.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/whenSkipSendToEndpoint.json
@@ -16,6 +16,6 @@
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "expression": { "index": 3, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "java", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "sec [...]
-    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
+    "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.ProcessorDefinition<java.lang.Object>>", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance [...]
   }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java
index efd82afa711..1fabeee1813 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java
@@ -124,18 +124,38 @@ public abstract class BuilderSupport implements CamelContextAware {
 
     /**
      * Returns a JOOR expression value builder
+     *
+     * @deprecated use java instead
      */
+    @Deprecated
     public ValueBuilder joor(String value) {
         return Builder.joor(value);
     }
 
     /**
      * Returns a JOOR expression value builder
+     *
+     * @deprecated use java instead
      */
+    @Deprecated
     public ValueBuilder joor(String value, Class<?> resultType) {
         return Builder.joor(value, resultType);
     }
 
+    /**
+     * Returns a Java expression value builder
+     */
+    public ValueBuilder java(String value) {
+        return Builder.java(value);
+    }
+
+    /**
+     * Returns a Java expression value builder
+     */
+    public ValueBuilder java(String value, Class<?> resultType) {
+        return Builder.java(value, resultType);
+    }
+
     /**
      * Returns a JSonPath expression value builder
      */
@@ -153,6 +173,20 @@ public abstract class BuilderSupport implements CamelContextAware {
         return Builder.jsonpath(value, resultType);
     }
 
+    /**
+     * Returns a JQ expression value builder
+     */
+    public ValueBuilder jq(String value) {
+        return Builder.jq(value);
+    }
+
+    /**
+     * Returns a JQ expression value builder
+     */
+    public ValueBuilder jq(String value, Class<?> resultType) {
+        return Builder.jq(value, resultType);
+    }
+
     /**
      * Returns a compiled simple expression value builder
      */
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
index 156de5bda88..af8278dd62a 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
@@ -2558,7 +2558,7 @@ public abstract class ProcessorDefinition<Type extends ProcessorDefinition<Type>
      * Adds a processor which sets the header on the IN message
      *
      * @param  name the header name
-     * @return      a expression builder clause to set the header
+     * @return      an expression builder clause to set the header
      */
     public ExpressionClause<ProcessorDefinition<Type>> setHeader(String name) {
         ExpressionClause<ProcessorDefinition<Type>> clause = new ExpressionClause<>(this);
@@ -2606,7 +2606,50 @@ public abstract class ProcessorDefinition<Type extends ProcessorDefinition<Type>
                 return supplier.get();
             }
         });
+        addOutput(answer);
+        return asType();
+    }
+
+    /**
+     * Adds a processor which sets the variable
+     *
+     * @param  name the variable name
+     * @return      an expression builder clause to set the variable
+     */
+    public ExpressionClause<ProcessorDefinition<Type>> setVariable(String name) {
+        ExpressionClause<ProcessorDefinition<Type>> clause = new ExpressionClause<>(this);
+        SetVariableDefinition answer = new SetVariableDefinition(name, clause);
+        addOutput(answer);
+        return clause;
+    }
+
+    /**
+     * Adds a processor which sets the variable
+     *
+     * @param  name       the variable name
+     * @param  expression the expression used to set the variable
+     * @return            the builder
+     */
+    public Type setVariable(String name, Expression expression) {
+        SetVariableDefinition answer = new SetVariableDefinition(name, expression);
+        addOutput(answer);
+        return asType();
+    }
 
+    /**
+     * Adds a processor which sets the variable
+     *
+     * @param  name     the variable name
+     * @param  supplier the supplier used to set the variable
+     * @return          the builder
+     */
+    public Type setVariable(String name, final Supplier<Object> supplier) {
+        SetVariableDefinition answer = new SetVariableDefinition(name, new ExpressionAdapter() {
+            @Override
+            public Object evaluate(Exchange exchange) {
+                return supplier.get();
+            }
+        });
         addOutput(answer);
         return asType();
     }
@@ -2693,6 +2736,18 @@ public abstract class ProcessorDefinition<Type extends ProcessorDefinition<Type>
         return asType();
     }
 
+    /**
+     * Adds a processor which removes the variable
+     *
+     * @param  name the variable name
+     * @return      the builder
+     */
+    public Type removeVariable(String name) {
+        RemoveVariableDefinition answer = new RemoveVariableDefinition(name);
+        addOutput(answer);
+        return asType();
+    }
+
     /**
      * Adds a processor which removes the exchange property
      *
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RemoveVariableDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RemoveVariableDefinition.java
new file mode 100644
index 00000000000..eea99806b31
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RemoveVariableDefinition.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.model;
+
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAttribute;
+import jakarta.xml.bind.annotation.XmlRootElement;
+
+import org.apache.camel.spi.Metadata;
+
+/**
+ * Removes a named variable
+ */
+@Metadata(label = "eip,transformation")
+@XmlRootElement(name = "removeVariable")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RemoveVariableDefinition extends NoOutputDefinition<RemoveVariableDefinition> {
+
+    @XmlAttribute(required = true)
+    private String name;
+
+    public RemoveVariableDefinition() {
+    }
+
+    public RemoveVariableDefinition(String variableName) {
+        this.name = variableName;
+    }
+
+    @Override
+    public String toString() {
+        return "RemoveVariable[" + name + "]";
+    }
+
+    @Override
+    public String getShortName() {
+        return "removeVariable";
+    }
+
+    @Override
+    public String getLabel() {
+        return "removeVariable[" + name + "]";
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Name of variable to remove.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/SetVariableDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/SetVariableDefinition.java
new file mode 100644
index 00000000000..86c5373f8c8
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/SetVariableDefinition.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.model;
+
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAttribute;
+import jakarta.xml.bind.annotation.XmlRootElement;
+
+import org.apache.camel.Expression;
+import org.apache.camel.builder.ExpressionBuilder;
+import org.apache.camel.model.language.ExpressionDefinition;
+import org.apache.camel.spi.Metadata;
+
+/**
+ * Sets the value of a variable
+ */
+@Metadata(label = "eip,transformation")
+@XmlRootElement(name = "setVariable")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class SetVariableDefinition extends ExpressionNode {
+
+    @XmlAttribute(required = true)
+    private String name;
+
+    public SetVariableDefinition() {
+    }
+
+    public SetVariableDefinition(String name, ExpressionDefinition expression) {
+        super(expression);
+        setName(name);
+    }
+
+    public SetVariableDefinition(String name, Expression expression) {
+        super(expression);
+        setName(name);
+    }
+
+    public SetVariableDefinition(String name, String value) {
+        super(ExpressionBuilder.constantExpression(value));
+        setName(name);
+    }
+
+    @Override
+    public String toString() {
+        return "SetVariable[" + getName() + ", " + getExpression() + "]";
+    }
+
+    @Override
+    public String getShortName() {
+        return "setVariable";
+    }
+
+    @Override
+    public String getLabel() {
+        return "setVariable[" + getName() + "]";
+    }
+
+    /**
+     * Expression to return the value of the variable
+     */
+    @Override
+    public void setExpression(ExpressionDefinition expression) {
+        // override to include javadoc what the expression is used for
+        super.setExpression(expression);
+    }
+
+    /**
+     * Name of variable to set a new value
+     * <p/>
+     * The <tt>simple</tt> language can be used to define a dynamic evaluated variable name to be used. Otherwise a
+     * constant name will be used.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+}
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/RemoveVariableProcessor.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/RemoveVariableProcessor.java
new file mode 100644
index 00000000000..bcc150ebfbd
--- /dev/null
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/RemoveVariableProcessor.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.processor;
+
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.Exchange;
+import org.apache.camel.Expression;
+import org.apache.camel.Traceable;
+import org.apache.camel.spi.IdAware;
+import org.apache.camel.spi.RouteIdAware;
+import org.apache.camel.spi.VariableRepository;
+import org.apache.camel.spi.VariableRepositoryFactory;
+import org.apache.camel.support.AsyncProcessorSupport;
+import org.apache.camel.util.StringHelper;
+
+/**
+ * A processor which removes the variable
+ */
+public class RemoveVariableProcessor extends AsyncProcessorSupport
+        implements Traceable, IdAware, RouteIdAware, CamelContextAware {
+    private CamelContext camelContext;
+    private String id;
+    private String routeId;
+    private final Expression variableName;
+    private VariableRepositoryFactory factory;
+
+    public RemoveVariableProcessor(Expression variableName) {
+        this.variableName = variableName;
+    }
+
+    @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    @Override
+    public boolean process(Exchange exchange, AsyncCallback callback) {
+        try {
+            String key = variableName.evaluate(exchange, String.class);
+            String id = StringHelper.before(key, ":");
+            if (id != null) {
+                VariableRepository repo = factory.getVariableRepository(id);
+                if (repo != null) {
+                    key = StringHelper.after(key, ":");
+                    repo.removeVariable(key);
+                } else {
+                    exchange.setException(
+                            new IllegalArgumentException("VariableRepository with id: " + id + " does not exists"));
+                }
+            } else {
+                exchange.removeVariable(key);
+            }
+        } catch (Exception e) {
+            exchange.setException(e);
+        }
+
+        callback.done(true);
+        return true;
+    }
+
+    @Override
+    protected void doBuild() throws Exception {
+        super.doBuild();
+        factory = getCamelContext().getCamelContextExtension().getContextPlugin(VariableRepositoryFactory.class);
+    }
+
+    @Override
+    public String toString() {
+        return id;
+    }
+
+    @Override
+    public String getTraceLabel() {
+        return "removeVariable[" + variableName + "]";
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getRouteId() {
+        return routeId;
+    }
+
+    @Override
+    public void setRouteId(String routeId) {
+        this.routeId = routeId;
+    }
+
+    public String getVariableName() {
+        return variableName.toString();
+    }
+
+}
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/SetVariableProcessor.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/SetVariableProcessor.java
new file mode 100644
index 00000000000..f0690902e27
--- /dev/null
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/SetVariableProcessor.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.processor;
+
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.Exchange;
+import org.apache.camel.Expression;
+import org.apache.camel.Traceable;
+import org.apache.camel.spi.IdAware;
+import org.apache.camel.spi.RouteIdAware;
+import org.apache.camel.spi.VariableRepository;
+import org.apache.camel.spi.VariableRepositoryFactory;
+import org.apache.camel.support.AsyncProcessorSupport;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
+
+/**
+ * A processor which sets the variable with an {@link Expression}
+ */
+public class SetVariableProcessor extends AsyncProcessorSupport implements Traceable, IdAware, RouteIdAware, CamelContextAware {
+
+    private CamelContext camelContext;
+    private String id;
+    private String routeId;
+    private final Expression variableName;
+    private final Expression expression;
+    private VariableRepositoryFactory factory;
+
+    public SetVariableProcessor(Expression variableName, Expression expression) {
+        this.variableName = variableName;
+        this.expression = expression;
+        ObjectHelper.notNull(variableName, "variableName");
+        ObjectHelper.notNull(expression, "expression");
+    }
+
+    @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    @Override
+    public boolean process(Exchange exchange, AsyncCallback callback) {
+        try {
+            Object newVariable = expression.evaluate(exchange, Object.class);
+
+            if (exchange.getException() != null) {
+                // the expression threw an exception so we should break-out
+                callback.done(true);
+                return true;
+            }
+
+            String key = variableName.evaluate(exchange, String.class);
+            String id = StringHelper.before(key, ":");
+            if (id != null) {
+                VariableRepository repo = factory.getVariableRepository(id);
+                if (repo != null) {
+                    key = StringHelper.after(key, ":");
+                    repo.setVariable(key, newVariable);
+                } else {
+                    exchange.setException(
+                            new IllegalArgumentException("VariableRepository with id: " + id + " does not exists"));
+                }
+            } else {
+                exchange.setVariable(key, newVariable);
+            }
+        } catch (Exception e) {
+            exchange.setException(e);
+        }
+
+        callback.done(true);
+        return true;
+    }
+
+    @Override
+    protected void doBuild() throws Exception {
+        super.doBuild();
+        factory = getCamelContext().getCamelContextExtension().getContextPlugin(VariableRepositoryFactory.class);
+    }
+
+    @Override
+    public String toString() {
+        return id;
+    }
+
+    @Override
+    public String getTraceLabel() {
+        return "setVariable[" + variableName + ", " + expression + "]";
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getRouteId() {
+        return routeId;
+    }
+
+    @Override
+    public void setRouteId(String routeId) {
+        this.routeId = routeId;
+    }
+
+    public String getVariableName() {
+        return variableName.toString();
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java
index 258e4733387..e35292084fa 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java
@@ -76,6 +76,7 @@ import org.apache.camel.model.RemoveHeaderDefinition;
 import org.apache.camel.model.RemoveHeadersDefinition;
 import org.apache.camel.model.RemovePropertiesDefinition;
 import org.apache.camel.model.RemovePropertyDefinition;
+import org.apache.camel.model.RemoveVariableDefinition;
 import org.apache.camel.model.ResequenceDefinition;
 import org.apache.camel.model.ResumableDefinition;
 import org.apache.camel.model.RollbackDefinition;
@@ -90,6 +91,7 @@ import org.apache.camel.model.SetExchangePatternDefinition;
 import org.apache.camel.model.SetHeaderDefinition;
 import org.apache.camel.model.SetHeadersDefinition;
 import org.apache.camel.model.SetPropertyDefinition;
+import org.apache.camel.model.SetVariableDefinition;
 import org.apache.camel.model.SortDefinition;
 import org.apache.camel.model.SplitDefinition;
 import org.apache.camel.model.StepDefinition;
@@ -273,6 +275,8 @@ public abstract class ProcessorReifier<T extends ProcessorDefinition<?>> extends
             return new RemovePropertyReifier(route, definition);
         } else if (definition instanceof RemovePropertiesDefinition) {
             return new RemovePropertiesReifier(route, definition);
+        } else if (definition instanceof RemoveVariableDefinition) {
+            return new RemoveVariableReifier(route, definition);
         } else if (definition instanceof ResequenceDefinition) {
             return new ResequenceReifier(route, definition);
         } else if (definition instanceof RollbackDefinition) {
@@ -297,6 +301,8 @@ public abstract class ProcessorReifier<T extends ProcessorDefinition<?>> extends
             return new SetHeadersReifier(route, definition);
         } else if (definition instanceof SetPropertyDefinition) {
             return new SetPropertyReifier(route, definition);
+        } else if (definition instanceof SetVariableDefinition) {
+            return new SetVariableReifier(route, definition);
         } else if (definition instanceof SortDefinition) {
             return new SortReifier<>(route, definition);
         } else if (definition instanceof SplitDefinition) {
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RemoveVariableReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RemoveVariableReifier.java
new file mode 100644
index 00000000000..4774ac0c231
--- /dev/null
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RemoveVariableReifier.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.reifier;
+
+import org.apache.camel.Expression;
+import org.apache.camel.Processor;
+import org.apache.camel.Route;
+import org.apache.camel.model.ProcessorDefinition;
+import org.apache.camel.model.RemoveVariableDefinition;
+import org.apache.camel.processor.RemoveVariableProcessor;
+import org.apache.camel.support.LanguageSupport;
+
+public class RemoveVariableReifier extends ProcessorReifier<RemoveVariableDefinition> {
+
+    public RemoveVariableReifier(Route route, ProcessorDefinition<?> definition) {
+        super(route, (RemoveVariableDefinition) definition);
+    }
+
+    @Override
+    public Processor createProcessor() throws Exception {
+        Expression nameExpr;
+        String key = parseString(definition.getName());
+        if (LanguageSupport.hasSimpleFunction(key)) {
+            nameExpr = camelContext.resolveLanguage("simple").createExpression(key);
+        } else {
+            nameExpr = camelContext.resolveLanguage("constant").createExpression(key);
+        }
+        nameExpr.init(camelContext);
+        return new RemoveVariableProcessor(nameExpr);
+    }
+}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SetVariableReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SetVariableReifier.java
new file mode 100644
index 00000000000..a2b983ea71e
--- /dev/null
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SetVariableReifier.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.reifier;
+
+import org.apache.camel.Expression;
+import org.apache.camel.Processor;
+import org.apache.camel.Route;
+import org.apache.camel.model.ProcessorDefinition;
+import org.apache.camel.model.SetVariableDefinition;
+import org.apache.camel.processor.SetVariableProcessor;
+import org.apache.camel.support.LanguageSupport;
+import org.apache.camel.util.ObjectHelper;
+
+public class SetVariableReifier extends ExpressionReifier<SetVariableDefinition> {
+
+    public SetVariableReifier(Route route, ProcessorDefinition<?> definition) {
+        super(route, (SetVariableDefinition) definition);
+    }
+
+    @Override
+    public Processor createProcessor() throws Exception {
+        ObjectHelper.notNull(definition.getName(), "variableName");
+        Expression expr = createExpression(definition.getExpression());
+        Expression nameExpr;
+        String key = parseString(definition.getName());
+        if (LanguageSupport.hasSimpleFunction(key)) {
+            nameExpr = camelContext.resolveLanguage("simple").createExpression(key);
+        } else {
+            nameExpr = camelContext.resolveLanguage("constant").createExpression(key);
+        }
+        nameExpr.init(camelContext);
+        return new SetVariableProcessor(nameExpr, expr);
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/ExchangeTestSupport.java b/core/camel-core/src/test/java/org/apache/camel/ExchangeTestSupport.java
index 422d82d141f..872c588d6e3 100644
--- a/core/camel-core/src/test/java/org/apache/camel/ExchangeTestSupport.java
+++ b/core/camel-core/src/test/java/org/apache/camel/ExchangeTestSupport.java
@@ -44,6 +44,7 @@ public abstract class ExchangeTestSupport extends ContextTestSupport {
         in.setBody("<hello id='m123'>world!</hello>");
 
         exchange.setProperty("foobar", "cba");
+        exchange.setVariable("cheese", "gauda");
     }
 
     @Override
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanPipelineVariablesTest.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanPipelineVariablesTest.java
new file mode 100644
index 00000000000..02355fd2da8
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanPipelineVariablesTest.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.bean;
+
+import java.util.Map;
+
+import org.apache.camel.Body;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.Variables;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spi.Registry;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * Unit test of bean can propagate headers in a pipeline
+ */
+public class BeanPipelineVariablesTest extends ContextTestSupport {
+
+    @Test
+    public void testBeanInPipeline() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceived("Hello World from James");
+        mock.expectedVariableReceived("from", "James");
+
+        template.sendBodyAndHeader("direct:input", "Hello World", "from", "Claus");
+        mock.assertIsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() throws Exception {
+                from("direct:input").pipeline("bean:foo", "bean:bar?method=usingExchange", "bean:baz").to("mock:result");
+            }
+        };
+    }
+
+    @Override
+    protected Registry createRegistry() throws Exception {
+        Registry answer = super.createRegistry();
+        answer.bind("foo", new FooBean());
+        answer.bind("bar", new BarBean());
+        answer.bind("baz", new BazBean());
+        return answer;
+    }
+
+    public static class FooBean {
+        public void onlyPlainBody(Object body) {
+            assertEquals("Hello World", body);
+        }
+    }
+
+    public static class BarBean {
+        public void doNotUseMe(String body) {
+            fail("Should not invoce me");
+        }
+
+        public void usingExchange(Exchange exchange) {
+            String body = exchange.getIn().getBody(String.class);
+            assertEquals("Hello World", body);
+            assertEquals("Claus", exchange.getIn().getHeader("from"));
+            exchange.setVariable("from", "James");
+            exchange.getMessage().setBody("Hello World from James");
+        }
+    }
+
+    public static class BazBean {
+        public void doNotUseMe(String body) {
+            fail("Should not invoce me");
+        }
+
+        public void withAnnotations(@Variables Map<String, Object> variables, @Body String body) {
+            assertEquals("Hello World from James", body);
+            assertEquals("James", variables.get("from"));
+        }
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithPropertiesAndVariablesInjectionTest.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithPropertiesAndVariablesInjectionTest.java
new file mode 100644
index 00000000000..b627ce63ead
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithPropertiesAndVariablesInjectionTest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.bean;
+
+import java.util.Map;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.ExchangeProperties;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.Variables;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.processor.BeanRouteTest;
+import org.apache.camel.spi.Registry;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class BeanWithPropertiesAndVariablesInjectionTest extends ContextTestSupport {
+    private static final Logger LOG = LoggerFactory.getLogger(BeanRouteTest.class);
+    protected MyBean myBean = new MyBean();
+
+    @Test
+    public void testSendMessage() throws Exception {
+        template.send("direct:in", new Processor() {
+            public void process(Exchange exchange) throws Exception {
+                exchange.setProperty("p1", "abc");
+                exchange.setProperty("p2", 123);
+
+                Message in = exchange.getIn();
+                exchange.setVariable("h1", "xyz");
+                exchange.setVariable("h2", 456);
+            }
+        });
+
+        Map<?, ?> foo = myBean.foo;
+        Map<?, ?> bar = myBean.bar;
+        assertNotNull(foo, "myBean.foo");
+        assertNotNull(bar, "myBean.bar");
+
+        assertEquals("abc", foo.get("p1"), "foo.p1");
+        assertEquals(123, foo.get("p2"), "foo.p2");
+
+        assertEquals("xyz", bar.get("h1"), "bar.h1");
+        assertEquals(456, bar.get("h2"), "bar.h2");
+    }
+
+    @Override
+    protected Registry createRegistry() throws Exception {
+        Registry answer = super.createRegistry();
+        answer.bind("myBean", myBean);
+        return answer;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:in").bean("myBean");
+            }
+        };
+    }
+
+    public static class MyBean {
+        public Map<?, ?> foo;
+        public Map<?, ?> bar;
+
+        @Override
+        public String toString() {
+            return "MyBean[foo: " + foo + " bar: " + bar + "]";
+        }
+
+        public void myMethod(@ExchangeProperties Map<?, ?> foo, @Variables Map<?, ?> bar) {
+            this.foo = foo;
+            this.bar = bar;
+            LOG.info("myMethod() method called on {}", this);
+        }
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInject3Test.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInject3Test.java
new file mode 100644
index 00000000000..795f0ca46bd
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInject3Test.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.bean;
+
+import java.util.Map;
+
+import org.apache.camel.Body;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Variables;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spi.Registry;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class BeanWithVariablesAndBodyInject3Test extends ContextTestSupport {
+    private final MyBean myBean = new MyBean();
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:start").to("bean:myBean?method=doSomething").to("mock:finish");
+            }
+        };
+    }
+
+    @Test
+    public void testInOnly() throws Exception {
+        MockEndpoint end = getMockEndpoint("mock:finish");
+        end.expectedBodiesReceived("Hello!");
+
+        sendBody("direct:start", "Test Input");
+
+        assertMockEndpointsSatisfied();
+
+        assertNotNull(end.getExchanges().get(0).getIn().getBody());
+        assertEquals("Hello!", end.getExchanges().get(0).getIn().getBody());
+    }
+
+    @Test
+    public void testInOut() throws Exception {
+        MockEndpoint end = getMockEndpoint("mock:finish");
+        end.expectedBodiesReceived("Hello!");
+        end.expectedVariableReceived("out", 123);
+
+        String out = template.requestBody("direct:start", "Test Input", String.class);
+        assertEquals("Hello!", out);
+
+        assertMockEndpointsSatisfied();
+
+        assertNotNull(end.getExchanges().get(0).getIn().getBody());
+        assertEquals("Hello!", end.getExchanges().get(0).getIn().getBody());
+        assertEquals(123, end.getExchanges().get(0).getVariable("out"));
+    }
+
+    @Override
+    protected Registry createRegistry() throws Exception {
+        Registry answer = super.createRegistry();
+        answer.bind("myBean", myBean);
+        return answer;
+    }
+
+    public static class MyBean {
+
+        public String doSomething(@Body String body, @Variables Map<String, Object> variables) {
+            variables.put("out", 123);
+            return "Hello!";
+        }
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInjectionTest.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInjectionTest.java
new file mode 100644
index 00000000000..e1245c0cdeb
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInjectionTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.bean;
+
+import java.util.Map;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.Variables;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.processor.BeanRouteTest;
+import org.apache.camel.spi.Registry;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.fail;
+
+public class BeanWithVariablesAndBodyInjectionTest extends ContextTestSupport {
+    private static final Logger LOG = LoggerFactory.getLogger(BeanRouteTest.class);
+    protected MyBean myBean = new MyBean();
+
+    @Test
+    public void testSendMessage() throws Exception {
+        template.send("direct:in", new Processor() {
+            public void process(Exchange exchange) throws Exception {
+                exchange.setProperty("p1", "abc");
+                exchange.setProperty("p2", 123);
+
+                Message in = exchange.getIn();
+                exchange.setVariable("h1", "xyz");
+                exchange.setVariable("h2", 456);
+                in.setBody("TheBody");
+            }
+        });
+
+        Map<String, Object> foo = myBean.variables;
+        assertNotNull(foo, "myBean.foo");
+
+        assertEquals("xyz", foo.get("h1"), "foo.h1");
+        assertEquals(456, foo.get("h2"), "foo.h2");
+
+        assertEquals("TheBody", myBean.body, "body");
+    }
+
+    @Override
+    protected Registry createRegistry() throws Exception {
+        Registry answer = super.createRegistry();
+        answer.bind("myBean", myBean);
+        return answer;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:in").to("bean:myBean?method=myMethod");
+            }
+        };
+    }
+
+    public static class MyBean {
+        public Map<String, Object> variables;
+        public Object body;
+
+        @Override
+        public String toString() {
+            return "MyBean[foo: " + variables + " body: " + body + "]";
+        }
+
+        public void myMethod(@Variables Map<String, Object> variables, Object body) {
+            this.variables = variables;
+            this.body = body;
+            LOG.info("myMethod() method called on {}", this);
+        }
+
+        public void anotherMethod(@Variables Map<String, Object> variables, Object body) {
+            fail("Should not have called this method!");
+        }
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/log/DefaultExchangeFormatterTest.java b/core/camel-core/src/test/java/org/apache/camel/component/log/DefaultExchangeFormatterTest.java
index 0f7ffc779d7..449b76c5204 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/log/DefaultExchangeFormatterTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/log/DefaultExchangeFormatterTest.java
@@ -176,6 +176,7 @@ public class DefaultExchangeFormatterTest extends ContextTestSupport {
         assertFalse(formatter.isShowExchangeId());
         assertFalse(formatter.isShowProperties());
         assertFalse(formatter.isShowHeaders());
+        assertFalse(formatter.isShowVariables());
         assertTrue(formatter.isShowBodyType());
         assertTrue(formatter.isShowBody());
         assertFalse(formatter.isShowException());
diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/DefaultExchangeTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/DefaultExchangeTest.java
index 6147d9877ec..8bafb939671 100644
--- a/core/camel-core/src/test/java/org/apache/camel/impl/DefaultExchangeTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/DefaultExchangeTest.java
@@ -142,6 +142,30 @@ public class DefaultExchangeTest extends ExchangeTestSupport {
         assertEquals("banana", exchange.getProperty("beer", "banana", String.class));
     }
 
+    @Test
+    public void testVariable() throws Exception {
+        exchange.removeVariable("cheese");
+        assertFalse(exchange.hasVariables());
+
+        exchange.setVariable("fruit", "apple");
+        assertTrue(exchange.hasVariables());
+
+        assertEquals("apple", exchange.getVariable("fruit"));
+        assertNull(exchange.getVariable("beer"));
+        assertNull(exchange.getVariable("beer", String.class));
+
+        // Current TypeConverter support to turn the null value to false of
+        // boolean,
+        // as assertEquals needs the Object as the parameter, we have to use
+        // Boolean.FALSE value in this case
+        assertEquals(Boolean.FALSE, exchange.getVariable("beer", boolean.class));
+        assertNull(exchange.getVariable("beer", Boolean.class));
+
+        assertEquals("apple", exchange.getVariable("fruit", String.class));
+        assertEquals("apple", exchange.getVariable("fruit", "banana", String.class));
+        assertEquals("banana", exchange.getVariable("beer", "banana", String.class));
+    }
+
     @Test
     public void testRemoveProperties() throws Exception {
         exchange.removeProperty("foobar");
@@ -164,6 +188,21 @@ public class DefaultExchangeTest extends ExchangeTestSupport {
         assertEquals("Africa", exchange.getProperty("zone", String.class));
     }
 
+    @Test
+    public void testRemoveVariables() throws Exception {
+        exchange.removeVariable("cheese");
+        assertFalse(exchange.hasVariables());
+
+        exchange.setVariable("fruit", "apple");
+        exchange.setVariable("fruit1", "banana");
+        exchange.setVariable("zone", "Africa");
+        assertTrue(exchange.hasVariables());
+
+        assertEquals("apple", exchange.getVariable("fruit"));
+        assertEquals("banana", exchange.getVariable("fruit1"));
+        assertEquals("Africa", exchange.getVariable("zone"));
+    }
+
     @Test
     public void testRemoveAllProperties() throws Exception {
         exchange.removeProperty("foobar");
@@ -179,6 +218,21 @@ public class DefaultExchangeTest extends ExchangeTestSupport {
         assertEquals(0, exchange.getProperties().size());
     }
 
+    @Test
+    public void testRemoveAllVariables() throws Exception {
+        exchange.removeVariable("cheese");
+        assertFalse(exchange.hasVariables());
+
+        exchange.setVariable("fruit", "apple");
+        exchange.setVariable("fruit1", "banana");
+        exchange.setVariable("zone", "Africa");
+        assertTrue(exchange.hasVariables());
+
+        exchange.removeVariable("*");
+        assertFalse(exchange.hasVariables());
+        assertEquals(0, exchange.getVariables().size());
+    }
+
     @Test
     public void testRemovePropertiesWithExclusion() throws Exception {
         exchange.removeProperty("foobar");
@@ -265,6 +319,31 @@ public class DefaultExchangeTest extends ExchangeTestSupport {
         assertEquals(3, exchange.getAllProperties().size());
     }
 
+    @Test
+    public void testCopyExchangeWithVariables() throws Exception {
+        exchange.setVariable("beer", "Carlsberg");
+        assertEquals(2, exchange.getVariables().size());
+
+        Exchange copy = exchange.copy();
+        assertTrue(copy.hasVariables());
+        assertEquals(2, copy.getVariables().size());
+        assertEquals("gauda", copy.getVariable("cheese"));
+        assertEquals("Carlsberg", copy.getVariable("beer"));
+
+        exchange.setVariable("beer", "Heineken");
+        assertEquals("Carlsberg", copy.getVariable("beer"));
+
+        exchange.removeVariable("beer");
+        assertEquals(1, exchange.getVariables().size());
+        assertEquals("Carlsberg", copy.getVariable("beer"));
+        assertEquals(2, copy.getVariables().size());
+
+        exchange.removeVariable("*");
+        assertFalse(exchange.hasVariables());
+        assertTrue(copy.hasVariables());
+        assertEquals(2, copy.getVariables().size());
+    }
+
     @Test
     public void testInType() throws Exception {
         exchange.setIn(new MyMessage(context));
diff --git a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
index f6d5e1a8586..7550edc2ca4 100644
--- a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
@@ -45,6 +45,8 @@ import org.apache.camel.spi.Language;
 import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.spi.Registry;
 import org.apache.camel.spi.UuidGenerator;
+import org.apache.camel.spi.VariableRepository;
+import org.apache.camel.spi.VariableRepositoryFactory;
 import org.apache.camel.util.InetAddressUtil;
 import org.apache.camel.util.StringHelper;
 import org.junit.jupiter.api.Test;
@@ -62,7 +64,6 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 public class SimpleTest extends LanguageTestSupport {
 
-    private static final String JAVA8_INDEX_OUT_OF_BOUNDS_ERROR_MSG = "Index: 2, Size: 2";
     private static final String INDEX_OUT_OF_BOUNDS_ERROR_MSG = "Index 2 out of bounds for length 2";
 
     @Override
@@ -941,6 +942,113 @@ public class SimpleTest extends LanguageTestSupport {
         }
     }
 
+    @Test
+    public void testVariables() throws Exception {
+        exchange.getVariables().putAll(exchange.getMessage().getHeaders());
+        exchange.getMessage().removeHeaders("*");
+
+        Map<String, Object> variables = exchange.getVariables();
+        assertEquals(3, variables.size());
+
+        assertExpression("${variables}", variables);
+    }
+
+    @Test
+    public void testGlobalVariable() throws Exception {
+        // exchange has 1 variable already set
+        Map<String, Object> variables = exchange.getVariables();
+        assertEquals(1, variables.size());
+
+        VariableRepository global = context.getCamelContextExtension().getContextPlugin(VariableRepositoryFactory.class)
+                .getVariableRepository("global");
+        global.setVariable("foo", "123");
+        global.setVariable("bar", "456");
+        global.setVariable("cheese", "gorgonzola");
+
+        // exchange scoped
+        assertExpression("${variable.cheese}", "gauda");
+        assertExpression("${variable.foo}", null);
+        assertExpression("${variable.bar}", null);
+
+        // global scoped
+        assertExpression("${variable.global:cheese}", "gorgonzola");
+        assertExpression("${variable.global:foo}", "123");
+        assertExpression("${variable.global:bar}", "456");
+
+        // exchange scoped
+        assertExpression("${variableAs('cheese', 'String')}", "gauda");
+        assertExpression("${variableAs('foo', 'int')}", null);
+        assertExpression("${variableAA('bar', 'int')}", null);
+
+        // global scoped
+        assertExpression("${variableAs('global:cheese', 'String')}", "gorgonzola");
+        assertExpression("${variableAs('global:foo', 'int')}", 123);
+        assertExpression("${variableAs('global:bar', 'int')}", 456);
+    }
+
+    @Test
+    public void testVariableKeyWithSpace() throws Exception {
+        exchange.getVariables().putAll(exchange.getMessage().getHeaders());
+        exchange.getMessage().removeHeaders("*");
+
+        Map<String, Object> variables = exchange.getVariables();
+        variables.put("some key", "Some Value");
+        assertEquals(4, variables.size());
+
+        assertExpression("${variableAs(foo,String)}", "abc");
+        assertExpression("${variableAs(some key,String)}", "Some Value");
+        assertExpression("${variableAs('some key',String)}", "Some Value");
+
+        assertExpression("${variable[foo]}", "abc");
+        assertExpression("${variable[cheese]}", "gauda");
+        assertExpression("${variable[some key]}", "Some Value");
+        assertExpression("${variable['some key']}", "Some Value");
+
+        assertExpression("${variables[foo]}", "abc");
+        assertExpression("${variables[cheese]}", "gauda");
+        assertExpression("${variables[some key]}", "Some Value");
+        assertExpression("${variables['some key']}", "Some Value");
+    }
+
+    @Test
+    public void testVariableAs() throws Exception {
+        exchange.getVariables().putAll(exchange.getMessage().getHeaders());
+        exchange.getMessage().removeHeaders("*");
+
+        assertExpression("${variableAs(foo,String)}", "abc");
+
+        assertExpression("${variableAs(bar,int)}", 123);
+        assertExpression("${variableAs(bar, int)}", 123);
+        assertExpression("${variableAs('bar', int)}", 123);
+        assertExpression("${variableAs('bar','int')}", 123);
+        assertExpression("${variableAs('bar','Integer')}", 123);
+        assertExpression("${variableAs('bar',\"int\")}", 123);
+        assertExpression("${variableAs(bar,String)}", "123");
+
+        assertExpression("${variableAs(unknown,String)}", null);
+
+        try {
+            assertExpression("${variableAs(unknown String)}", null);
+            fail("Should have thrown an exception");
+        } catch (ExpressionIllegalSyntaxException e) {
+            assertTrue(e.getMessage().startsWith("Valid syntax: ${variableAs(key, type)} was: variableAs(unknown String)"));
+        }
+
+        try {
+            assertExpression("${variableAs(fool,String).test}", null);
+            fail("Should have thrown an exception");
+        } catch (ExpressionIllegalSyntaxException e) {
+            assertTrue(e.getMessage().startsWith("Valid syntax: ${variableAs(key, type)} was: variableAs(fool,String).test"));
+        }
+
+        try {
+            assertExpression("${variableAs(bar,XXX)}", 123);
+            fail("Should have thrown an exception");
+        } catch (CamelExecutionException e) {
+            assertIsInstanceOf(ClassNotFoundException.class, e.getCause());
+        }
+    }
+
     @Test
     public void testIllegalSyntax() throws Exception {
         try {
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/CustomGlobalVariableTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/CustomGlobalVariableTest.java
new file mode 100644
index 00000000000..609ed161d27
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/CustomGlobalVariableTest.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.processor;
+
+import java.util.List;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spi.VariableRepository;
+import org.apache.camel.support.service.ServiceSupport;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.camel.spi.VariableRepositoryFactory.GLOBAL_VARIABLE_REPOSITORY_ID;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class CustomGlobalVariableTest extends ContextTestSupport {
+    private MockEndpoint end;
+    private String variableName = "foo";
+    private String expectedVariableValue = "bar";
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        context.getRegistry().bind(GLOBAL_VARIABLE_REPOSITORY_ID, new MyGlobalRepo());
+        return context;
+    }
+
+    @Test
+    public void testSetExchangeVariableMidRoute() throws Exception {
+        assertNull(context.getVariable(variableName));
+
+        end.expectedMessageCount(1);
+
+        template.sendBody("direct:start", "<blah/>");
+
+        // make sure we got the message
+        assertMockEndpointsSatisfied();
+
+        // lets get the variable value
+        List<Exchange> exchanges = end.getExchanges();
+        Exchange exchange = exchanges.get(0);
+        String actualVariableValue = exchange.getVariable(variableName, String.class);
+        // should be stored on global so null
+        assertNull(actualVariableValue);
+
+        // should be stored as global variable
+        assertEquals("!" + expectedVariableValue + "!", context.getVariable(variableName));
+    }
+
+    @Override
+    @BeforeEach
+    public void setUp() throws Exception {
+        super.setUp();
+        end = getMockEndpoint("mock:end");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                // stored as global variable
+                from("direct:start").setVariable("global:" + variableName).constant(expectedVariableValue).to("mock:end");
+            }
+        };
+    }
+
+    private static class MyGlobalRepo extends ServiceSupport implements VariableRepository {
+
+        private Object value;
+
+        @Override
+        public String getId() {
+            return "myGlobal";
+        }
+
+        @Override
+        public Object getVariable(String name) {
+            if (value != null) {
+                return "!" + value + "!";
+            }
+            return null;
+        }
+
+        @Override
+        public void setVariable(String name, Object value) {
+            this.value = value;
+        }
+
+        @Override
+        public Object removeVariable(String name) {
+            return null;
+        }
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/MethodFilterVariableTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/MethodFilterVariableTest.java
new file mode 100644
index 00000000000..15a510d7c3a
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/MethodFilterVariableTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.processor;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.Variable;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.Registry;
+import org.junit.jupiter.api.Test;
+
+public class MethodFilterVariableTest extends ContextTestSupport {
+    @Test
+    public void testSendMatchingMessage() throws Exception {
+        String body = "<person name='James' city='London'/>";
+        getMockEndpoint("mock:result").expectedBodiesReceived(body);
+
+        template.sendBodyAndHeader("direct:start", ExchangePattern.InOut, body, "city", "London");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testSendNotMatchingMessage() throws Exception {
+        String body = "<person name='Hiram' city='Tampa'/>";
+        getMockEndpoint("mock:result").expectedMessageCount(0);
+
+        template.sendBodyAndHeader("direct:start", ExchangePattern.InOut, body, "city", "Tampa");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                // START SNIPPET: example
+                from("direct:start")
+                        .setVariable("location", header("city"))
+                        .filter().method("myBean", "matches").to("mock:result");
+                // END SNIPPET: example
+            }
+        };
+    }
+
+    @Override
+    protected Registry createRegistry() throws Exception {
+        Registry answer = super.createRegistry();
+        answer.bind("myBean", new MyBean());
+        return answer;
+    }
+
+    // START SNIPPET: filter
+    public static class MyBean {
+        public boolean matches(@Variable("location") String location) {
+            return "London".equals(location);
+        }
+    }
+    // END SNIPPET: filter
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/RemoveGlobalVariableTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/RemoveGlobalVariableTest.java
new file mode 100644
index 00000000000..44ab6ae7a34
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/RemoveGlobalVariableTest.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.processor;
+
+import java.util.List;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class RemoveGlobalVariableTest extends ContextTestSupport {
+    private MockEndpoint end;
+    private MockEndpoint mid;
+    private String variableName = "foo";
+    private String expectedVariableValue = "bar";
+
+    @Test
+    public void testSetHeaderMidRouteThenRemove() throws Exception {
+        mid.expectedMessageCount(1);
+        end.expectedMessageCount(1);
+
+        template.sendBody("direct:start", "<blah/>");
+
+        // make sure we got the message
+        assertMockEndpointsSatisfied();
+
+        List<Exchange> midExchanges = mid.getExchanges();
+        Exchange midExchange = midExchanges.get(0);
+        String actualVariableValue = midExchange.getVariable(variableName, String.class);
+        // should be stored on global so null
+        assertNull(actualVariableValue);
+
+        List<Exchange> endExchanges = end.getExchanges();
+        Exchange endExchange = endExchanges.get(0);
+
+        // should be stored as global variable (but removed)
+        assertNull(context.getVariable(variableName));
+    }
+
+    @Override
+    @BeforeEach
+    public void setUp() throws Exception {
+        super.setUp();
+        end = getMockEndpoint("mock:end");
+        mid = getMockEndpoint("mock:mid");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:start").setVariable("global:" + variableName).constant(expectedVariableValue).to("mock:mid")
+                        .removeVariable("global:" + variableName)
+                        .to("mock:end");
+            }
+        };
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/RemoveVariableTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/RemoveVariableTest.java
new file mode 100644
index 00000000000..10fe7d440cc
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/RemoveVariableTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.processor;
+
+import java.util.List;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class RemoveVariableTest extends ContextTestSupport {
+    private MockEndpoint end;
+    private MockEndpoint mid;
+    private String variableName = "foo";
+    private String expectedVariableValue = "bar";
+
+    @Test
+    public void testSetHeaderMidRouteThenRemove() throws Exception {
+        mid.expectedMessageCount(1);
+        end.expectedMessageCount(1);
+
+        template.sendBody("direct:start", "<blah/>");
+
+        // make sure we got the message
+        assertMockEndpointsSatisfied();
+
+        List<Exchange> midExchanges = mid.getExchanges();
+        Exchange midExchange = midExchanges.get(0);
+        String actualVariableValue = midExchange.getVariable(variableName, String.class);
+
+        assertEquals(expectedVariableValue, actualVariableValue);
+
+        List<Exchange> endExchanges = end.getExchanges();
+        Exchange endExchange = endExchanges.get(0);
+
+        // header should be removed
+        assertNull(endExchange.getVariable(variableName, String.class));
+    }
+
+    @Override
+    @BeforeEach
+    public void setUp() throws Exception {
+        super.setUp();
+        end = getMockEndpoint("mock:end");
+        mid = getMockEndpoint("mock:mid");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:start").setVariable(variableName).constant(expectedVariableValue).to("mock:mid")
+                        .removeVariable(variableName)
+                        .to("mock:end");
+            }
+        };
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/SetGlobalVariableTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/SetGlobalVariableTest.java
new file mode 100644
index 00000000000..7870bd292f1
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/SetGlobalVariableTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.processor;
+
+import java.util.List;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class SetGlobalVariableTest extends ContextTestSupport {
+    private MockEndpoint end;
+    private String variableName = "foo";
+    private String expectedVariableValue = "bar";
+
+    @Test
+    public void testSetExchangeVariableMidRoute() throws Exception {
+        assertNull(context.getVariable(variableName));
+
+        end.expectedMessageCount(1);
+
+        template.sendBody("direct:start", "<blah/>");
+
+        // make sure we got the message
+        assertMockEndpointsSatisfied();
+
+        // lets get the variable value
+        List<Exchange> exchanges = end.getExchanges();
+        Exchange exchange = exchanges.get(0);
+        String actualVariableValue = exchange.getVariable(variableName, String.class);
+        // should be stored on global so null
+        assertNull(actualVariableValue);
+
+        // should be stored as global variable
+        assertEquals(expectedVariableValue, context.getVariable(variableName));
+    }
+
+    @Override
+    @BeforeEach
+    public void setUp() throws Exception {
+        super.setUp();
+        end = getMockEndpoint("mock:end");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                // stored as global variable
+                from("direct:start").setVariable("global:" + variableName).constant(expectedVariableValue).to("mock:end");
+            }
+        };
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/SetVariableTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/SetVariableTest.java
new file mode 100644
index 00000000000..d3cacb3645e
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/SetVariableTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.processor;
+
+import java.util.List;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class SetVariableTest extends ContextTestSupport {
+    private MockEndpoint end;
+    private String variableName = "foo";
+    private String expectedVariableValue = "bar";
+
+    @Test
+    public void testSetExchangeVariableMidRoute() throws Exception {
+        end.expectedMessageCount(1);
+
+        template.sendBody("direct:start", "<blah/>");
+
+        // make sure we got the message
+        assertMockEndpointsSatisfied();
+
+        // lets get the variable value
+        List<Exchange> exchanges = end.getExchanges();
+        Exchange exchange = exchanges.get(0);
+        String actualVariableValue = exchange.getVariable(variableName, String.class);
+
+        assertEquals(expectedVariableValue, actualVariableValue);
+    }
+
+    @Override
+    @BeforeEach
+    public void setUp() throws Exception {
+        super.setUp();
+        end = getMockEndpoint("mock:end");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:start").setVariable(variableName).constant(expectedVariableValue).to("mock:end");
+            }
+        };
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/util/ExchangeHelperTest.java b/core/camel-core/src/test/java/org/apache/camel/util/ExchangeHelperTest.java
index cf4331c12a2..ab3fd5f157d 100644
--- a/core/camel-core/src/test/java/org/apache/camel/util/ExchangeHelperTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/util/ExchangeHelperTest.java
@@ -116,7 +116,7 @@ public class ExchangeHelperTest extends ContextTestSupport {
         Map<String, Object> map = new HashMap<>();
         ExchangeHelper.populateVariableMap(exchange, map, false);
 
-        assertEquals(2, map.size());
+        assertEquals(3, map.size());
         assertNull(map.get("exchange"));
         assertNull(map.get("in"));
         assertNull(map.get("request"));
@@ -124,6 +124,7 @@ public class ExchangeHelperTest extends ContextTestSupport {
         assertNull(map.get("response"));
         assertSame(exchange.getIn().getHeaders(), map.get("headers"));
         assertSame(exchange.getIn().getBody(), map.get("body"));
+        assertSame(exchange.getVariable("cheese"), map.get("cheese"));
         assertNull(map.get("camelContext"));
     }
 
@@ -136,7 +137,7 @@ public class ExchangeHelperTest extends ContextTestSupport {
         Map<String, Object> map = new HashMap<>();
         ExchangeHelper.populateVariableMap(exchange, map, true);
 
-        assertEquals(8, map.size());
+        assertEquals(9, map.size());
         assertSame(exchange, map.get("exchange"));
         assertSame(exchange.getIn(), map.get("in"));
         assertSame(exchange.getIn(), map.get("request"));
@@ -152,10 +153,11 @@ public class ExchangeHelperTest extends ContextTestSupport {
         exchange.setPattern(ExchangePattern.InOut);
         exchange.getMessage().setBody("bar");
         exchange.getMessage().setHeader("quote", "Camel rocks");
+        exchange.setVariable("cheese", "gauda");
 
         Map<?, ?> map = ExchangeHelper.createVariableMap(exchange, true);
 
-        assertEquals(8, map.size());
+        assertEquals(9, map.size());
         assertSame(exchange, map.get("exchange"));
         assertSame(exchange.getIn(), map.get("in"));
         assertSame(exchange.getIn(), map.get("request"));
@@ -175,8 +177,8 @@ public class ExchangeHelperTest extends ContextTestSupport {
 
         Map<?, ?> map = ExchangeHelper.createVariableMap(exchange, true);
 
-        // there should still be 8 in the map
-        assertEquals(8, map.size());
+        // there should still be 9 in the map
+        assertEquals(9, map.size());
         assertSame(exchange, map.get("exchange"));
         assertSame(exchange.getIn(), map.get("in"));
         assertSame(exchange.getIn(), map.get("request"));
@@ -184,6 +186,7 @@ public class ExchangeHelperTest extends ContextTestSupport {
         assertSame(exchange.getIn(), map.get("response"));
         assertSame(exchange.getIn().getHeaders(), map.get("headers"));
         assertSame(exchange.getIn().getBody(), map.get("body"));
+        assertSame(exchange.getVariable("cheese"), map.get("cheese"));
         assertSame(exchange.getContext(), map.get("camelContext"));
 
         // but the Exchange does still not have an OUT message to avoid
diff --git a/core/camel-core/src/test/resources/org/apache/camel/model/removeVariable.xml b/core/camel-core/src/test/resources/org/apache/camel/model/removeVariable.xml
new file mode 100644
index 00000000000..cf9f70bb857
--- /dev/null
+++ b/core/camel-core/src/test/resources/org/apache/camel/model/removeVariable.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<routes id="camel" xmlns="http://camel.apache.org/schema/spring">
+  <route>
+    <from uri="seda:a"/>
+    <setVariable name="myBody">
+      <simple>${body}</simple>
+    </setVariable>
+    <to uri="mock:b"/>
+    <removeVariable name="myBody"/>
+  </route>
+</routes>
diff --git a/core/camel-core/src/test/resources/org/apache/camel/model/setVariable.xml b/core/camel-core/src/test/resources/org/apache/camel/model/setVariable.xml
new file mode 100644
index 00000000000..59fc7f8749c
--- /dev/null
+++ b/core/camel-core/src/test/resources/org/apache/camel/model/setVariable.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<routes id="camel" xmlns="http://camel.apache.org/schema/spring">
+  <route>
+    <from uri="seda:a"/>
+    <setVariable name="myBody">
+      <simple>${body}</simple>
+    </setVariable>
+    <to uri="mock:b"/>     
+  </route>
+</routes>
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index b5bb31d52dc..f9a8b74cd26 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -970,6 +970,7 @@ public abstract class BaseMainSupport extends BaseService {
         OrderedLocationProperties otelProperties = new OrderedLocationProperties();
         OrderedLocationProperties metricsProperties = new OrderedLocationProperties();
         OrderedLocationProperties routeTemplateProperties = new OrderedLocationProperties();
+        OrderedLocationProperties variableProperties = new OrderedLocationProperties();
         OrderedLocationProperties beansProperties = new OrderedLocationProperties();
         OrderedLocationProperties devConsoleProperties = new OrderedLocationProperties();
         OrderedLocationProperties globalOptions = new OrderedLocationProperties();
@@ -1051,6 +1052,12 @@ public abstract class BaseMainSupport extends BaseService {
                 String option = key.substring(17);
                 validateOptionAndValue(key, option, value);
                 devConsoleProperties.put(loc, optionKey(option), value);
+            } else if (key.startsWith("camel.variable.")) {
+                // grab the value
+                String value = prop.getProperty(key);
+                String option = key.substring(15);
+                validateOptionAndValue(key, option, value);
+                variableProperties.put(loc, optionKey(option), value);
             } else if (key.startsWith("camel.beans.")) {
                 // grab the value
                 String value = prop.getProperty(key);
@@ -1097,6 +1104,11 @@ public abstract class BaseMainSupport extends BaseService {
                 mainConfigurationProperties.addGlobalOption(name, value);
             }
         }
+        // create variables first as they may be used later
+        if (!variableProperties.isEmpty()) {
+            LOG.debug("Auto-configuring Variables from loaded properties: {}", variableProperties.size());
+            MainSupportModelConfigurer.setVariableProperties(camelContext, variableProperties, autoConfiguredProperties);
+        }
         // create beans first as they may be used later
         if (!beansProperties.isEmpty()) {
             LOG.debug("Creating and binding beans to registry from loaded properties: {}", beansProperties.size());
@@ -1192,6 +1204,11 @@ public abstract class BaseMainSupport extends BaseService {
                 autoConfiguredProperties, resilience4jProperties, faultToleranceProperties);
 
         // log which options was not set
+        if (!variableProperties.isEmpty()) {
+            variableProperties.forEach((k, v) -> {
+                LOG.warn("Property not auto-configured: camel.variable.{}={}", k, v);
+            });
+        }
         if (!beansProperties.isEmpty()) {
             beansProperties.forEach((k, v) -> {
                 LOG.warn("Property not auto-configured: camel.beans.{}={}", k, v);
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
index c403d714a0e..4d4f664c20f 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
@@ -82,6 +82,7 @@ import org.apache.camel.spi.ThreadPoolFactory;
 import org.apache.camel.spi.ThreadPoolProfile;
 import org.apache.camel.spi.UnitOfWorkFactory;
 import org.apache.camel.spi.UuidGenerator;
+import org.apache.camel.spi.VariableRepositoryFactory;
 import org.apache.camel.support.ClassicUuidGenerator;
 import org.apache.camel.support.DefaultContextReloadStrategy;
 import org.apache.camel.support.DefaultUuidGenerator;
@@ -367,6 +368,10 @@ public final class DefaultConfigurationConfigurer {
         if (ccf != null) {
             camelContext.getCamelContextExtension().addContextPlugin(CliConnectorFactory.class, ccf);
         }
+        VariableRepositoryFactory vrf = getSingleBeanOfType(registry, VariableRepositoryFactory.class);
+        if (vrf != null) {
+            camelContext.getCamelContextExtension().addContextPlugin(VariableRepositoryFactory.class, vrf);
+        }
         PropertiesComponent pc = getSingleBeanOfType(registry, PropertiesComponent.class);
         if (pc != null) {
             camelContext.setPropertiesComponent(pc);
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MainSupportModelConfigurer.java b/core/camel-main/src/main/java/org/apache/camel/main/MainSupportModelConfigurer.java
index d143d6cc016..d6e5a91a5ad 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/MainSupportModelConfigurer.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/MainSupportModelConfigurer.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.main;
 
+import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -25,6 +26,11 @@ import org.apache.camel.model.FaultToleranceConfigurationDefinition;
 import org.apache.camel.model.ModelCamelContext;
 import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.spi.ThreadPoolProfile;
+import org.apache.camel.spi.VariableRepository;
+import org.apache.camel.spi.VariableRepositoryFactory;
+import org.apache.camel.support.LanguageSupport;
+import org.apache.camel.support.ResourceHelper;
+import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.OrderedLocationProperties;
 import org.apache.camel.util.PropertiesHelper;
 import org.apache.camel.util.StringHelper;
@@ -82,6 +88,32 @@ public final class MainSupportModelConfigurer {
         }
     }
 
+    static void setVariableProperties(
+            CamelContext camelContext,
+            OrderedLocationProperties variableProperties,
+            OrderedLocationProperties autoConfiguredProperties)
+            throws Exception {
+
+        for (String key : variableProperties.stringPropertyNames()) {
+            String value = variableProperties.getProperty(key);
+            String id = StringHelper.before(key, ":", "global");
+            key = StringHelper.after(key, ":", key);
+            VariableRepository repo = camelContext.getCamelContextExtension().getContextPlugin(VariableRepositoryFactory.class)
+                    .getVariableRepository(id);
+            // it may be a resource to load from disk then
+            if (value.startsWith(LanguageSupport.RESOURCE)) {
+                value = value.substring(9);
+                if (ResourceHelper.hasScheme(value)) {
+                    InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(camelContext, value);
+                    value = IOHelper.loadText(is);
+                    IOHelper.close(is);
+                }
+            }
+            repo.setVariable(key, value);
+        }
+        autoConfiguredProperties.putAll(variableProperties);
+    }
+
     static void setThreadPoolProperties(
             CamelContext camelContext,
             MainConfigurationProperties mainConfigurationProperties,
diff --git a/core/camel-main/src/test/java/org/apache/camel/main/MainVariableTest.java b/core/camel-main/src/test/java/org/apache/camel/main/MainVariableTest.java
new file mode 100644
index 00000000000..1202db74721
--- /dev/null
+++ b/core/camel-main/src/test/java/org/apache/camel/main/MainVariableTest.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.main;
+
+import java.io.FileInputStream;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.util.IOHelper;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class MainVariableTest {
+
+    @Test
+    public void testMainVariableParameters() throws Exception {
+        Main main = new Main();
+
+        main.addInitialProperty("camel.variable.global:greeting", "Random number");
+        // global is default
+        main.addInitialProperty("camel.variable.random", "999");
+
+        main.start();
+
+        CamelContext context = main.getCamelContext();
+        assertNotNull(context);
+
+        assertEquals("Random number", context.getVariable("greeting"));
+        assertEquals("999", context.getVariable("random"));
+
+        main.stop();
+    }
+
+    @Test
+    public void testMainVariableResource() throws Exception {
+        Main main = new Main();
+
+        main.addInitialProperty("camel.variable.random", "resource:classpath:random.json");
+
+        main.start();
+
+        CamelContext context = main.getCamelContext();
+        assertNotNull(context);
+
+        String text = IOHelper.loadText(new FileInputStream("src/test/resources/random.json"));
+        assertEquals(text, context.getVariable("random"));
+
+        main.stop();
+    }
+
+    @Test
+    public void testMainVariableContext() throws Exception {
+        Main main = new Main();
+
+        main.start();
+
+        CamelContext context = main.getCamelContext();
+        assertNotNull(context);
+
+        context.setVariable("global:greeting", "Random number");
+        // global is default
+        context.setVariable("random", 999);
+
+        assertEquals("Random number", context.getVariable("greeting"));
+        assertEquals(999, context.getVariable("random"));
+
+        main.stop();
+    }
+
+}
diff --git a/core/camel-main/src/test/resources/random.json b/core/camel-main/src/test/resources/random.json
new file mode 100644
index 00000000000..a92f8cb78ba
--- /dev/null
+++ b/core/camel-main/src/test/resources/random.json
@@ -0,0 +1,3 @@
+{
+  "number": 123
+}
\ No newline at end of file
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
index 93b01ebd60d..a89c5100773 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
+++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
@@ -295,4 +295,17 @@ public final class CamelOpenMBeanTypes {
                         SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING });
     }
 
+    public static CompositeType camelVariablesCompositeType() throws OpenDataException {
+        return new CompositeType(
+                "variables", "Variables",
+                new String[] { "id", "key", "className", "value" },
+                new String[] { "Id", "Key", "className", "Value" },
+                new OpenType[] { SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING });
+    }
+
+    public static TabularType camelVariablesTabularType() throws OpenDataException {
+        CompositeType ct = camelVariablesCompositeType();
+        return new TabularType("variables", "Variables", ct, new String[] { "id", "key" });
+    }
+
 }
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRemoveVariableMBean.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRemoveVariableMBean.java
new file mode 100644
index 00000000000..e8364f05d3a
--- /dev/null
+++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRemoveVariableMBean.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.api.management.mbean;
+
+import org.apache.camel.api.management.ManagedAttribute;
+
+public interface ManagedRemoveVariableMBean extends ManagedProcessorMBean {
+
+    @ManagedAttribute(description = "Name of variable to remove")
+    String getVariableName();
+
+}
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedSetVariableMBean.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedSetVariableMBean.java
new file mode 100644
index 00000000000..2dcac16a462
--- /dev/null
+++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedSetVariableMBean.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.api.management.mbean;
+
+import org.apache.camel.api.management.ManagedAttribute;
+
+public interface ManagedSetVariableMBean extends ManagedProcessorMBean {
+
+    @ManagedAttribute(description = "Name of variable to set a new value")
+    String getVariableName();
+
+    @ManagedAttribute(description = "The language for the expression")
+    String getExpressionLanguage();
+
+    @ManagedAttribute(description = "Expression to return the value of the variable")
+    String getExpression();
+
+}
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedVariableRepositoryMBean.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedVariableRepositoryMBean.java
new file mode 100644
index 00000000000..6a976f07bee
--- /dev/null
+++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedVariableRepositoryMBean.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.api.management.mbean;
+
+import java.util.Set;
+
+import javax.management.openmbean.TabularData;
+
+import org.apache.camel.api.management.ManagedAttribute;
+import org.apache.camel.api.management.ManagedOperation;
+
+public interface ManagedVariableRepositoryMBean extends ManagedServiceMBean {
+
+    @ManagedAttribute(description = "Repository ID")
+    String getId();
+
+    @ManagedAttribute(description = "Number of variables")
+    int getSize();
+
+    @ManagedOperation(description = "Removes all variables")
+    void clear();
+
+    @ManagedOperation(description = "Variable names")
+    Set<String> names();
+
+    @ManagedOperation(description = "List all variables")
+    TabularData variables();
+
+}
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectStrategy.java b/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectStrategy.java
index ceb347c4482..ee31f12b21a 100644
--- a/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectStrategy.java
+++ b/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectStrategy.java
@@ -73,6 +73,7 @@ import org.apache.camel.management.mbean.ManagedRemoveHeader;
 import org.apache.camel.management.mbean.ManagedRemoveHeaders;
 import org.apache.camel.management.mbean.ManagedRemoveProperties;
 import org.apache.camel.management.mbean.ManagedRemoveProperty;
+import org.apache.camel.management.mbean.ManagedRemoveVariable;
 import org.apache.camel.management.mbean.ManagedResequencer;
 import org.apache.camel.management.mbean.ManagedRollback;
 import org.apache.camel.management.mbean.ManagedRoundRobinLoadBalancer;
@@ -89,6 +90,7 @@ import org.apache.camel.management.mbean.ManagedSetBody;
 import org.apache.camel.management.mbean.ManagedSetExchangePattern;
 import org.apache.camel.management.mbean.ManagedSetHeader;
 import org.apache.camel.management.mbean.ManagedSetProperty;
+import org.apache.camel.management.mbean.ManagedSetVariable;
 import org.apache.camel.management.mbean.ManagedSplitter;
 import org.apache.camel.management.mbean.ManagedStep;
 import org.apache.camel.management.mbean.ManagedStickyLoadBalancer;
@@ -125,6 +127,7 @@ import org.apache.camel.model.ScriptDefinition;
 import org.apache.camel.model.SetBodyDefinition;
 import org.apache.camel.model.SetHeaderDefinition;
 import org.apache.camel.model.SetPropertyDefinition;
+import org.apache.camel.model.SetVariableDefinition;
 import org.apache.camel.model.SplitDefinition;
 import org.apache.camel.model.TransformDefinition;
 import org.apache.camel.model.TryDefinition;
@@ -151,6 +154,7 @@ import org.apache.camel.processor.RemoveHeaderProcessor;
 import org.apache.camel.processor.RemoveHeadersProcessor;
 import org.apache.camel.processor.RemovePropertiesProcessor;
 import org.apache.camel.processor.RemovePropertyProcessor;
+import org.apache.camel.processor.RemoveVariableProcessor;
 import org.apache.camel.processor.Resequencer;
 import org.apache.camel.processor.RollbackProcessor;
 import org.apache.camel.processor.RoutingSlip;
@@ -161,6 +165,7 @@ import org.apache.camel.processor.SendProcessor;
 import org.apache.camel.processor.SetBodyProcessor;
 import org.apache.camel.processor.SetHeaderProcessor;
 import org.apache.camel.processor.SetPropertyProcessor;
+import org.apache.camel.processor.SetVariableProcessor;
 import org.apache.camel.processor.Splitter;
 import org.apache.camel.processor.StepProcessor;
 import org.apache.camel.processor.StopProcessor;
@@ -423,10 +428,14 @@ public class DefaultManagementObjectStrategy implements ManagementObjectStrategy
                 answer = new ManagedRemoveHeaders(context, (RemoveHeadersProcessor) target, definition);
             } else if (target instanceof SetHeaderProcessor) {
                 answer = new ManagedSetHeader(context, (SetHeaderProcessor) target, (SetHeaderDefinition) definition);
+            } else if (target instanceof SetVariableProcessor) {
+                answer = new ManagedSetVariable(context, (SetVariableProcessor) target, (SetVariableDefinition) definition);
             } else if (target instanceof RemovePropertyProcessor) {
                 answer = new ManagedRemoveProperty(context, (RemovePropertyProcessor) target, definition);
             } else if (target instanceof RemovePropertiesProcessor) {
                 answer = new ManagedRemoveProperties(context, (RemovePropertiesProcessor) target, definition);
+            } else if (target instanceof RemoveVariableProcessor) {
+                answer = new ManagedRemoveVariable(context, (RemoveVariableProcessor) target, definition);
             } else if (target instanceof SetPropertyProcessor) {
                 answer = new ManagedSetProperty(context, (SetPropertyProcessor) target, (SetPropertyDefinition) definition);
             } else if (target instanceof ExchangePatternProcessor) {
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java b/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java
index ec17575664e..426ce12f53b 100644
--- a/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java
+++ b/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java
@@ -74,6 +74,7 @@ import org.apache.camel.management.mbean.ManagedTracer;
 import org.apache.camel.management.mbean.ManagedTransformerRegistry;
 import org.apache.camel.management.mbean.ManagedTypeConverterRegistry;
 import org.apache.camel.management.mbean.ManagedValidatorRegistry;
+import org.apache.camel.management.mbean.ManagedVariableRepository;
 import org.apache.camel.model.InterceptDefinition;
 import org.apache.camel.model.OnCompletionDefinition;
 import org.apache.camel.model.OnExceptionDefinition;
@@ -83,6 +84,7 @@ import org.apache.camel.model.ProcessorDefinitionHelper;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.spi.AsyncProcessorAwaitManager;
 import org.apache.camel.spi.BeanIntrospection;
+import org.apache.camel.spi.BrowsableVariableRepository;
 import org.apache.camel.spi.ConsumerCache;
 import org.apache.camel.spi.DataFormat;
 import org.apache.camel.spi.DumpRoutesStrategy;
@@ -565,6 +567,8 @@ public class JmxManagementLifecycleStrategy extends ServiceSupport implements Li
             answer = new ManagedTransformerRegistry(context, transformerRegistry);
         } else if (service instanceof ValidatorRegistry<?> validatorRegistry) {
             answer = new ManagedValidatorRegistry(context, validatorRegistry);
+        } else if (service instanceof BrowsableVariableRepository variableRepository) {
+            answer = new ManagedVariableRepository(context, variableRepository);
         } else if (service instanceof CamelClusterService) {
             answer = getManagementObjectStrategy().getManagedObjectForClusterService(context, (CamelClusterService) service);
         } else if (service != null) {
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRemoveVariable.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRemoveVariable.java
new file mode 100644
index 00000000000..7bfa2310c87
--- /dev/null
+++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRemoveVariable.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.management.mbean;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.api.management.mbean.ManagedRemoveVariableMBean;
+import org.apache.camel.model.ProcessorDefinition;
+import org.apache.camel.processor.RemoveVariableProcessor;
+
+@ManagedResource(description = "Managed RemoveVariable")
+public class ManagedRemoveVariable extends ManagedProcessor implements ManagedRemoveVariableMBean {
+    private final RemoveVariableProcessor processor;
+
+    public ManagedRemoveVariable(CamelContext context, RemoveVariableProcessor processor, ProcessorDefinition<?> definition) {
+        super(context, processor, definition);
+        this.processor = processor;
+    }
+
+    @Override
+    public String getVariableName() {
+        return processor.getVariableName();
+    }
+}
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedSetVariable.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedSetVariable.java
new file mode 100644
index 00000000000..ad039eb96cc
--- /dev/null
+++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedSetVariable.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.management.mbean;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.api.management.mbean.ManagedSetVariableMBean;
+import org.apache.camel.model.SetVariableDefinition;
+import org.apache.camel.processor.SetVariableProcessor;
+
+@ManagedResource(description = "Managed SetVariable")
+public class ManagedSetVariable extends ManagedProcessor implements ManagedSetVariableMBean {
+    private final SetVariableProcessor processor;
+
+    public ManagedSetVariable(CamelContext context, SetVariableProcessor processor, SetVariableDefinition definition) {
+        super(context, processor, definition);
+        this.processor = processor;
+    }
+
+    @Override
+    public SetVariableDefinition getDefinition() {
+        return (SetVariableDefinition) super.getDefinition();
+    }
+
+    @Override
+    public String getVariableName() {
+        return processor.getVariableName();
+    }
+
+    @Override
+    public String getExpressionLanguage() {
+        return getDefinition().getExpression().getLanguage();
+    }
+
+    @Override
+    public String getExpression() {
+        return getDefinition().getExpression().getExpression();
+    }
+}
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedVariableRepository.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedVariableRepository.java
new file mode 100644
index 00000000000..859d0ecce6c
--- /dev/null
+++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedVariableRepository.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.management.mbean;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes;
+import org.apache.camel.api.management.mbean.ManagedVariableRepositoryMBean;
+import org.apache.camel.spi.BrowsableVariableRepository;
+
+@ManagedResource(description = "Managed VariableRepository")
+public class ManagedVariableRepository extends ManagedService implements ManagedVariableRepositoryMBean {
+    private final BrowsableVariableRepository variableRepository;
+
+    public ManagedVariableRepository(CamelContext context, BrowsableVariableRepository variableRepository) {
+        super(context, variableRepository);
+        this.variableRepository = variableRepository;
+    }
+
+    public BrowsableVariableRepository getVariableRepository() {
+        return variableRepository;
+    }
+
+    @Override
+    public String getId() {
+        return variableRepository.getId();
+    }
+
+    @Override
+    public int getSize() {
+        return variableRepository.size();
+    }
+
+    @Override
+    public void clear() {
+        variableRepository.clear();
+    }
+
+    @Override
+    public Set<String> names() {
+        return variableRepository.names().collect(Collectors.toSet());
+    }
+
+    @Override
+    public TabularData variables() {
+        try {
+            final TabularData answer = new TabularDataSupport(CamelOpenMBeanTypes.camelVariablesTabularType());
+            final CompositeType type = CamelOpenMBeanTypes.camelVariablesCompositeType();
+
+            for (Map.Entry<String, Object> entry : variableRepository.getVariables().entrySet()) {
+                String key = entry.getKey();
+                String className = entry.getValue() != null ? entry.getValue().getClass().getName() : "";
+                String value = entry.getValue() != null ? entry.getValue().toString() : "";
+                if (value.length() > 1000) {
+                    value = value.substring(0, 1000) + "...";
+                }
+
+                CompositeData data = new CompositeDataSupport(
+                        type,
+                        new String[] {
+                                "id",
+                                "key",
+                                "className",
+                                "value",
+                        },
+                        new Object[] {
+                                getId(),
+                                key,
+                                className,
+                                value
+                        });
+                answer.put(data);
+            }
+
+            return answer;
+        } catch (Exception e) {
+            throw RuntimeCamelException.wrapRuntimeCamelException(e);
+        }
+    }
+
+}
diff --git a/core/camel-management/src/test/java/org/apache/camel/management/ManagedNonManagedServiceTest.java b/core/camel-management/src/test/java/org/apache/camel/management/ManagedNonManagedServiceTest.java
index 4450b8511fa..29e6e24dcf8 100644
--- a/core/camel-management/src/test/java/org/apache/camel/management/ManagedNonManagedServiceTest.java
+++ b/core/camel-management/src/test/java/org/apache/camel/management/ManagedNonManagedServiceTest.java
@@ -34,7 +34,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 @DisabledOnOs(OS.AIX)
 public class ManagedNonManagedServiceTest extends ManagementTestSupport {
 
-    private static final int SERVICES = 14;
+    private static final int SERVICES = 15;
 
     @Test
     public void testService() throws Exception {
diff --git a/core/camel-management/src/test/java/org/apache/camel/management/ManagedProducerRouteAddRemoveRegisterAlwaysTest.java b/core/camel-management/src/test/java/org/apache/camel/management/ManagedProducerRouteAddRemoveRegisterAlwaysTest.java
index 57a0b4c33d5..56b9275cc96 100644
--- a/core/camel-management/src/test/java/org/apache/camel/management/ManagedProducerRouteAddRemoveRegisterAlwaysTest.java
+++ b/core/camel-management/src/test/java/org/apache/camel/management/ManagedProducerRouteAddRemoveRegisterAlwaysTest.java
@@ -36,7 +36,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 @DisabledOnOs(OS.AIX)
 public class ManagedProducerRouteAddRemoveRegisterAlwaysTest extends ManagementTestSupport {
 
-    private static final int SERVICES = 14;
+    private static final int SERVICES = 15;
 
     @Override
     protected CamelContext createCamelContext() throws Exception {
diff --git a/core/camel-management/src/test/java/org/apache/camel/management/ManagedRouteAddRemoveTest.java b/core/camel-management/src/test/java/org/apache/camel/management/ManagedRouteAddRemoveTest.java
index abeda66326b..69c52be028b 100644
--- a/core/camel-management/src/test/java/org/apache/camel/management/ManagedRouteAddRemoveTest.java
+++ b/core/camel-management/src/test/java/org/apache/camel/management/ManagedRouteAddRemoveTest.java
@@ -40,7 +40,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 @DisabledOnOs(OS.AIX)
 public class ManagedRouteAddRemoveTest extends ManagementTestSupport {
 
-    private static final int SERVICES = 14;
+    private static final int SERVICES = 15;
 
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
diff --git a/core/camel-management/src/test/java/org/apache/camel/management/ManagedSetAndRemoveHeaderAndPropertiesTest.java b/core/camel-management/src/test/java/org/apache/camel/management/ManagedSetAndRemoveHeaderAndPropertiesTest.java
index 892e89def6f..ed0142249f9 100644
--- a/core/camel-management/src/test/java/org/apache/camel/management/ManagedSetAndRemoveHeaderAndPropertiesTest.java
+++ b/core/camel-management/src/test/java/org/apache/camel/management/ManagedSetAndRemoveHeaderAndPropertiesTest.java
@@ -42,7 +42,7 @@ public class ManagedSetAndRemoveHeaderAndPropertiesTest extends ManagementTestSu
         MBeanServer mbeanServer = getMBeanServer();
 
         Set<ObjectName> set = mbeanServer.queryNames(new ObjectName("*:type=processors,*"), null);
-        assertEquals(8, set.size());
+        assertEquals(9, set.size());
 
         boolean found = false;
         boolean found2 = false;
@@ -50,6 +50,7 @@ public class ManagedSetAndRemoveHeaderAndPropertiesTest extends ManagementTestSu
         boolean found4 = false;
         boolean found5 = false;
         boolean found6 = false;
+        boolean found7 = false;
 
         for (ObjectName on : set) {
             boolean registered = mbeanServer.isRegistered(on);
@@ -61,18 +62,20 @@ public class ManagedSetAndRemoveHeaderAndPropertiesTest extends ManagementTestSu
 
             found |= "setFoo".equals(id);
             found2 |= "setBeer".equals(id);
-            found3 |= "unsetFoo".equals(id);
-            found4 |= "unsetFoos".equals(id);
-            found5 |= "unsetBeer".equals(id);
-            found6 |= "unsetBeers".equals(id);
+            found3 |= "setCheese".equals(id);
+            found4 |= "unsetFoo".equals(id);
+            found5 |= "unsetFoos".equals(id);
+            found6 |= "unsetBeer".equals(id);
+            found7 |= "unsetBeers".equals(id);
         }
 
         assertTrue(found, "Should find setHeader mbean");
         assertTrue(found2, "Should find setProperty mbean");
-        assertTrue(found3, "Should find removeHeader mbean");
-        assertTrue(found4, "Should find removeHeaders mbean");
-        assertTrue(found5, "Should find removeProperty mbean");
+        assertTrue(found3, "Should find setVariable mbean");
+        assertTrue(found4, "Should find removeHeader mbean");
+        assertTrue(found5, "Should find removeHeaders mbean");
         assertTrue(found6, "Should find removeProperty mbean");
+        assertTrue(found7, "Should find removeProperty mbean");
     }
 
     @Override
@@ -83,6 +86,7 @@ public class ManagedSetAndRemoveHeaderAndPropertiesTest extends ManagementTestSu
                 from("direct:start").routeId("foo")
                         .setHeader("foo", constant("bar")).id("setFoo")
                         .setProperty("beer", constant("yes")).id("setBeer")
+                        .setVariable("cheese", constant("gauda")).id("setCheese")
                         .removeHeader("foo").id("unsetFoo")
                         .removeHeaders("foo").id("unsetFoos")
                         .removeProperty("beer").id("unsetBeer")
diff --git a/core/camel-support/src/generated/java/org/apache/camel/support/processor/DefaultExchangeFormatterConfigurer.java b/core/camel-support/src/generated/java/org/apache/camel/support/processor/DefaultExchangeFormatterConfigurer.java
index 5765e5932a2..bf62d2e1d28 100644
--- a/core/camel-support/src/generated/java/org/apache/camel/support/processor/DefaultExchangeFormatterConfigurer.java
+++ b/core/camel-support/src/generated/java/org/apache/camel/support/processor/DefaultExchangeFormatterConfigurer.java
@@ -61,6 +61,8 @@ public class DefaultExchangeFormatterConfigurer extends org.apache.camel.support
         case "ShowStackTrace": target.setShowStackTrace(property(camelContext, boolean.class, value)); return true;
         case "showstreams":
         case "ShowStreams": target.setShowStreams(property(camelContext, boolean.class, value)); return true;
+        case "showvariables":
+        case "ShowVariables": target.setShowVariables(property(camelContext, boolean.class, value)); return true;
         case "skipbodylineseparator":
         case "SkipBodyLineSeparator": target.setSkipBodyLineSeparator(property(camelContext, boolean.class, value)); return true;
         case "style":
@@ -112,6 +114,8 @@ public class DefaultExchangeFormatterConfigurer extends org.apache.camel.support
         case "ShowStackTrace": return boolean.class;
         case "showstreams":
         case "ShowStreams": return boolean.class;
+        case "showvariables":
+        case "ShowVariables": return boolean.class;
         case "skipbodylineseparator":
         case "SkipBodyLineSeparator": return boolean.class;
         case "style":
@@ -164,6 +168,8 @@ public class DefaultExchangeFormatterConfigurer extends org.apache.camel.support
         case "ShowStackTrace": return target.isShowStackTrace();
         case "showstreams":
         case "ShowStreams": return target.isShowStreams();
+        case "showvariables":
+        case "ShowVariables": return target.isShowVariables();
         case "skipbodylineseparator":
         case "SkipBodyLineSeparator": return target.isSkipBodyLineSeparator();
         case "style":
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/AbstractExchange.java b/core/camel-support/src/main/java/org/apache/camel/support/AbstractExchange.java
index ce3acd09507..50d4a1d170c 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/AbstractExchange.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/AbstractExchange.java
@@ -62,6 +62,7 @@ abstract class AbstractExchange implements Exchange {
     protected boolean rollbackOnly;
     protected boolean rollbackOnlyLast;
     protected Map<String, SafeCopyProperty> safeCopyProperties;
+    protected ExchangeVariableRepository variableRepository;
     private final ExtendedExchangeExtension privateExtension;
     private RedeliveryTraitPayload externalRedelivered = RedeliveryTraitPayload.UNDEFINED_REDELIVERY;
 
@@ -124,10 +125,16 @@ abstract class AbstractExchange implements Exchange {
         privateExtension.setErrorHandlerHandled(parent.getExchangeExtension().getErrorHandlerHandled());
         privateExtension.setStreamCacheDisabled(parent.getExchangeExtension().isStreamCacheDisabled());
 
+        if (parent.hasVariables()) {
+            if (this.variableRepository == null) {
+                this.variableRepository = new ExchangeVariableRepository();
+            }
+            this.variableRepository.setVariables(parent.getVariables());
+
+        }
         if (parent.hasProperties()) {
             this.properties = safeCopyProperties(parent.properties);
         }
-
         if (parent.hasSafeCopyProperties()) {
             this.safeCopyProperties = parent.copySafeCopyProperties();
         }
@@ -385,6 +392,63 @@ abstract class AbstractExchange implements Exchange {
         return safeCopyProperties != null && !safeCopyProperties.isEmpty();
     }
 
+    @Override
+    public Object getVariable(String name) {
+        if (variableRepository != null) {
+            return variableRepository.getVariable(name);
+        }
+        return null;
+    }
+
+    @Override
+    public <T> T getVariable(String name, Class<T> type) {
+        Object value = getVariable(name);
+        return evalPropertyValue(type, value);
+    }
+
+    @Override
+    public <T> T getVariable(String name, Object defaultValue, Class<T> type) {
+        Object value = getVariable(name);
+        return evalPropertyValue(defaultValue, type, value);
+    }
+
+    @Override
+    public void setVariable(String name, Object value) {
+        if (variableRepository == null) {
+            variableRepository = new ExchangeVariableRepository();
+        }
+        variableRepository.setVariable(name, value);
+    }
+
+    @Override
+    public Object removeVariable(String name) {
+        if (variableRepository != null) {
+            if ("*".equals(name)) {
+                variableRepository.clear();
+                return null;
+            }
+            return variableRepository.removeVariable(name);
+        }
+        return null;
+    }
+
+    @Override
+    public Map<String, Object> getVariables() {
+        if (variableRepository == null) {
+            // force creating variables
+            variableRepository = new ExchangeVariableRepository();
+        }
+        return variableRepository.getVariables();
+    }
+
+    @Override
+    public boolean hasVariables() {
+        if (variableRepository != null) {
+            return variableRepository.hasVariables();
+        }
+        return false;
+    }
+
     @Override
     public Message getIn() {
         if (in == null) {
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/DefaultPooledExchange.java b/core/camel-support/src/main/java/org/apache/camel/support/DefaultPooledExchange.java
index 75fa2d70e42..620a7af2623 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/DefaultPooledExchange.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/DefaultPooledExchange.java
@@ -41,7 +41,6 @@ public final class DefaultPooledExchange extends AbstractExchange implements Poo
         super(context);
         this.originalPattern = getPattern();
         this.properties = new ConcurrentHashMap<>(8);
-
         this.clock = new ResetableClock();
     }
 
@@ -184,9 +183,7 @@ public final class DefaultPooledExchange extends AbstractExchange implements Poo
 
     public static DefaultPooledExchange newFromEndpoint(Endpoint fromEndpoint, ExchangePattern exchangePattern) {
         DefaultPooledExchange exchange = new DefaultPooledExchange(fromEndpoint.getCamelContext(), exchangePattern);
-
         exchange.getExchangeExtension().setFromEndpoint(fromEndpoint);
-
         return exchange;
     }
 }
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/ExchangeHelper.java b/core/camel-support/src/main/java/org/apache/camel/support/ExchangeHelper.java
index ca806a88a50..9f45cd44431 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/ExchangeHelper.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/ExchangeHelper.java
@@ -474,6 +474,7 @@ public final class ExchangeHelper {
         Message in = exchange.getIn();
         map.put("headers", in.getHeaders());
         map.put("body", in.getBody());
+        map.put("variables", exchange.getVariables());
         if (allowContextMapAll) {
             map.put("in", in);
             map.put("request", in);
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/ExchangeVariableRepository.java b/core/camel-support/src/main/java/org/apache/camel/support/ExchangeVariableRepository.java
new file mode 100644
index 00000000000..3e0a3fd3192
--- /dev/null
+++ b/core/camel-support/src/main/java/org/apache/camel/support/ExchangeVariableRepository.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.support;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Stream;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.NonManagedService;
+import org.apache.camel.spi.BrowsableVariableRepository;
+import org.apache.camel.spi.VariableRepository;
+import org.apache.camel.support.service.ServiceSupport;
+
+/**
+ * {@link VariableRepository} which is local per {@link Exchange} to hold request-scoped variables.
+ */
+class ExchangeVariableRepository extends ServiceSupport implements BrowsableVariableRepository, NonManagedService {
+
+    private final Map<String, Object> variables = new ConcurrentHashMap<>(8);
+
+    @Override
+    public String getId() {
+        return "exchange";
+    }
+
+    @Override
+    public Object getVariable(String name) {
+        return variables.get(name);
+    }
+
+    @Override
+    public void setVariable(String name, Object value) {
+        if (value != null) {
+            // avoid the NullPointException
+            variables.put(name, value);
+        } else {
+            // if the value is null, we just remove the key from the map
+            variables.remove(name);
+        }
+    }
+
+    public boolean hasVariables() {
+        return !variables.isEmpty();
+    }
+
+    public int size() {
+        return variables.size();
+    }
+
+    public Stream<String> names() {
+        return variables.keySet().stream();
+    }
+
+    public Map<String, Object> getVariables() {
+        return variables;
+    }
+
+    public void setVariables(Map<String, Object> map) {
+        variables.putAll(map);
+    }
+
+    public void clear() {
+        variables.clear();
+    }
+
+    @Override
+    public Object removeVariable(String name) {
+        if (!hasVariables()) {
+            return null;
+        }
+        return variables.remove(name);
+    }
+}
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/ExtendedExchangeExtension.java b/core/camel-support/src/main/java/org/apache/camel/support/ExtendedExchangeExtension.java
index 42cb778526b..9f35486dd0b 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/ExtendedExchangeExtension.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/ExtendedExchangeExtension.java
@@ -328,14 +328,13 @@ public class ExtendedExchangeExtension implements ExchangeExtension {
         setRedeliveryExhausted(false);
         setErrorHandlerHandled(null);
         setStreamCacheDisabled(false);
+        this.exchange.variableRepository = null;
     }
 
     @Override
     public Exchange createCopyWithProperties(CamelContext context) {
         DefaultExchange answer = new DefaultExchange(context, exchange.internalProperties, exchange.properties);
-
         answer.setPattern(exchange.pattern);
-
         return answer;
     }
 }
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/GlobalVariableRepository.java b/core/camel-support/src/main/java/org/apache/camel/support/GlobalVariableRepository.java
new file mode 100644
index 00000000000..daad901fde1
--- /dev/null
+++ b/core/camel-support/src/main/java/org/apache/camel/support/GlobalVariableRepository.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.support;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Stream;
+
+import org.apache.camel.spi.BrowsableVariableRepository;
+import org.apache.camel.spi.VariableRepository;
+import org.apache.camel.support.service.ServiceSupport;
+
+/**
+ * Global {@link VariableRepository} which stores variables in-memory in a {@link Map}.
+ */
+public final class GlobalVariableRepository extends ServiceSupport implements BrowsableVariableRepository {
+
+    private final ConcurrentMap<String, Object> variables = new ConcurrentHashMap<>();
+
+    @Override
+    public String getId() {
+        return "global";
+    }
+
+    @Override
+    public Object getVariable(String name) {
+        return variables.get(name);
+    }
+
+    @Override
+    public void setVariable(String name, Object value) {
+        if (value != null) {
+            // avoid the NullPointException
+            variables.put(name, value);
+        } else {
+            // if the value is null, we just remove the key from the map
+            variables.remove(name);
+        }
+    }
+
+    @Override
+    public Object removeVariable(String name) {
+        return variables.remove(name);
+    }
+
+    @Override
+    public boolean hasVariables() {
+        return !variables.isEmpty();
+    }
+
+    @Override
+    public int size() {
+        return variables.size();
+    }
+
+    @Override
+    public Stream<String> names() {
+        return variables.keySet().stream();
+    }
+
+    @Override
+    public Map<String, Object> getVariables() {
+        return variables;
+    }
+
+    @Override
+    public void clear() {
+        variables.clear();
+    }
+}
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/LanguageHelper.java b/core/camel-support/src/main/java/org/apache/camel/support/LanguageHelper.java
index fdbb92ce501..7725136bb95 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/LanguageHelper.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/LanguageHelper.java
@@ -256,6 +256,21 @@ public final class LanguageHelper {
         return null;
     }
 
+    public static Date dateFromVariable(Exchange exchange, String command, BiFunction<Exchange, Object, Date> orElseFunction) {
+        final String key = command.substring(command.lastIndexOf('.') + 1);
+        final Object obj = exchange.getVariable(key);
+        if (obj instanceof Date) {
+            return (Date) obj;
+        } else if (obj instanceof Long) {
+            return new Date((Long) obj);
+        } else {
+            if (orElseFunction != null) {
+                return orElseFunction.apply(exchange, obj);
+            }
+        }
+        return null;
+    }
+
     /**
      * Extracts the creation date from an exchange
      *
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java b/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
index 820c42dfbce..2939d2c1362 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
@@ -44,6 +44,8 @@ import org.apache.camel.spi.Language;
 import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.spi.Registry;
 import org.apache.camel.spi.UnitOfWork;
+import org.apache.camel.spi.VariableRepository;
+import org.apache.camel.spi.VariableRepositoryFactory;
 import org.apache.camel.support.ConstantExpressionAdapter;
 import org.apache.camel.support.ExchangeHelper;
 import org.apache.camel.support.ExpressionAdapter;
@@ -178,6 +180,135 @@ public class ExpressionBuilder {
         };
     }
 
+    /**
+     * Returns an expression for the variable with the given name
+     *
+     * @param  variableName the name of the variable the expression will return
+     * @return              an expression object which will return the variable value
+     */
+    public static Expression variableExpression(final String variableName) {
+        return variableExpression(simpleExpression(variableName));
+    }
+
+    /**
+     * Returns an expression for the variable with the given name
+     *
+     * @param  variableName the name of the variable the expression will return
+     * @return              an expression object which will return the variable value
+     */
+    public static Expression variableExpression(final Expression variableName) {
+        return new ExpressionAdapter() {
+            private VariableRepositoryFactory factory;
+
+            @Override
+            public Object evaluate(Exchange exchange) {
+                String key = variableName.evaluate(exchange, String.class);
+                String id = StringHelper.before(key, ":");
+                if (id != null) {
+                    VariableRepository repo = factory.getVariableRepository(id);
+                    if (repo != null) {
+                        key = StringHelper.after(key, ":");
+                        return repo.getVariable(key);
+                    } else {
+                        throw new IllegalArgumentException("VariableRepository with id: " + id + " does not exists");
+                    }
+                } else {
+                    return exchange.getVariable(key);
+                }
+            }
+
+            @Override
+            public void init(CamelContext context) {
+                variableName.init(context);
+                factory = context.getCamelContextExtension().getContextPlugin(VariableRepositoryFactory.class);
+            }
+
+            @Override
+            public String toString() {
+                return "variable(" + variableName + ")";
+            }
+        };
+    }
+
+    /**
+     * Returns an expression for the variable with the given name converted to the given type
+     *
+     * @param  variableName the name of the variable the expression will return
+     * @param  type         the type to convert to
+     * @return              an expression object which will return the variable value
+     */
+    public static <T> Expression variableExpression(final String variableName, final Class<T> type) {
+        return variableExpression(simpleExpression(variableName), constantExpression(type.getName()));
+    }
+
+    /**
+     * Returns an expression for the variable with the given name converted to the given type
+     *
+     * @param  variableName the name of the variable the expression will return
+     * @param  typeName     the type to convert to as a FQN class name
+     * @return              an expression object which will return the header value
+     */
+    public static Expression variableExpression(final String variableName, final String typeName) {
+        return variableExpression(simpleExpression(variableName), simpleExpression(typeName));
+    }
+
+    /**
+     * Returns an expression for the variable with the given name converted to the given type
+     *
+     * @param  variableName the name of the variable the expression will return
+     * @param  typeName     the type to convert to as a FQN class name
+     * @return              an expression object which will return the header value
+     */
+    public static Expression variableExpression(final Expression variableName, final Expression typeName) {
+        return new ExpressionAdapter() {
+            private ClassResolver classResolver;
+            private VariableRepositoryFactory factory;
+            private TypeConverter converter;
+
+            @Override
+            public Object evaluate(Exchange exchange) {
+                Class<?> type;
+                try {
+                    String text = typeName.evaluate(exchange, String.class);
+                    type = classResolver.resolveMandatoryClass(text);
+                } catch (ClassNotFoundException e) {
+                    throw CamelExecutionException.wrapCamelExecutionException(exchange, e);
+                }
+                String key = variableName.evaluate(exchange, String.class);
+                String id = StringHelper.before(key, ":");
+                if (id != null) {
+                    VariableRepository repo = factory.getVariableRepository(id);
+                    if (repo != null) {
+                        key = StringHelper.after(key, ":");
+                        Object value = repo.getVariable(key);
+                        if (value != null) {
+                            value = converter.convertTo(type, value);
+                        }
+                        return value;
+                    } else {
+                        throw new IllegalArgumentException("VariableRepository with id: " + id + " does not exists");
+                    }
+                } else {
+                    return exchange.getVariable(key, type);
+                }
+            }
+
+            @Override
+            public void init(CamelContext context) {
+                variableName.init(context);
+                typeName.init(context);
+                classResolver = context.getClassResolver();
+                factory = context.getCamelContextExtension().getContextPlugin(VariableRepositoryFactory.class);
+                converter = context.getTypeConverter();
+            }
+
+            @Override
+            public String toString() {
+                return "variableAs(" + variableName + ", " + typeName + ")";
+            }
+        };
+    }
+
     /**
      * Returns an expression for the inbound message headers
      *
@@ -197,6 +328,25 @@ public class ExpressionBuilder {
         };
     }
 
+    /**
+     * Returns an expression for the {@link Exchange} variables
+     *
+     * @return an expression object which will return the variables
+     */
+    public static Expression variablesExpression() {
+        return new ExpressionAdapter() {
+            @Override
+            public Object evaluate(Exchange exchange) {
+                return exchange.getVariables();
+            }
+
+            @Override
+            public String toString() {
+                return "variables";
+            }
+        };
+    }
+
     /**
      * Returns an expression for the exchange pattern
      *
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/processor/DefaultExchangeFormatter.java b/core/camel-support/src/main/java/org/apache/camel/support/processor/DefaultExchangeFormatter.java
index e249806ebf0..e9f919d5b45 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/processor/DefaultExchangeFormatter.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/processor/DefaultExchangeFormatter.java
@@ -63,6 +63,8 @@ public class DefaultExchangeFormatter implements ExchangeFormatter {
     private boolean showProperties;
     @UriParam(label = "formatting", description = "Show all the exchange properties (both internal and custom).")
     private boolean showAllProperties;
+    @UriParam(label = "formatting", description = "Show the variables.")
+    private boolean showVariables;
     @UriParam(label = "formatting", description = "Show the message headers.")
     private boolean showHeaders;
     @UriParam(label = "formatting", defaultValue = "true",
@@ -179,6 +181,14 @@ public class DefaultExchangeFormatter implements ExchangeFormatter {
             }
             style(sb, "Properties").append(sortMap(filterHeaderAndProperties(exchange.getProperties())));
         }
+        if (showAll || showVariables) {
+            if (multiline) {
+                sb.append(SEPARATOR);
+            }
+            if (exchange.hasVariables()) {
+                style(sb, "Variables").append(sortMap(filterHeaderAndProperties(exchange.getVariables())));
+            }
+        }
         if (showAll || showHeaders) {
             if (multiline) {
                 sb.append(SEPARATOR);
@@ -327,6 +337,17 @@ public class DefaultExchangeFormatter implements ExchangeFormatter {
         this.showAllProperties = showAllProperties;
     }
 
+    public boolean isShowVariables() {
+        return showVariables;
+    }
+
+    /**
+     * Show the variables.
+     */
+    public void setShowVariables(boolean showVariables) {
+        this.showVariables = showVariables;
+    }
+
     public boolean isShowHeaders() {
         return showHeaders;
     }
@@ -555,7 +576,9 @@ public class DefaultExchangeFormatter implements ExchangeFormatter {
 
     private static Map<String, Object> sortMap(Map<String, Object> map) {
         Map<String, Object> answer = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-        answer.putAll(map);
+        if (map != null && !map.isEmpty()) {
+            answer.putAll(map);
+        }
         return answer;
     }
 
diff --git a/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java b/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java
index c5611e3ee33..8771410df5f 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java
@@ -569,6 +569,9 @@ public final class StringHelper {
      * @return       the text after the token, or <tt>null</tt> if text does not contain the token
      */
     public static String after(String text, String after) {
+        if (text == null) {
+            return null;
+        }
         int pos = text.indexOf(after);
         if (pos == -1) {
             return null;
@@ -614,6 +617,9 @@ public final class StringHelper {
      * @return       the text after the token, or <tt>null</tt> if text does not contain the token
      */
     public static String afterLast(String text, String after) {
+        if (text == null) {
+            return null;
+        }
         int pos = text.lastIndexOf(after);
         if (pos == -1) {
             return null;
@@ -642,6 +648,9 @@ public final class StringHelper {
      * @return        the text before the token, or <tt>null</tt> if text does not contain the token
      */
     public static String before(String text, String before) {
+        if (text == null) {
+            return null;
+        }
         int pos = text.indexOf(before);
         return pos == -1 ? null : text.substring(0, pos);
     }
@@ -655,6 +664,9 @@ public final class StringHelper {
      * @return              the text before the token, or the supplied defaultValue if text does not contain the token
      */
     public static String before(String text, String before, String defaultValue) {
+        if (text == null) {
+            return defaultValue;
+        }
         int pos = text.indexOf(before);
         return pos == -1 ? defaultValue : text.substring(0, pos);
     }
@@ -668,6 +680,9 @@ public final class StringHelper {
      * @return              the text before the token, or the supplied defaultValue if text does not contain the token
      */
     public static String before(String text, char before, String defaultValue) {
+        if (text == null) {
+            return defaultValue;
+        }
         int pos = text.indexOf(before);
         return pos == -1 ? defaultValue : text.substring(0, pos);
     }
@@ -697,6 +712,9 @@ public final class StringHelper {
      * @return        the text before the token, or <tt>null</tt> if text does not contain the token
      */
     public static String beforeLast(String text, String before) {
+        if (text == null) {
+            return null;
+        }
         int pos = text.lastIndexOf(before);
         return pos == -1 ? null : text.substring(0, pos);
     }
diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
index 49bf724f710..d1904e585ab 100644
--- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
+++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
@@ -859,6 +859,15 @@ public class ModelParser extends BaseParser {
             return processorDefinitionAttributeHandler().accept(def, key, val);
         }, optionalIdentifiedDefinitionElementHandler(), noValueHandler());
     }
+    protected RemoveVariableDefinition doParseRemoveVariableDefinition() throws IOException, XmlPullParserException {
+        return doParse(new RemoveVariableDefinition(), (def, key, val) -> {
+            if ("name".equals(key)) {
+                def.setName(val);
+                return true;
+            }
+            return processorDefinitionAttributeHandler().accept(def, key, val);
+        }, optionalIdentifiedDefinitionElementHandler(), noValueHandler());
+    }
     protected ResequenceDefinition doParseResequenceDefinition() throws IOException, XmlPullParserException {
         return doParse(new ResequenceDefinition(),
             processorDefinitionAttributeHandler(), (def, key) -> {
@@ -1327,6 +1336,15 @@ public class ModelParser extends BaseParser {
             return processorDefinitionAttributeHandler().accept(def, key, val);
         }, expressionNodeElementHandler(), noValueHandler());
     }
+    protected SetVariableDefinition doParseSetVariableDefinition() throws IOException, XmlPullParserException {
+        return doParse(new SetVariableDefinition(), (def, key, val) -> {
+            if ("name".equals(key)) {
+                def.setName(val);
+                return true;
+            }
+            return processorDefinitionAttributeHandler().accept(def, key, val);
+        }, expressionNodeElementHandler(), noValueHandler());
+    }
     protected SortDefinition doParseSortDefinition() throws IOException, XmlPullParserException {
         return doParse(new SortDefinition(), (def, key, val) -> {
             if ("comparator".equals(key)) {
@@ -3469,6 +3487,7 @@ public class ModelParser extends BaseParser {
             case "removeHeaders": return doParseRemoveHeadersDefinition();
             case "removeProperties": return doParseRemovePropertiesDefinition();
             case "removeProperty": return doParseRemovePropertyDefinition();
+            case "removeVariable": return doParseRemoveVariableDefinition();
             case "resequence": return doParseResequenceDefinition();
             case "resumable": return doParseResumableDefinition();
             case "rollback": return doParseRollbackDefinition();
@@ -3482,6 +3501,7 @@ public class ModelParser extends BaseParser {
             case "setHeader": return doParseSetHeaderDefinition();
             case "setHeaders": return doParseSetHeadersDefinition();
             case "setProperty": return doParseSetPropertyDefinition();
+            case "setVariable": return doParseSetVariableDefinition();
             case "sort": return doParseSortDefinition();
             case "split": return doParseSplitDefinition();
             case "step": return doParseStepDefinition();
diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
index 5167687a41c..9819165689c 100644
--- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
+++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
@@ -276,6 +276,11 @@ public class ModelWriter extends BaseWriter {
             throws IOException {
         doWriteRemovePropertyDefinition("removeProperty", def);
     }
+    public void writeRemoveVariableDefinition(
+            RemoveVariableDefinition def)
+            throws IOException {
+        doWriteRemoveVariableDefinition("removeVariable", def);
+    }
     public void writeResequenceDefinition(
             ResequenceDefinition def)
             throws IOException {
@@ -396,6 +401,11 @@ public class ModelWriter extends BaseWriter {
             throws IOException {
         doWriteSetPropertyDefinition("setProperty", def);
     }
+    public void writeSetVariableDefinition(
+            SetVariableDefinition def)
+            throws IOException {
+        doWriteSetVariableDefinition("setVariable", def);
+    }
     public void writeSortDefinition(SortDefinition def) throws IOException {
         doWriteSortDefinition("sort", def);
     }
@@ -1887,6 +1897,15 @@ public class ModelWriter extends BaseWriter {
         doWriteAttribute("name", def.getName());
         endElement(name);
     }
+    protected void doWriteRemoveVariableDefinition(
+            String name,
+            RemoveVariableDefinition def)
+            throws IOException {
+        startElement(name);
+        doWriteProcessorDefinitionAttributes(def);
+        doWriteAttribute("name", def.getName());
+        endElement(name);
+    }
     protected void doWriteResequenceDefinition(
             String name,
             ResequenceDefinition def)
@@ -2226,6 +2245,16 @@ public class ModelWriter extends BaseWriter {
         doWriteExpressionNodeElements(def);
         endElement(name);
     }
+    protected void doWriteSetVariableDefinition(
+            String name,
+            SetVariableDefinition def)
+            throws IOException {
+        startElement(name);
+        doWriteProcessorDefinitionAttributes(def);
+        doWriteAttribute("name", def.getName());
+        doWriteExpressionNodeElements(def);
+        endElement(name);
+    }
     protected void doWriteSortDefinition(
             String name,
             SortDefinition<?> def)
@@ -4794,6 +4823,7 @@ public class ModelWriter extends BaseWriter {
                 case "RemoveHeadersDefinition" -> doWriteRemoveHeadersDefinition("removeHeaders", (RemoveHeadersDefinition) v);
                 case "RemovePropertiesDefinition" -> doWriteRemovePropertiesDefinition("removeProperties", (RemovePropertiesDefinition) v);
                 case "RemovePropertyDefinition" -> doWriteRemovePropertyDefinition("removeProperty", (RemovePropertyDefinition) v);
+                case "RemoveVariableDefinition" -> doWriteRemoveVariableDefinition("removeVariable", (RemoveVariableDefinition) v);
                 case "ResequenceDefinition" -> doWriteResequenceDefinition("resequence", (ResequenceDefinition) v);
                 case "ResumableDefinition" -> doWriteResumableDefinition("resumable", (ResumableDefinition) v);
                 case "RollbackDefinition" -> doWriteRollbackDefinition("rollback", (RollbackDefinition) v);
@@ -4812,6 +4842,7 @@ public class ModelWriter extends BaseWriter {
                 case "SetHeaderDefinition" -> doWriteSetHeaderDefinition("setHeader", (SetHeaderDefinition) v);
                 case "SetHeadersDefinition" -> doWriteSetHeadersDefinition("setHeaders", (SetHeadersDefinition) v);
                 case "SetPropertyDefinition" -> doWriteSetPropertyDefinition("setProperty", (SetPropertyDefinition) v);
+                case "SetVariableDefinition" -> doWriteSetVariableDefinition("setVariable", (SetVariableDefinition) v);
                 case "SortDefinition" -> doWriteSortDefinition("sort", (SortDefinition) v);
                 case "SplitDefinition" -> doWriteSplitDefinition("split", (SplitDefinition) v);
                 case "StepDefinition" -> doWriteStepDefinition("step", (StepDefinition) v);
@@ -4896,6 +4927,7 @@ public class ModelWriter extends BaseWriter {
                 case "RemoveHeadersDefinition" -> doWriteRemoveHeadersDefinition("removeHeaders", (RemoveHeadersDefinition) v);
                 case "RemovePropertiesDefinition" -> doWriteRemovePropertiesDefinition("removeProperties", (RemovePropertiesDefinition) v);
                 case "RemovePropertyDefinition" -> doWriteRemovePropertyDefinition("removeProperty", (RemovePropertyDefinition) v);
+                case "RemoveVariableDefinition" -> doWriteRemoveVariableDefinition("removeVariable", (RemoveVariableDefinition) v);
                 case "ResequenceDefinition" -> doWriteResequenceDefinition("resequence", (ResequenceDefinition) v);
                 case "ResumableDefinition" -> doWriteResumableDefinition("resumable", (ResumableDefinition) v);
                 case "RollbackDefinition" -> doWriteRollbackDefinition("rollback", (RollbackDefinition) v);
@@ -4909,6 +4941,7 @@ public class ModelWriter extends BaseWriter {
                 case "SetHeaderDefinition" -> doWriteSetHeaderDefinition("setHeader", (SetHeaderDefinition) v);
                 case "SetHeadersDefinition" -> doWriteSetHeadersDefinition("setHeaders", (SetHeadersDefinition) v);
                 case "SetPropertyDefinition" -> doWriteSetPropertyDefinition("setProperty", (SetPropertyDefinition) v);
+                case "SetVariableDefinition" -> doWriteSetVariableDefinition("setVariable", (SetVariableDefinition) v);
                 case "SortDefinition" -> doWriteSortDefinition("sort", (SortDefinition) v);
                 case "SplitDefinition" -> doWriteSplitDefinition("split", (SplitDefinition) v);
                 case "StepDefinition" -> doWriteStepDefinition("step", (StepDefinition) v);
diff --git a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
index 403cf7e9724..6e45d23c7d9 100644
--- a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
+++ b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
@@ -276,6 +276,11 @@ public class ModelWriter extends BaseWriter {
             throws IOException {
         doWriteRemovePropertyDefinition("removeProperty", def);
     }
+    public void writeRemoveVariableDefinition(
+            RemoveVariableDefinition def)
+            throws IOException {
+        doWriteRemoveVariableDefinition("removeVariable", def);
+    }
     public void writeResequenceDefinition(
             ResequenceDefinition def)
             throws IOException {
@@ -396,6 +401,11 @@ public class ModelWriter extends BaseWriter {
             throws IOException {
         doWriteSetPropertyDefinition("setProperty", def);
     }
+    public void writeSetVariableDefinition(
+            SetVariableDefinition def)
+            throws IOException {
+        doWriteSetVariableDefinition("setVariable", def);
+    }
     public void writeSortDefinition(SortDefinition def) throws IOException {
         doWriteSortDefinition("sort", def);
     }
@@ -1887,6 +1897,15 @@ public class ModelWriter extends BaseWriter {
         doWriteAttribute("name", def.getName());
         endElement(name);
     }
+    protected void doWriteRemoveVariableDefinition(
+            String name,
+            RemoveVariableDefinition def)
+            throws IOException {
+        startElement(name);
+        doWriteProcessorDefinitionAttributes(def);
+        doWriteAttribute("name", def.getName());
+        endElement(name);
+    }
     protected void doWriteResequenceDefinition(
             String name,
             ResequenceDefinition def)
@@ -2226,6 +2245,16 @@ public class ModelWriter extends BaseWriter {
         doWriteExpressionNodeElements(def);
         endElement(name);
     }
+    protected void doWriteSetVariableDefinition(
+            String name,
+            SetVariableDefinition def)
+            throws IOException {
+        startElement(name);
+        doWriteProcessorDefinitionAttributes(def);
+        doWriteAttribute("name", def.getName());
+        doWriteExpressionNodeElements(def);
+        endElement(name);
+    }
     protected void doWriteSortDefinition(
             String name,
             SortDefinition<?> def)
@@ -4794,6 +4823,7 @@ public class ModelWriter extends BaseWriter {
                 case "RemoveHeadersDefinition" -> doWriteRemoveHeadersDefinition("removeHeaders", (RemoveHeadersDefinition) v);
                 case "RemovePropertiesDefinition" -> doWriteRemovePropertiesDefinition("removeProperties", (RemovePropertiesDefinition) v);
                 case "RemovePropertyDefinition" -> doWriteRemovePropertyDefinition("removeProperty", (RemovePropertyDefinition) v);
+                case "RemoveVariableDefinition" -> doWriteRemoveVariableDefinition("removeVariable", (RemoveVariableDefinition) v);
                 case "ResequenceDefinition" -> doWriteResequenceDefinition("resequence", (ResequenceDefinition) v);
                 case "ResumableDefinition" -> doWriteResumableDefinition("resumable", (ResumableDefinition) v);
                 case "RollbackDefinition" -> doWriteRollbackDefinition("rollback", (RollbackDefinition) v);
@@ -4812,6 +4842,7 @@ public class ModelWriter extends BaseWriter {
                 case "SetHeaderDefinition" -> doWriteSetHeaderDefinition("setHeader", (SetHeaderDefinition) v);
                 case "SetHeadersDefinition" -> doWriteSetHeadersDefinition("setHeaders", (SetHeadersDefinition) v);
                 case "SetPropertyDefinition" -> doWriteSetPropertyDefinition("setProperty", (SetPropertyDefinition) v);
+                case "SetVariableDefinition" -> doWriteSetVariableDefinition("setVariable", (SetVariableDefinition) v);
                 case "SortDefinition" -> doWriteSortDefinition("sort", (SortDefinition) v);
                 case "SplitDefinition" -> doWriteSplitDefinition("split", (SplitDefinition) v);
                 case "StepDefinition" -> doWriteStepDefinition("step", (StepDefinition) v);
@@ -4896,6 +4927,7 @@ public class ModelWriter extends BaseWriter {
                 case "RemoveHeadersDefinition" -> doWriteRemoveHeadersDefinition("removeHeaders", (RemoveHeadersDefinition) v);
                 case "RemovePropertiesDefinition" -> doWriteRemovePropertiesDefinition("removeProperties", (RemovePropertiesDefinition) v);
                 case "RemovePropertyDefinition" -> doWriteRemovePropertyDefinition("removeProperty", (RemovePropertyDefinition) v);
+                case "RemoveVariableDefinition" -> doWriteRemoveVariableDefinition("removeVariable", (RemoveVariableDefinition) v);
                 case "ResequenceDefinition" -> doWriteResequenceDefinition("resequence", (ResequenceDefinition) v);
                 case "ResumableDefinition" -> doWriteResumableDefinition("resumable", (ResumableDefinition) v);
                 case "RollbackDefinition" -> doWriteRollbackDefinition("rollback", (RollbackDefinition) v);
@@ -4909,6 +4941,7 @@ public class ModelWriter extends BaseWriter {
                 case "SetHeaderDefinition" -> doWriteSetHeaderDefinition("setHeader", (SetHeaderDefinition) v);
                 case "SetHeadersDefinition" -> doWriteSetHeadersDefinition("setHeaders", (SetHeadersDefinition) v);
                 case "SetPropertyDefinition" -> doWriteSetPropertyDefinition("setProperty", (SetPropertyDefinition) v);
+                case "SetVariableDefinition" -> doWriteSetVariableDefinition("setVariable", (SetVariableDefinition) v);
                 case "SortDefinition" -> doWriteSortDefinition("sort", (SortDefinition) v);
                 case "SplitDefinition" -> doWriteSplitDefinition("split", (SplitDefinition) v);
                 case "StepDefinition" -> doWriteStepDefinition("step", (StepDefinition) v);
diff --git a/docs/components/modules/ROOT/examples/json/jte.json b/docs/components/modules/ROOT/examples/json/jte.json
new file mode 120000
index 00000000000..069dcb3d83d
--- /dev/null
+++ b/docs/components/modules/ROOT/examples/json/jte.json
@@ -0,0 +1 @@
+../../../../../../components/camel-jte/src/generated/resources/org/apache/camel/component/jte/jte.json
\ No newline at end of file
diff --git a/docs/components/modules/ROOT/nav.adoc b/docs/components/modules/ROOT/nav.adoc
index 02028884d8d..17fd4657d73 100644
--- a/docs/components/modules/ROOT/nav.adoc
+++ b/docs/components/modules/ROOT/nav.adoc
@@ -183,6 +183,7 @@
 ** xref:jsonata-component.adoc[JSONata]
 ** xref:json-patch-component.adoc[JsonPatch]
 ** xref:jt400-component.adoc[JT400]
+** xref:jte-component.adoc[JTE]
 ** xref:kafka-component.adoc[Kafka]
 ** xref:kamelet-component.adoc[Kamelet]
 ** xref:knative-component.adoc[Knative]
diff --git a/docs/components/modules/ROOT/pages/jte-component.adoc b/docs/components/modules/ROOT/pages/jte-component.adoc
new file mode 120000
index 00000000000..b09b7af356d
--- /dev/null
+++ b/docs/components/modules/ROOT/pages/jte-component.adoc
@@ -0,0 +1 @@
+../../../../../components/camel-jte/src/main/docs/jte-component.adoc
\ No newline at end of file
diff --git a/docs/main/modules/working-with-camel-core/pages/index.adoc b/docs/main/modules/working-with-camel-core/pages/index.adoc
index fa5127d92e6..4ce6e00653a 100644
--- a/docs/main/modules/working-with-camel-core/pages/index.adoc
+++ b/docs/main/modules/working-with-camel-core/pages/index.adoc
@@ -94,6 +94,7 @@ Learn about additional ways to customize your integrations. Explore alternatives
 ** xref:manual::spring.adoc[Spring]
 ** xref:manual::spring-xml-extensions.adoc[Spring XML Extensions]
 ** xref:manual::validator.adoc[Validator]
+** xref:manual::variables.adoc[Variables]
 ** xref:manual::what-are-the-dependencies.adoc[Camel Requirements]
 ** xref:manual::testing.adoc[Testing]
 
diff --git a/docs/user-manual/modules/ROOT/pages/parameter-binding-annotations.adoc b/docs/user-manual/modules/ROOT/pages/parameter-binding-annotations.adoc
index 03861ef0ad2..6afb0d5a88c 100644
--- a/docs/user-manual/modules/ROOT/pages/parameter-binding-annotations.adoc
+++ b/docs/user-manual/modules/ROOT/pages/parameter-binding-annotations.adoc
@@ -9,11 +9,18 @@ The bean parameter binding annotations from Camel are as follows:
 |To bind to an inbound message body | 
 
 |`org.apache.camel.Header`
-|To bind to an message header |String name of the header
+|To bind to a message header |String name of the header
 
 |`org.apache.camel.Headers`
 |To bind to the Map of the message headers |
 
+|`org.apache.camel.Variable`
+|To bind to a named variable |String name of the
+variable
+
+|`org.apache.camel.Variables`
+|To bind to the variables map |
+
 |`org.apache.camel.ExchangeProperty`
 |To bind to a named property on the exchange |String name of the
 property
diff --git a/docs/user-manual/modules/ROOT/pages/variables.adoc b/docs/user-manual/modules/ROOT/pages/variables.adoc
new file mode 100644
index 00000000000..7f8b100ff65
--- /dev/null
+++ b/docs/user-manual/modules/ROOT/pages/variables.adoc
@@ -0,0 +1,171 @@
+= Variables
+
+*Available from Camel 4.4*
+
+In Camel 4.4, we have introduced the concept of _variables_.
+
+A variable is a key/value that can hold a value that can either be private per `Exchange` or global shared
+in the `CamelContext`.
+
+NOTE: You can also use _exchange properties_ as variables but the exchange properties are also used internally by Camel,
+and some EIPs and components. With the newly introduced _variables_ then these are exclusively for end users.
+
+== Variable Repository
+
+The variables are stored in one or more `org.apache.camel.spi.VariableRepository`. By default, there are the following repositories
+
+- `ExchangeVariableRepository` - A private repository per `Exchange` that holds variables that are private for the lifecycle of each `Exchange`.
+- `GlobalVariableRepository` - Uses `global` as id. A shared global repository for the entire `CamelContext`.
+
+The `ExchangeVariableRepository` is special as its private per exchange and is the default repository when used during routing.
+
+TIP: There is also `org.apache.camel.spi.BrowsableVariableRepository` which is an extension to `VariableRepository` that
+has APIs to browse the currently variables. This is used by Camel with Camel JBang, and JMX to be able to see the current variables
+from management tooling, CLI and the developer console.
+
+=== Custom variable repositories
+
+You can implement custom `org.apache.camel.spi.VariableRepository` and plugin to be used out of the box with Apache Camel.
+For example, you can build a custom repository that stores the variables in a database, so they are persisted.
+
+Each repository must have its own unique id. However, it's also possible to replace the default `global` repository with another.
+
+== Getting and setting variables from Java API
+
+To get a local variable from the current exchange, you can do this via Java API:
+
+[source,java]
+----
+String myValue = "...";
+exchange.setVariable("myKey", myValue);
+
+// and later to get the variable
+Object val = exchange.getVariable("myKey");
+
+// you can get the value as a specific type
+String str = exchange.getVariable("myKey", String.class);
+----
+
+The API on `Exchange` will by default get the variables from its local private repository.
+However, you can also get variables from other repositories, such as the `global` as show:
+
+[source,java]
+----
+Object val = exchange.getVariable("global:myGlobalKey");
+----
+
+And you can also assign a global variable by prefixing with `global:` as follows:
+
+[source,java]
+----
+exchange.setVariable("global:myGlobalKey", someObjectHere);
+----
+
+There is also API on `CamelContext` to get variables. However, this API will by default get from the `global` repository,
+as it's not possible to get variables from any inflight `Exchange` currently being routed.
+
+[source,java]
+----
+Object val = context.getVariable("myGlobalKey");
+
+// you can get the value as a specific type
+String str = context.getVariable("myGlobalKey", String.class);
+----
+
+== Setting and getting variables from DSL
+
+It is also possible to use variables in Camel xref:routes.adoc[routes] using the
+xref:components:eips:setVariable-eip.adoc[SetVariable], and xref:components:eips:removeVariable-eip.adoc[RemoveVariable] EIPs.
+
+These EIPs makes it possible to set and remove variables from routes. And you can also access variables from the xref:components:languages:simple-language.adoc[Simple] language.
+
+In the following route we set a variable on the exchange which we use later to build a human-readable event message:
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("kafka:order.in")
+  .setVariable("customerId", jq(".customer.custId"))
+  .setVariable("country", jq(".customer.address.co"))
+  .transform().simple("Order received from customer ${variable.customerId} in ${variable.country}")
+  .to("kafka:order.event");
+----
+
+XML::
++
+[source,xml]
+----
+<route>
+    <from uri="kafka:order.in"/>
+    <setVariable name="customerId">
+        <jq>.customer.custId</jq>
+    </setVariable>
+    <setVariable name="country">
+        <jq>.customer.address.co</jq>
+    </setVariable>
+    <transform>
+        <simple>Order received from customer ${variable.customerId} in ${variable.country}</simple>
+    </transform>
+    <to uri="kafka:order.event"/>
+</route>
+----
+
+YAML::
++
+[source,yaml]
+----
+- route:
+    from:
+      uri: kafka:order.in
+      steps:
+        - setVariable:
+            name: customerId
+            jq:
+              expression: .customer.custId
+        - setVariable:
+            name: country
+            jq:
+              expression: .customer.address.co
+        - transform:
+            simple:
+              expression: "Order received from customer ${variable.customerId} in ${variable.country}"
+        - to:
+            uri: kafka:order.event
+----
+====
+
+== Configuring initial variables on startup
+
+When Camel is starting then it's possible to configure initial variables.
+
+This can be done in `application.properties` as shown below:
+
+[source,properties]
+----
+camel.variable.greeting = Random number
+camel.variable.random = 999
+----
+
+The variables are default set on the `global` repository, but you can specify a custom repository by
+prefixing with `id:` in the key, such as below:
+
+[source,properties]
+----
+camel.variable.acme:gold = true
+camel.variable.greeting = Random number
+camel.variable.random = 999
+----
+
+Here the gold variable is set on the `acme` repository, and the other variables are set on the `global` repository.
+
+The value of a variable can also be loaded from file system, such as a JSon file. To do this you should
+prefix the value with `resource:file:` or `resource:classpath:` to load from file system or classpath,
+as shown below:
+
+[source,properties]
+----
+camel.variable.user-template = resource:file:/etc/user.json
+----
diff --git a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
index bc7b89a9ddb..bf2f3cacfc8 100644
--- a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
+++ b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
@@ -943,6 +943,13 @@ public class LocalCliConnector extends ServiceSupport implements CliConnector, C
                         root.put("consumers", json);
                     }
                 }
+                DevConsole dc15 = dcr.resolveById("variables");
+                if (dc15 != null) {
+                    JsonObject json = (JsonObject) dc15.call(DevConsole.MediaType.JSON);
+                    if (json != null && !json.isEmpty()) {
+                        root.put("variables", json);
+                    }
+                }
             }
             // various details
             JsonObject services = collectServices();
diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LogEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LogEndpointBuilderFactory.java
index 57a0fefb6f2..842acc4a91d 100644
--- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LogEndpointBuilderFactory.java
+++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LogEndpointBuilderFactory.java
@@ -911,6 +911,37 @@ public interface LogEndpointBuilderFactory {
             doSetProperty("showStreams", showStreams);
             return this;
         }
+        /**
+         * Show the variables.
+         * 
+         * The option is a: &lt;code&gt;boolean&lt;/code&gt; type.
+         * 
+         * Default: false
+         * Group: formatting
+         * 
+         * @param showVariables the value to set
+         * @return the dsl builder
+         */
+        default LogEndpointBuilder showVariables(boolean showVariables) {
+            doSetProperty("showVariables", showVariables);
+            return this;
+        }
+        /**
+         * Show the variables.
+         * 
+         * The option will be converted to a &lt;code&gt;boolean&lt;/code&gt;
+         * type.
+         * 
+         * Default: false
+         * Group: formatting
+         * 
+         * @param showVariables the value to set
+         * @return the dsl builder
+         */
+        default LogEndpointBuilder showVariables(String showVariables) {
+            doSetProperty("showVariables", showVariables);
+            return this;
+        }
         /**
          * Whether to skip line separators when logging the message body. This
          * allows to log the message body in one line, setting this option to
diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/ThymeleafEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/ThymeleafEndpointBuilderFactory.java
index 30266eb8b4e..8875df45c16 100644
--- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/ThymeleafEndpointBuilderFactory.java
+++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/ThymeleafEndpointBuilderFactory.java
@@ -203,16 +203,91 @@ public interface ThymeleafEndpointBuilderFactory {
             return this;
         }
         /**
-         * The character encoding to be used for reading template resources.
+         * The template mode to be applied to templates.
          * 
          * The option is a: &lt;code&gt;java.lang.String&lt;/code&gt; type.
          * 
+         * Default: HTML
          * Group: producer
          * 
+         * @param templateMode the value to set
+         * @return the dsl builder
+         */
+        default ThymeleafEndpointBuilder templateMode(String templateMode) {
+            doSetProperty("templateMode", templateMode);
+            return this;
+        }
+    }
+
+    /**
+     * Advanced builder for endpoint for the Thymeleaf component.
+     */
+    public interface AdvancedThymeleafEndpointBuilder
+            extends
+                EndpointProducerBuilder {
+        default ThymeleafEndpointBuilder basic() {
+            return (ThymeleafEndpointBuilder) this;
+        }
+        /**
+         * Whether the producer should be started lazy (on the first message).
+         * By starting lazy you can use this to allow CamelContext and routes to
+         * startup in situations where a producer may otherwise fail during
+         * starting and cause the route to fail being started. By deferring this
+         * startup to be lazy then the startup failure can be handled during
+         * routing messages via Camel's routing error handlers. Beware that when
+         * the first message is processed then creating and starting the
+         * producer may take a little time and prolong the total processing time
+         * of the processing.
+         * 
+         * The option is a: &lt;code&gt;boolean&lt;/code&gt; type.
+         * 
+         * Default: false
+         * Group: producer (advanced)
+         * 
+         * @param lazyStartProducer the value to set
+         * @return the dsl builder
+         */
+        default AdvancedThymeleafEndpointBuilder lazyStartProducer(
+                boolean lazyStartProducer) {
+            doSetProperty("lazyStartProducer", lazyStartProducer);
+            return this;
+        }
+        /**
+         * Whether the producer should be started lazy (on the first message).
+         * By starting lazy you can use this to allow CamelContext and routes to
+         * startup in situations where a producer may otherwise fail during
+         * starting and cause the route to fail being started. By deferring this
+         * startup to be lazy then the startup failure can be handled during
+         * routing messages via Camel's routing error handlers. Beware that when
+         * the first message is processed then creating and starting the
+         * producer may take a little time and prolong the total processing time
+         * of the processing.
+         * 
+         * The option will be converted to a &lt;code&gt;boolean&lt;/code&gt;
+         * type.
+         * 
+         * Default: false
+         * Group: producer (advanced)
+         * 
+         * @param lazyStartProducer the value to set
+         * @return the dsl builder
+         */
+        default AdvancedThymeleafEndpointBuilder lazyStartProducer(
+                String lazyStartProducer) {
+            doSetProperty("lazyStartProducer", lazyStartProducer);
+            return this;
+        }
+        /**
+         * The character encoding to be used for reading template resources.
+         * 
+         * The option is a: &lt;code&gt;java.lang.String&lt;/code&gt; type.
+         * 
+         * Group: advanced
+         * 
          * @param encoding the value to set
          * @return the dsl builder
          */
-        default ThymeleafEndpointBuilder encoding(String encoding) {
+        default AdvancedThymeleafEndpointBuilder encoding(String encoding) {
             doSetProperty("encoding", encoding);
             return this;
         }
@@ -222,12 +297,12 @@ public interface ThymeleafEndpointBuilderFactory {
          * 
          * The option is a: &lt;code&gt;java.lang.Integer&lt;/code&gt; type.
          * 
-         * Group: producer
+         * Group: advanced
          * 
          * @param order the value to set
          * @return the dsl builder
          */
-        default ThymeleafEndpointBuilder order(Integer order) {
+        default AdvancedThymeleafEndpointBuilder order(Integer order) {
             doSetProperty("order", order);
             return this;
         }
@@ -238,12 +313,12 @@ public interface ThymeleafEndpointBuilderFactory {
          * The option will be converted to a
          * &lt;code&gt;java.lang.Integer&lt;/code&gt; type.
          * 
-         * Group: producer
+         * Group: advanced
          * 
          * @param order the value to set
          * @return the dsl builder
          */
-        default ThymeleafEndpointBuilder order(String order) {
+        default AdvancedThymeleafEndpointBuilder order(String order) {
             doSetProperty("order", order);
             return this;
         }
@@ -253,12 +328,12 @@ public interface ThymeleafEndpointBuilderFactory {
          * 
          * The option is a: &lt;code&gt;java.lang.String&lt;/code&gt; type.
          * 
-         * Group: producer
+         * Group: advanced
          * 
          * @param prefix the value to set
          * @return the dsl builder
          */
-        default ThymeleafEndpointBuilder prefix(String prefix) {
+        default AdvancedThymeleafEndpointBuilder prefix(String prefix) {
             doSetProperty("prefix", prefix);
             return this;
         }
@@ -269,12 +344,12 @@ public interface ThymeleafEndpointBuilderFactory {
          * &lt;code&gt;org.apache.camel.component.thymeleaf.ThymeleafResolverType&lt;/code&gt; type.
          * 
          * Default: CLASS_LOADER
-         * Group: producer
+         * Group: advanced
          * 
          * @param resolver the value to set
          * @return the dsl builder
          */
-        default ThymeleafEndpointBuilder resolver(
+        default AdvancedThymeleafEndpointBuilder resolver(
                 org.apache.camel.component.thymeleaf.ThymeleafResolverType resolver) {
             doSetProperty("resolver", resolver);
             return this;
@@ -286,12 +361,12 @@ public interface ThymeleafEndpointBuilderFactory {
          * &lt;code&gt;org.apache.camel.component.thymeleaf.ThymeleafResolverType&lt;/code&gt; type.
          * 
          * Default: CLASS_LOADER
-         * Group: producer
+         * Group: advanced
          * 
          * @param resolver the value to set
          * @return the dsl builder
          */
-        default ThymeleafEndpointBuilder resolver(String resolver) {
+        default AdvancedThymeleafEndpointBuilder resolver(String resolver) {
             doSetProperty("resolver", resolver);
             return this;
         }
@@ -301,89 +376,15 @@ public interface ThymeleafEndpointBuilderFactory {
          * 
          * The option is a: &lt;code&gt;java.lang.String&lt;/code&gt; type.
          * 
-         * Group: producer
+         * Group: advanced
          * 
          * @param suffix the value to set
          * @return the dsl builder
          */
-        default ThymeleafEndpointBuilder suffix(String suffix) {
+        default AdvancedThymeleafEndpointBuilder suffix(String suffix) {
             doSetProperty("suffix", suffix);
             return this;
         }
-        /**
-         * The template mode to be applied to templates.
-         * 
-         * The option is a: &lt;code&gt;java.lang.String&lt;/code&gt; type.
-         * 
-         * Group: producer
-         * 
-         * @param templateMode the value to set
-         * @return the dsl builder
-         */
-        default ThymeleafEndpointBuilder templateMode(String templateMode) {
-            doSetProperty("templateMode", templateMode);
-            return this;
-        }
-    }
-
-    /**
-     * Advanced builder for endpoint for the Thymeleaf component.
-     */
-    public interface AdvancedThymeleafEndpointBuilder
-            extends
-                EndpointProducerBuilder {
-        default ThymeleafEndpointBuilder basic() {
-            return (ThymeleafEndpointBuilder) this;
-        }
-        /**
-         * Whether the producer should be started lazy (on the first message).
-         * By starting lazy you can use this to allow CamelContext and routes to
-         * startup in situations where a producer may otherwise fail during
-         * starting and cause the route to fail being started. By deferring this
-         * startup to be lazy then the startup failure can be handled during
-         * routing messages via Camel's routing error handlers. Beware that when
-         * the first message is processed then creating and starting the
-         * producer may take a little time and prolong the total processing time
-         * of the processing.
-         * 
-         * The option is a: &lt;code&gt;boolean&lt;/code&gt; type.
-         * 
-         * Default: false
-         * Group: producer (advanced)
-         * 
-         * @param lazyStartProducer the value to set
-         * @return the dsl builder
-         */
-        default AdvancedThymeleafEndpointBuilder lazyStartProducer(
-                boolean lazyStartProducer) {
-            doSetProperty("lazyStartProducer", lazyStartProducer);
-            return this;
-        }
-        /**
-         * Whether the producer should be started lazy (on the first message).
-         * By starting lazy you can use this to allow CamelContext and routes to
-         * startup in situations where a producer may otherwise fail during
-         * starting and cause the route to fail being started. By deferring this
-         * startup to be lazy then the startup failure can be handled during
-         * routing messages via Camel's routing error handlers. Beware that when
-         * the first message is processed then creating and starting the
-         * producer may take a little time and prolong the total processing time
-         * of the processing.
-         * 
-         * The option will be converted to a &lt;code&gt;boolean&lt;/code&gt;
-         * type.
-         * 
-         * Default: false
-         * Group: producer (advanced)
-         * 
-         * @param lazyStartProducer the value to set
-         * @return the dsl builder
-         */
-        default AdvancedThymeleafEndpointBuilder lazyStartProducer(
-                String lazyStartProducer) {
-            doSetProperty("lazyStartProducer", lazyStartProducer);
-            return this;
-        }
     }
 
     public interface ThymeleafBuilders {
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
index f66f17b4ebe..bce20df06d9 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
@@ -76,6 +76,7 @@ public class CamelJBangMain implements Callable<Integer> {
                         .addSubcommand("processor", new CommandLine(new CamelProcessorStatus(main)))
                         .addSubcommand("count", new CommandLine(new CamelCount(main)))
                         .addSubcommand("health", new CommandLine(new ListHealth(main)))
+                        .addSubcommand("variable", new CommandLine(new ListVariable(main)))
                         .addSubcommand("consumer", new CommandLine(new ListConsumer(main)))
                         .addSubcommand("endpoint", new CommandLine(new ListEndpoint(main)))
                         .addSubcommand("event", new CommandLine(new ListEvent(main)))
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListVariable.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListVariable.java
new file mode 100644
index 00000000000..b19927f1bfa
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListVariable.java
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.process;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import com.github.freva.asciitable.AsciiTable;
+import com.github.freva.asciitable.Column;
+import com.github.freva.asciitable.HorizontalAlign;
+import com.github.freva.asciitable.OverflowBehaviour;
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.common.ProcessHelper;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+
+@Command(name = "variable", description = "List variables in a running Camel integration", sortOptions = false)
+public class ListVariable extends ProcessWatchCommand {
+
+    public static class PidNameKeyCompletionCandidates implements Iterable<String> {
+
+        public PidNameKeyCompletionCandidates() {
+        }
+
+        @Override
+        public Iterator<String> iterator() {
+            return List.of("pid", "name", "key").iterator();
+        }
+
+    }
+
+    @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
+    String name = "*";
+
+    @CommandLine.Option(names = { "--sort" }, completionCandidates = PidNameKeyCompletionCandidates.class,
+                        description = "Sort by pid, name or key", defaultValue = "pid")
+    String sort;
+
+    public ListVariable(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer doProcessWatchCall() throws Exception {
+        List<Row> rows = new ArrayList<>();
+
+        List<Long> pids = findPids(name);
+
+        ProcessHandle.allProcesses()
+                .filter(ph -> pids.contains(ph.pid()))
+                .forEach(ph -> {
+                    JsonObject root = loadStatus(ph.pid());
+                    // there must be a status file for the running Camel integration
+                    if (root != null) {
+                        Row row = new Row();
+                        JsonObject context = (JsonObject) root.get("context");
+                        if (context == null) {
+                            return;
+                        }
+                        row.name = context.getString("name");
+                        if ("CamelJBang".equals(row.name)) {
+                            row.name = ProcessHelper.extractName(root, ph);
+                        }
+                        row.pid = Long.toString(ph.pid());
+
+                        // platform-http is special
+                        JsonObject jo = (JsonObject) root.get("variables");
+                        for (String id : jo.keySet()) {
+                            JsonArray arr = jo.getCollection(id);
+                            for (int i = 0; i < arr.size(); i++) {
+                                row = row.copy();
+                                jo = (JsonObject) arr.get(i);
+                                row.id = id;
+                                row.key = jo.getString("key");
+                                row.className = jo.getString("className");
+                                row.value = jo.get("value");
+                                rows.add(row);
+                            }
+                        }
+                    }
+                });
+
+        // sort rows
+        rows.sort(this::sortRow);
+
+        if (!rows.isEmpty()) {
+            printer().println(AsciiTable.getTable(AsciiTable.NO_BORDERS, rows, Arrays.asList(
+                    new Column().header("PID").headerAlign(HorizontalAlign.CENTER).with(r -> r.pid),
+                    new Column().header("NAME").dataAlign(HorizontalAlign.LEFT).maxWidth(30, OverflowBehaviour.ELLIPSIS_RIGHT)
+                            .with(r -> r.name),
+                    new Column().header("REPOSITORY").headerAlign(HorizontalAlign.CENTER).with(r -> r.id),
+                    new Column().header("TYPE").headerAlign(HorizontalAlign.CENTER)
+                            .maxWidth(40, OverflowBehaviour.ELLIPSIS_LEFT).with(r -> r.className),
+                    new Column().header("KEY").dataAlign(HorizontalAlign.LEFT).maxWidth(50, OverflowBehaviour.ELLIPSIS_RIGHT)
+                            .with(r -> r.key),
+                    new Column().header("VALUE").headerAlign(HorizontalAlign.RIGHT).maxWidth(80, OverflowBehaviour.NEWLINE)
+                            .with(r -> r.value.toString()))));
+        }
+
+        return 0;
+    }
+
+    protected int sortRow(Row o1, Row o2) {
+        String s = sort;
+        int negate = 1;
+        if (s.startsWith("-")) {
+            s = s.substring(1);
+            negate = -1;
+        }
+        switch (s) {
+            case "pid":
+                return Long.compare(Long.parseLong(o1.pid), Long.parseLong(o2.pid)) * negate;
+            case "name":
+                return o1.name.compareToIgnoreCase(o2.name) * negate;
+            case "key":
+                return o1.key.compareToIgnoreCase(o2.key) * negate;
+            default:
+                return 0;
+        }
+    }
+
+    private String getValue(Row r) {
+        if (r.value != null) {
+            // clip very large value
+            String s = r.value.toString();
+            if (s.length() > 300) {
+                s = s.substring(0, 300) + "...";
+            }
+            return s;
+        }
+        return "";
+    }
+
+    private static class Row implements Cloneable {
+        String pid;
+        String name;
+        String id;
+        String key;
+        String className;
+        Object value;
+
+        Row copy() {
+            try {
+                return (Row) clone();
+            } catch (CloneNotSupportedException e) {
+                return null;
+            }
+        }
+    }
+
+}
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
index 242300692e7..03e230868e0 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
@@ -60,6 +60,7 @@ import org.apache.camel.model.RemoveHeaderDefinition;
 import org.apache.camel.model.RemoveHeadersDefinition;
 import org.apache.camel.model.RemovePropertiesDefinition;
 import org.apache.camel.model.RemovePropertyDefinition;
+import org.apache.camel.model.RemoveVariableDefinition;
 import org.apache.camel.model.ResequenceDefinition;
 import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.model.RestContextRefDefinition;
@@ -80,6 +81,7 @@ import org.apache.camel.model.SetExchangePatternDefinition;
 import org.apache.camel.model.SetHeaderDefinition;
 import org.apache.camel.model.SetHeadersDefinition;
 import org.apache.camel.model.SetPropertyDefinition;
+import org.apache.camel.model.SetVariableDefinition;
 import org.apache.camel.model.SortDefinition;
 import org.apache.camel.model.SplitDefinition;
 import org.apache.camel.model.StepDefinition;
@@ -12945,6 +12947,78 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
         }
     }
 
+    @YamlType(
+            nodes = {
+                    "remove-variable",
+                    "removeVariable"
+            },
+            inline = true,
+            types = org.apache.camel.model.RemoveVariableDefinition.class,
+            order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
+            displayName = "Remove Variable",
+            description = "Removes a named variable",
+            deprecated = false,
+            properties = {
+                    @YamlProperty(name = "description", type = "string", description = "Sets the description of this node", displayName = "Description"),
+                    @YamlProperty(name = "disabled", type = "boolean", description = "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime.", displayName = "Disabled"),
+                    @YamlProperty(name = "id", type = "string", description = "Sets the id of this node", displayName = "Id"),
+                    @YamlProperty(name = "inheritErrorHandler", type = "boolean"),
+                    @YamlProperty(name = "name", type = "string", required = true, description = "Name of variable to remove.", displayName = "Name")
+            }
+    )
+    public static class RemoveVariableDefinitionDeserializer extends YamlDeserializerBase<RemoveVariableDefinition> {
+        public RemoveVariableDefinitionDeserializer() {
+            super(RemoveVariableDefinition.class);
+        }
+
+        @Override
+        protected RemoveVariableDefinition newInstance() {
+            return new RemoveVariableDefinition();
+        }
+
+        @Override
+        protected RemoveVariableDefinition newInstance(String value) {
+            return new RemoveVariableDefinition(value);
+        }
+
+        @Override
+        protected boolean setProperty(RemoveVariableDefinition target, String propertyKey,
+                String propertyName, Node node) {
+            propertyKey = org.apache.camel.util.StringHelper.dashToCamelCase(propertyKey);
+            switch(propertyKey) {
+                case "disabled": {
+                    String val = asText(node);
+                    target.setDisabled(val);
+                    break;
+                }
+                case "inheritErrorHandler": {
+                    String val = asText(node);
+                    target.setInheritErrorHandler(java.lang.Boolean.valueOf(val));
+                    break;
+                }
+                case "name": {
+                    String val = asText(node);
+                    target.setName(val);
+                    break;
+                }
+                case "id": {
+                    String val = asText(node);
+                    target.setId(val);
+                    break;
+                }
+                case "description": {
+                    String val = asText(node);
+                    target.setDescription(val);
+                    break;
+                }
+                default: {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
     @YamlType(
             nodes = "resequence",
             types = org.apache.camel.model.ResequenceDefinition.class,
@@ -16115,6 +16189,88 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
         }
     }
 
+    @YamlType(
+            nodes = {
+                    "set-variable",
+                    "setVariable"
+            },
+            types = org.apache.camel.model.SetVariableDefinition.class,
+            order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
+            displayName = "Set Variable",
+            description = "Sets the value of a variable",
+            deprecated = false,
+            properties = {
+                    @YamlProperty(name = "__extends", type = "object:org.apache.camel.model.language.ExpressionDefinition", oneOf = "expression"),
+                    @YamlProperty(name = "description", type = "string", description = "Sets the description of this node", displayName = "Description"),
+                    @YamlProperty(name = "disabled", type = "boolean", description = "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime.", displayName = "Disabled"),
+                    @YamlProperty(name = "expression", type = "object:org.apache.camel.model.language.ExpressionDefinition", description = "Expression to return the value of the variable", displayName = "Expression", oneOf = "expression"),
+                    @YamlProperty(name = "id", type = "string", description = "Sets the id of this node", displayName = "Id"),
+                    @YamlProperty(name = "inheritErrorHandler", type = "boolean"),
+                    @YamlProperty(name = "name", type = "string", required = true, description = "Name of variable to set a new value The simple language can be used to define a dynamic evaluated variable name to be used. Otherwise a constant name will be used.", displayName = "Name")
+            }
+    )
+    public static class SetVariableDefinitionDeserializer extends YamlDeserializerBase<SetVariableDefinition> {
+        public SetVariableDefinitionDeserializer() {
+            super(SetVariableDefinition.class);
+        }
+
+        @Override
+        protected SetVariableDefinition newInstance() {
+            return new SetVariableDefinition();
+        }
+
+        @Override
+        protected boolean setProperty(SetVariableDefinition target, String propertyKey,
+                String propertyName, Node node) {
+            propertyKey = org.apache.camel.util.StringHelper.dashToCamelCase(propertyKey);
+            switch(propertyKey) {
+                case "disabled": {
+                    String val = asText(node);
+                    target.setDisabled(val);
+                    break;
+                }
+                case "expression": {
+                    org.apache.camel.model.language.ExpressionDefinition val = asType(node, org.apache.camel.model.language.ExpressionDefinition.class);
+                    target.setExpression(val);
+                    break;
+                }
+                case "inheritErrorHandler": {
+                    String val = asText(node);
+                    target.setInheritErrorHandler(java.lang.Boolean.valueOf(val));
+                    break;
+                }
+                case "name": {
+                    String val = asText(node);
+                    target.setName(val);
+                    break;
+                }
+                case "id": {
+                    String val = asText(node);
+                    target.setId(val);
+                    break;
+                }
+                case "description": {
+                    String val = asText(node);
+                    target.setDescription(val);
+                    break;
+                }
+                default: {
+                    ExpressionDefinition ed = target.getExpressionType();
+                    if (ed != null) {
+                        throw new org.apache.camel.dsl.yaml.common.exception.DuplicateFieldException(node, propertyName, "as an expression");
+                    }
+                    ed = ExpressionDeserializers.constructExpressionType(propertyKey, node);
+                    if (ed != null) {
+                        target.setExpressionType(ed);
+                    } else {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+    }
+
     @YamlType(
             nodes = "simple",
             inline = true,
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
index 56f461acd43..41dcf485515 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
@@ -343,6 +343,9 @@ public final class ModelDeserializersResolver implements YamlDeserializerResolve
             case "remove-property": return new ModelDeserializers.RemovePropertyDefinitionDeserializer();
             case "removeProperty": return new ModelDeserializers.RemovePropertyDefinitionDeserializer();
             case "org.apache.camel.model.RemovePropertyDefinition": return new ModelDeserializers.RemovePropertyDefinitionDeserializer();
+            case "remove-variable": return new ModelDeserializers.RemoveVariableDefinitionDeserializer();
+            case "removeVariable": return new ModelDeserializers.RemoveVariableDefinitionDeserializer();
+            case "org.apache.camel.model.RemoveVariableDefinition": return new ModelDeserializers.RemoveVariableDefinitionDeserializer();
             case "resequence": return new ModelDeserializers.ResequenceDefinitionDeserializer();
             case "org.apache.camel.model.ResequenceDefinition": return new ModelDeserializers.ResequenceDefinitionDeserializer();
             case "resilience4j-configuration": return new ModelDeserializers.Resilience4jConfigurationDefinitionDeserializer();
@@ -444,6 +447,9 @@ public final class ModelDeserializersResolver implements YamlDeserializerResolve
             case "set-property": return new ModelDeserializers.SetPropertyDefinitionDeserializer();
             case "setProperty": return new ModelDeserializers.SetPropertyDefinitionDeserializer();
             case "org.apache.camel.model.SetPropertyDefinition": return new ModelDeserializers.SetPropertyDefinitionDeserializer();
+            case "set-variable": return new ModelDeserializers.SetVariableDefinitionDeserializer();
+            case "setVariable": return new ModelDeserializers.SetVariableDefinitionDeserializer();
+            case "org.apache.camel.model.SetVariableDefinition": return new ModelDeserializers.SetVariableDefinitionDeserializer();
             case "simple": return new ModelDeserializers.SimpleExpressionDeserializer();
             case "org.apache.camel.model.language.SimpleExpression": return new ModelDeserializers.SimpleExpressionDeserializer();
             case "soap": return new ModelDeserializers.SoapDataFormatDeserializer();
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
index 7e9d6e87219..bb91046902f 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
@@ -106,6 +106,9 @@
           "removeProperty" : {
             "$ref" : "#/items/definitions/org.apache.camel.model.RemovePropertyDefinition"
           },
+          "removeVariable" : {
+            "$ref" : "#/items/definitions/org.apache.camel.model.RemoveVariableDefinition"
+          },
           "resequence" : {
             "$ref" : "#/items/definitions/org.apache.camel.model.ResequenceDefinition"
           },
@@ -142,6 +145,9 @@
           "setProperty" : {
             "$ref" : "#/items/definitions/org.apache.camel.model.SetPropertyDefinition"
           },
+          "setVariable" : {
+            "$ref" : "#/items/definitions/org.apache.camel.model.SetVariableDefinition"
+          },
           "sort" : {
             "$ref" : "#/items/definitions/org.apache.camel.model.SortDefinition"
           },
@@ -4272,6 +4278,39 @@
         } ],
         "required" : [ "name" ]
       },
+      "org.apache.camel.model.RemoveVariableDefinition" : {
+        "title" : "Remove Variable",
+        "description" : "Removes a named variable",
+        "oneOf" : [ {
+          "type" : "string"
+        }, {
+          "type" : "object",
+          "additionalProperties" : false,
+          "properties" : {
+            "description" : {
+              "type" : "string",
+              "title" : "Description",
+              "description" : "Sets the description of this node"
+            },
+            "disabled" : {
+              "type" : "boolean",
+              "title" : "Disabled",
+              "description" : "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime."
+            },
+            "id" : {
+              "type" : "string",
+              "title" : "Id",
+              "description" : "Sets the id of this node"
+            },
+            "name" : {
+              "type" : "string",
+              "title" : "Name",
+              "description" : "Name of variable to remove."
+            }
+          }
+        } ],
+        "required" : [ "name" ]
+      },
       "org.apache.camel.model.ResequenceDefinition" : {
         "title" : "Resequence",
         "description" : "Resequences (re-order) messages based on an expression",
@@ -5754,6 +5793,129 @@
         },
         "required" : [ "name" ]
       },
+      "org.apache.camel.model.SetVariableDefinition" : {
+        "title" : "Set Variable",
+        "description" : "Sets the value of a variable",
+        "type" : "object",
+        "additionalProperties" : false,
+        "anyOf" : [ {
+          "oneOf" : [ {
+            "$ref" : "#/items/definitions/org.apache.camel.model.language.ExpressionDefinition"
+          }, {
+            "not" : {
+              "anyOf" : [ {
+                "required" : [ "expression" ]
+              }, {
+                "required" : [ "constant" ]
+              }, {
+                "required" : [ "csimple" ]
+              }, {
+                "required" : [ "datasonnet" ]
+              }, {
+                "required" : [ "exchangeProperty" ]
+              }, {
+                "required" : [ "groovy" ]
+              }, {
+                "required" : [ "header" ]
+              }, {
+                "required" : [ "hl7terser" ]
+              }, {
+                "required" : [ "java" ]
+              }, {
+                "required" : [ "joor" ]
+              }, {
+                "required" : [ "jq" ]
+              }, {
+                "required" : [ "js" ]
+              }, {
+                "required" : [ "jsonpath" ]
+              }, {
+                "required" : [ "language" ]
+              }, {
+                "required" : [ "method" ]
+              }, {
+                "required" : [ "mvel" ]
+              }, {
+                "required" : [ "ognl" ]
+              }, {
+                "required" : [ "python" ]
+              }, {
+                "required" : [ "ref" ]
+              }, {
+                "required" : [ "simple" ]
+              }, {
+                "required" : [ "spel" ]
+              }, {
+                "required" : [ "tokenize" ]
+              }, {
+                "required" : [ "xpath" ]
+              }, {
+                "required" : [ "xquery" ]
+              }, {
+                "required" : [ "xtokenize" ]
+              } ]
+            }
+          }, {
+            "type" : "object",
+            "required" : [ "expression" ],
+            "properties" : {
+              "expression" : {
+                "title" : "Expression",
+                "description" : "Expression to return the value of the variable",
+                "$ref" : "#/items/definitions/org.apache.camel.model.language.ExpressionDefinition"
+              }
+            }
+          } ]
+        } ],
+        "properties" : {
+          "description" : {
+            "type" : "string",
+            "title" : "Description",
+            "description" : "Sets the description of this node"
+          },
+          "disabled" : {
+            "type" : "boolean",
+            "title" : "Disabled",
+            "description" : "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime."
+          },
+          "id" : {
+            "type" : "string",
+            "title" : "Id",
+            "description" : "Sets the id of this node"
+          },
+          "name" : {
+            "type" : "string",
+            "title" : "Name",
+            "description" : "Name of variable to set a new value The simple language can be used to define a dynamic evaluated variable name to be used. Otherwise a constant name will be used."
+          },
+          "constant" : { },
+          "csimple" : { },
+          "datasonnet" : { },
+          "exchangeProperty" : { },
+          "groovy" : { },
+          "header" : { },
+          "hl7terser" : { },
+          "java" : { },
+          "joor" : { },
+          "jq" : { },
+          "js" : { },
+          "jsonpath" : { },
+          "language" : { },
+          "method" : { },
+          "mvel" : { },
+          "ognl" : { },
+          "python" : { },
+          "ref" : { },
+          "simple" : { },
+          "spel" : { },
+          "tokenize" : { },
+          "xpath" : { },
+          "xquery" : { },
+          "xtokenize" : { },
+          "expression" : { }
+        },
+        "required" : [ "name" ]
+      },
       "org.apache.camel.model.SortDefinition" : {
         "title" : "Sort",
         "description" : "Sorts the contents of the message",
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RemoveVariableTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RemoveVariableTest.groovy
new file mode 100644
index 00000000000..d3f24acb038
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RemoveVariableTest.groovy
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.yaml
+
+import org.apache.camel.dsl.yaml.support.YamlTestSupport
+import org.apache.camel.model.RemoveVariableDefinition
+import org.apache.camel.spi.Resource
+import org.apache.camel.support.PluginHelper
+import org.junit.jupiter.api.Assertions
+
+class RemoveVariableTest extends YamlTestSupport {
+
+    def "removeVariable definition (#resource.location)"(Resource resource) {
+        when:
+            PluginHelper.getRoutesLoader(context).loadRoutes(resource)
+        then:
+            with(context.routeDefinitions[0].outputs[0], RemoveVariableDefinition) {
+                name == 'test'
+            }
+        where:
+            resource << [
+                asResource('expression', '''
+                    - from:
+                        uri: "direct:start"
+                        steps:    
+                          - removeVariable:
+                              name: test
+                          - to: "mock:result"
+                    '''),
+                asResource('expression-block', '''
+                    - from:
+                        uri: "direct:start"
+                        steps:    
+                          - removeVariable:
+                              name: test
+                          - to: "mock:result"
+                    ''')
+            ]
+    }
+
+    def "Error: kebab-case: remove-variable definition"() {
+        when:
+        var route = '''
+                    - from:
+                        uri: "direct:start"
+                        steps:    
+                          - remove-variable:
+                              name: test
+                          - to: "mock:result"
+            '''
+        then:
+        try {
+            loadRoutes(route)
+            Assertions.fail("Should have thrown exception")
+        } catch (e) {
+            e.message.contains("additional properties")
+        }
+    }
+}
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/SetVariableTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/SetVariableTest.groovy
new file mode 100644
index 00000000000..38fb251a837
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/SetVariableTest.groovy
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.yaml
+
+import org.apache.camel.dsl.yaml.support.YamlTestSupport
+import org.apache.camel.model.SetVariableDefinition
+import org.apache.camel.model.language.ExpressionDefinition
+import org.apache.camel.spi.Resource
+import org.apache.camel.support.PluginHelper
+import org.junit.jupiter.api.Assertions
+
+class SetVariableTest extends YamlTestSupport {
+
+    def "setVariable definition (#resource.location)"(Resource resource) {
+        when:
+            PluginHelper.getRoutesLoader(context).loadRoutes(resource)
+        then:
+            with(context.routeDefinitions[0].outputs[0], SetVariableDefinition) {
+                name == 'test'
+
+                with (expression, ExpressionDefinition) {
+                    language == 'simple'
+                    expression == 'Hello ${body}'
+                }
+            }
+        where:
+            resource << [
+                asResource('expression', '''
+                    - from:
+                        uri: "direct:start"
+                        steps:    
+                          - setVariable:
+                              name: test
+                              simple: "Hello ${body}"
+                          - to: "mock:result"
+                    '''),
+                asResource('expression-block', '''
+                    - from:
+                        uri: "direct:start"
+                        steps:    
+                          - setVariable:
+                              name: test
+                              expression:
+                                simple: "Hello ${body}"
+                          - to: "mock:result"
+                    ''')
+            ]
+    }
+
+    def "Error: kebab-case: set-property"() {
+        when:
+        var route = '''
+                    - from:
+                        uri: "direct:start"
+                        steps:    
+                          - set-variable:
+                              name: test
+                              expression:
+                                simple: "Hello ${body}"
+                          - to: "mock:result"
+                    '''
+        then:
+        try {
+            loadRoutes(route)
+            Assertions.fail("Should have thrown exception")
+        } catch (Exception e) {
+            Assertions.assertTrue(e.message.contains("additional properties"), e.getMessage())
+        }
+    }
+
+    def "kebab-case: set-property no validation"() {
+        when:
+        var route = '''
+                    - from:
+                        uri: "direct:start"
+                        steps:    
+                          - set-variable:
+                              name: test
+                              expression:
+                                simple: "Hello ${body}"
+                          - to: "mock:result"
+                    '''
+        loadRoutesNoValidate(route)
+
+        then:
+        with(context.routeDefinitions[0].outputs[0], SetVariableDefinition) {
+            name == 'test'
+
+            with(expression, ExpressionDefinition) {
+                language == 'simple'
+                expression == 'Hello ${body}'
+            }
+        }
+    }
+}