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 2024/01/31 10:46:52 UTC
(camel) branch main updated: Var headers (#12960)
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 e3582740a93 Var headers (#12960)
e3582740a93 is described below
commit e3582740a931ffb4e8a0938c45814706cb411ef7
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Jan 31 11:46:46 2024 +0100
Var headers (#12960)
CAMEL-19749: variables - Should also copy message headers into variable when using EIP variables
---
.../apache/camel/catalog/languages/hl7terser.json | 9 +-
.../org/apache/camel/catalog/languages/jq.json | 9 +-
.../apache/camel/catalog/languages/jsonpath.json | 9 +-
.../org/apache/camel/catalog/models/hl7terser.json | 9 +-
.../org/apache/camel/catalog/models/jq.json | 9 +-
.../org/apache/camel/catalog/models/jsonpath.json | 9 +-
.../apache/camel/catalog/schemas/camel-spring.xsd | 9 +
.../org/apache/camel/component/hl7/hl7terser.json | 9 +-
.../resources/org/apache/camel/language/jq/jq.json | 9 +-
.../org/apache/camel/language/jq/JqExpression.java | 24 +-
.../org/apache/camel/language/jq/JqFunctions.java | 2 +-
.../org/apache/camel/language/jq/JqLanguage.java | 6 +-
.../language/jq/JqSimpleTransformVariableTest.java | 42 ++--
.../org/apache/camel/jsonpath/jsonpath.json | 9 +-
.../apache/camel/jsonpath/JsonPathExpression.java | 12 +
.../apache/camel/jsonpath/JsonPathLanguage.java | 8 +-
.../camel/spring/processor/FromVariableTest.xml | 2 +
.../src/main/java/org/apache/camel/Exchange.java | 2 +-
.../VariableRepository.java => VariableAware.java} | 25 +-
.../apache/camel/spi/StreamCachingStrategy.java | 8 +
.../org/apache/camel/spi/VariableRepository.java | 11 +-
.../impl/engine/DefaultStreamCachingStrategy.java | 18 +-
.../modules/languages/pages/simple-language.adoc | 14 ++
.../simple/ast/SimpleFunctionExpression.java | 30 +++
.../camel/language/tokenizer/TokenizeLanguage.java | 3 +-
.../org/apache/camel/model/language/hl7terser.json | 9 +-
.../org/apache/camel/model/language/jq.json | 9 +-
.../org/apache/camel/model/language/jsonpath.json | 9 +-
.../java/org/apache/camel/builder/Builder.java | 2 +-
.../org/apache/camel/builder/DataFormatClause.java | 5 +-
.../camel/builder/ExpressionClauseSupport.java | 2 +-
.../camel/builder/LanguageBuilderFactory.java | 2 +-
.../camel/model/dataformat/BeanioDataFormat.java | 11 +-
.../SingleInputTypedExpressionDefinition.java | 27 ++
.../camel/model/language/WasmExpression.java | 2 +-
.../java/org/apache/camel/processor/Enricher.java | 20 +-
.../org/apache/camel/processor/PollEnricher.java | 17 +-
.../camel/processor/SendDynamicProcessor.java | 55 ++--
.../org/apache/camel/processor/SendProcessor.java | 32 ++-
.../org/apache/camel/reifier/RouteReifier.java | 7 +-
.../dataformat/BeanioDataFormatReifier.java | 4 +-
.../language/JsonPathExpressionReifier.java | 3 +-
.../SingleInputTypedExpressionReifier.java | 7 +-
.../org/apache/camel/language/VariableTest.java | 26 ++
.../apache/camel/language/simple/SimpleTest.java | 9 +
.../camel/processor/EnrichVariableHeadersTest.java | 94 +++++++
.../apache/camel/processor/FromVariableTest.java | 26 +-
...est.java => PollEnrichVariableHeadersTest.java} | 24 +-
.../processor/ToDynamicVariableHeadersTest.java | 93 +++++++
.../camel/processor/ToVariableHeadersTest.java | 94 +++++++
.../camel/converter/stream/CachedOutputStream.java | 38 ++-
.../org/apache/camel/support/AbstractExchange.java | 9 +-
...sitory.java => AbstractVariableRepository.java} | 61 ++++-
.../org/apache/camel/support/ExchangeHelper.java | 66 ++++-
.../camel/support/ExchangeVariableRepository.java | 106 ++++----
.../camel/support/GlobalVariableRepository.java | 60 +----
.../camel/support/HeaderVariableRepository.java | 68 +++++
.../camel/support/SingleInputLanguageSupport.java | 18 +-
.../support/SingleInputTypedLanguageSupport.java | 27 +-
.../camel/support/builder/ExpressionBuilder.java | 104 +++++++-
.../camel/support/processor/MarshalProcessor.java | 1 -
.../support/processor/UnmarshalProcessor.java | 1 -
.../java/org/apache/camel/xml/in/ModelParser.java | 1 +
.../java/org/apache/camel/xml/out/ModelWriter.java | 1 +
.../org/apache/camel/yaml/out/ModelWriter.java | 1 +
docs/user-manual/modules/ROOT/pages/variables.adoc | 279 ++++-----------------
.../dsl/yaml/deserializers/ModelDeserializers.java | 22 +-
.../generated/resources/schema/camelYamlDsl.json | 15 ++
.../apache/camel/dsl/yaml/FromVariableTest.groovy | 17 +-
69 files changed, 1218 insertions(+), 563 deletions(-)
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/hl7terser.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/hl7terser.json
index 3865481202b..58cd42e820c 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/hl7terser.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/hl7terser.json
@@ -18,9 +18,10 @@
"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" },
"expression": { "index": 1, "kind": "value", "displayName": "Expression", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The expression value in your chosen language syntax" },
- "headerName": { "index": 2, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
- "propertyName": { "index": 3, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
- "resultType": { "index": 4, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
- "trim": { "index": 5, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
+ "variableName": { "index": 2, "kind": "attribute", "displayName": "Variable Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to use as input, instead of the message body It has as higher precedent if other are set." },
+ "headerName": { "index": 3, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
+ "propertyName": { "index": 4, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
+ "resultType": { "index": 5, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
+ "trim": { "index": 6, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
}
}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/jq.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/jq.json
index 01859b055b7..2414f6e84ef 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/jq.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/jq.json
@@ -18,9 +18,10 @@
"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" },
"expression": { "index": 1, "kind": "value", "displayName": "Expression", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The expression value in your chosen language syntax" },
- "headerName": { "index": 2, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
- "propertyName": { "index": 3, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
- "resultType": { "index": 4, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
- "trim": { "index": 5, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
+ "variableName": { "index": 2, "kind": "attribute", "displayName": "Variable Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to use as input, instead of the message body It has as higher precedent if other are set." },
+ "headerName": { "index": 3, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
+ "propertyName": { "index": 4, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
+ "resultType": { "index": 5, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
+ "trim": { "index": 6, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
}
}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/jsonpath.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/jsonpath.json
index 1f60d86297e..ec518053441 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/jsonpath.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/jsonpath.json
@@ -24,9 +24,10 @@
"writeAsString": { "index": 5, "kind": "attribute", "displayName": "Write As String", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to write the output of each row\/element as a JSON String value instead of a Map\/POJO value." },
"unpackArray": { "index": 6, "kind": "attribute", "displayName": "Unpack Array", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to unpack a single element json-array into an object." },
"option": { "index": 7, "kind": "attribute", "displayName": "Option", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "DEFAULT_PATH_LEAF_TO_NULL", "ALWAYS_RETURN_LIST", "AS_PATH_LIST", "SUPPRESS_EXCEPTIONS", "REQUIRE_PROPERTIES" ], "deprecated": false, "autowired": false, "secret": false, "description": "To configure additional options on JSONPath. Multiple values can be separated by comma." },
- "headerName": { "index": 8, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
- "propertyName": { "index": 9, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
- "resultType": { "index": 10, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
- "trim": { "index": 11, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
+ "variableName": { "index": 8, "kind": "attribute", "displayName": "Variable Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to use as input, instead of the message body It has as higher precedent if other are set." },
+ "headerName": { "index": 9, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
+ "propertyName": { "index": 10, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
+ "resultType": { "index": 11, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
+ "trim": { "index": 12, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
}
}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/hl7terser.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/hl7terser.json
index c21ace421f3..175a11f5b72 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/hl7terser.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/hl7terser.json
@@ -15,9 +15,10 @@
"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" },
"expression": { "index": 1, "kind": "value", "displayName": "Expression", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The expression value in your chosen language syntax" },
- "headerName": { "index": 2, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
- "propertyName": { "index": 3, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
- "resultType": { "index": 4, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
- "trim": { "index": 5, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
+ "variableName": { "index": 2, "kind": "attribute", "displayName": "Variable Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to use as input, instead of the message body It has as higher precedent if other are set." },
+ "headerName": { "index": 3, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
+ "propertyName": { "index": 4, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
+ "resultType": { "index": 5, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
+ "trim": { "index": 6, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
}
}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/jq.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/jq.json
index c0d966613c3..04fb7ca5648 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/jq.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/jq.json
@@ -15,9 +15,10 @@
"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" },
"expression": { "index": 1, "kind": "value", "displayName": "Expression", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The expression value in your chosen language syntax" },
- "headerName": { "index": 2, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
- "propertyName": { "index": 3, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
- "resultType": { "index": 4, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
- "trim": { "index": 5, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
+ "variableName": { "index": 2, "kind": "attribute", "displayName": "Variable Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to use as input, instead of the message body It has as higher precedent if other are set." },
+ "headerName": { "index": 3, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
+ "propertyName": { "index": 4, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
+ "resultType": { "index": 5, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
+ "trim": { "index": 6, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
}
}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/jsonpath.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/jsonpath.json
index 18ebc270c0c..7a139068350 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/jsonpath.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/jsonpath.json
@@ -21,9 +21,10 @@
"writeAsString": { "index": 5, "kind": "attribute", "displayName": "Write As String", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to write the output of each row\/element as a JSON String value instead of a Map\/POJO value." },
"unpackArray": { "index": 6, "kind": "attribute", "displayName": "Unpack Array", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to unpack a single element json-array into an object." },
"option": { "index": 7, "kind": "attribute", "displayName": "Option", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "DEFAULT_PATH_LEAF_TO_NULL", "ALWAYS_RETURN_LIST", "AS_PATH_LIST", "SUPPRESS_EXCEPTIONS", "REQUIRE_PROPERTIES" ], "deprecated": false, "autowired": false, "secret": false, "description": "To configure additional options on JSONPath. Multiple values can be separated by comma." },
- "headerName": { "index": 8, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
- "propertyName": { "index": 9, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
- "resultType": { "index": 10, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
- "trim": { "index": 11, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
+ "variableName": { "index": 8, "kind": "attribute", "displayName": "Variable Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to use as input, instead of the message body It has as higher precedent if other are set." },
+ "headerName": { "index": 9, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
+ "propertyName": { "index": 10, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
+ "resultType": { "index": 11, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
+ "trim": { "index": 12, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
}
}
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 a9f51331f7f..8db2e5a49fb 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
@@ -15242,6 +15242,15 @@ The String representation of the MediaType to output.
<xs:complexType abstract="true" name="singleInputTypedExpressionDefinition">
<xs:simpleContent>
<xs:extension base="tns:typedExpressionDefinition">
+ <xs:attribute name="variableName" type="xs:string">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+<![CDATA[
+Name of variable to use as input, instead of the message body It has as higher precedent if other are set.
+]]>
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
<xs:attribute name="headerName" type="xs:string">
<xs:annotation>
<xs:documentation xml:lang="en">
diff --git a/components/camel-hl7/src/generated/resources/org/apache/camel/component/hl7/hl7terser.json b/components/camel-hl7/src/generated/resources/org/apache/camel/component/hl7/hl7terser.json
index 3865481202b..58cd42e820c 100644
--- a/components/camel-hl7/src/generated/resources/org/apache/camel/component/hl7/hl7terser.json
+++ b/components/camel-hl7/src/generated/resources/org/apache/camel/component/hl7/hl7terser.json
@@ -18,9 +18,10 @@
"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" },
"expression": { "index": 1, "kind": "value", "displayName": "Expression", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The expression value in your chosen language syntax" },
- "headerName": { "index": 2, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
- "propertyName": { "index": 3, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
- "resultType": { "index": 4, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
- "trim": { "index": 5, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
+ "variableName": { "index": 2, "kind": "attribute", "displayName": "Variable Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to use as input, instead of the message body It has as higher precedent if other are set." },
+ "headerName": { "index": 3, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
+ "propertyName": { "index": 4, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
+ "resultType": { "index": 5, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
+ "trim": { "index": 6, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
}
}
diff --git a/components/camel-jq/src/generated/resources/org/apache/camel/language/jq/jq.json b/components/camel-jq/src/generated/resources/org/apache/camel/language/jq/jq.json
index 01859b055b7..2414f6e84ef 100644
--- a/components/camel-jq/src/generated/resources/org/apache/camel/language/jq/jq.json
+++ b/components/camel-jq/src/generated/resources/org/apache/camel/language/jq/jq.json
@@ -18,9 +18,10 @@
"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" },
"expression": { "index": 1, "kind": "value", "displayName": "Expression", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The expression value in your chosen language syntax" },
- "headerName": { "index": 2, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
- "propertyName": { "index": 3, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
- "resultType": { "index": 4, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
- "trim": { "index": 5, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
+ "variableName": { "index": 2, "kind": "attribute", "displayName": "Variable Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to use as input, instead of the message body It has as higher precedent if other are set." },
+ "headerName": { "index": 3, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
+ "propertyName": { "index": 4, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
+ "resultType": { "index": 5, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
+ "trim": { "index": 6, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
}
}
diff --git a/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqExpression.java b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqExpression.java
index f66c0f8f1ed..a72cc5f90a3 100644
--- a/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqExpression.java
+++ b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqExpression.java
@@ -32,9 +32,11 @@ import org.apache.camel.Exchange;
import org.apache.camel.ExpressionIllegalSyntaxException;
import org.apache.camel.InvalidPayloadException;
import org.apache.camel.NoSuchHeaderOrPropertyException;
+import org.apache.camel.NoSuchVariableException;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.TypeConverter;
import org.apache.camel.spi.ExpressionResultTypeAware;
+import org.apache.camel.support.ExchangeHelper;
import org.apache.camel.support.ExpressionAdapter;
import org.apache.camel.support.MessageHelper;
@@ -48,6 +50,7 @@ public class JqExpression extends ExpressionAdapter implements ExpressionResultT
private JsonQuery query;
private TypeConverter typeConverter;
+ private String variableName;
private String headerName;
private String propertyName;
@@ -117,6 +120,17 @@ public class JqExpression extends ExpressionAdapter implements ExpressionResultT
this.resultTypeName = resultTypeName;
}
+ public String getVariableName() {
+ return variableName;
+ }
+
+ /**
+ * Name of the variable to use as input instead of the message body.
+ */
+ public void setVariableName(String variableName) {
+ this.variableName = variableName;
+ }
+
public String getHeaderName() {
return headerName;
}
@@ -206,7 +220,7 @@ public class JqExpression extends ExpressionAdapter implements ExpressionResultT
private JsonNode getPayload(Exchange exchange) throws Exception {
JsonNode payload = null;
- if (headerName == null && propertyName == null) {
+ if (variableName == null && headerName == null && propertyName == null) {
payload = exchange.getMessage().getBody(JsonNode.class);
if (payload == null) {
throw new InvalidPayloadException(exchange, JsonNode.class);
@@ -214,7 +228,13 @@ public class JqExpression extends ExpressionAdapter implements ExpressionResultT
// if body is stream cached then reset, so we can re-read it again
MessageHelper.resetStreamCache(exchange.getMessage());
} else {
- if (headerName != null) {
+ if (variableName != null) {
+ payload = ExchangeHelper.getVariable(exchange, variableName, JsonNode.class);
+ if (payload == null) {
+ throw new NoSuchVariableException(exchange, variableName, JsonNode.class);
+ }
+ }
+ if (payload == null && headerName != null) {
payload = exchange.getMessage().getHeader(headerName, JsonNode.class);
}
if (payload == null && propertyName != null) {
diff --git a/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqFunctions.java b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqFunctions.java
index 82d5ce182fa..8589ed7eeeb 100644
--- a/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqFunctions.java
+++ b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqFunctions.java
@@ -181,7 +181,7 @@ public final class JqFunctions {
*
* <pre>
* {@code
- * .name = proeprty(\"CommitterName\")"
+ * .name = property(\"CommitterName\")"
* }
* </pre>
*
diff --git a/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqLanguage.java b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqLanguage.java
index c5ef627cf27..151d4dcb242 100644
--- a/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqLanguage.java
+++ b/components/camel-jq/src/main/java/org/apache/camel/language/jq/JqLanguage.java
@@ -71,6 +71,7 @@ public class JqLanguage extends SingleInputTypedLanguageSupport implements Stati
public Expression createExpression(String expression) {
JqExpression answer = new JqExpression(Scope.newChildScope(rootScope), expression);
answer.setResultType(getResultType());
+ answer.setVariableName(getVariableName());
answer.setHeaderName(getHeaderName());
answer.setPropertyName(getPropertyName());
answer.init(getCamelContext());
@@ -81,8 +82,9 @@ public class JqLanguage extends SingleInputTypedLanguageSupport implements Stati
public Expression createExpression(String expression, Object[] properties) {
JqExpression answer = new JqExpression(Scope.newChildScope(rootScope), expression);
answer.setResultType(property(Class.class, properties, 0, getResultType()));
- answer.setHeaderName(property(String.class, properties, 1, getHeaderName()));
- answer.setPropertyName(property(String.class, properties, 2, getPropertyName()));
+ answer.setVariableName(property(String.class, properties, 1, getVariableName()));
+ answer.setHeaderName(property(String.class, properties, 2, getHeaderName()));
+ answer.setPropertyName(property(String.class, properties, 3, getPropertyName()));
answer.init(getCamelContext());
return answer;
}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/FromVariableTest.java b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqSimpleTransformVariableTest.java
similarity index 52%
copy from core/camel-core/src/test/java/org/apache/camel/processor/FromVariableTest.java
copy to components/camel-jq/src/test/java/org/apache/camel/language/jq/JqSimpleTransformVariableTest.java
index 3dfc5800ee8..5e62dbad94f 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/FromVariableTest.java
+++ b/components/camel-jq/src/test/java/org/apache/camel/language/jq/JqSimpleTransformVariableTest.java
@@ -14,35 +14,41 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.processor;
+package org.apache.camel.language.jq;
-import org.apache.camel.ContextTestSupport;
import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
import org.junit.jupiter.api.Test;
-public class FromVariableTest extends ContextTestSupport {
+public class JqSimpleTransformVariableTest extends JqTestSupport {
- @Test
- public void testOriginalBody() throws Exception {
- getMockEndpoint("mock:foo").expectedBodiesReceived("Bye World");
- getMockEndpoint("mock:result").expectedBodiesReceived("World");
-
- template.sendBody("direct:start", "World");
-
- assertMockEndpointsSatisfied();
- }
+ private static String EXPECTED = """
+ {
+ "country": "se",
+ }""";
@Override
- protected RouteBuilder createRouteBuilder() throws Exception {
+ protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
@Override
- public void configure() throws Exception {
- fromV("direct:start", "myKey")
- .transform().simple("Bye ${body}")
- .to("mock:foo")
- .setBody(simple("${variable:myKey}"))
+ public void configure() {
+ from("direct:start")
+ .setVariable("place", constant("{ \"name\": \"sweden\", \"iso\": \"se\" }"))
+ .transform().simple("""
+ {
+ "country": "${jq(variable:place,.iso)}",
+ }""")
.to("mock:result");
}
};
}
+
+ @Test
+ public void testTransform() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived(EXPECTED);
+
+ template.sendBody("direct:start", "{\"id\": 123, \"age\": 42, \"name\": \"scott\"}");
+
+ MockEndpoint.assertIsSatisfied(context);
+ }
}
diff --git a/components/camel-jsonpath/src/generated/resources/org/apache/camel/jsonpath/jsonpath.json b/components/camel-jsonpath/src/generated/resources/org/apache/camel/jsonpath/jsonpath.json
index 1f60d86297e..ec518053441 100644
--- a/components/camel-jsonpath/src/generated/resources/org/apache/camel/jsonpath/jsonpath.json
+++ b/components/camel-jsonpath/src/generated/resources/org/apache/camel/jsonpath/jsonpath.json
@@ -24,9 +24,10 @@
"writeAsString": { "index": 5, "kind": "attribute", "displayName": "Write As String", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to write the output of each row\/element as a JSON String value instead of a Map\/POJO value." },
"unpackArray": { "index": 6, "kind": "attribute", "displayName": "Unpack Array", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to unpack a single element json-array into an object." },
"option": { "index": 7, "kind": "attribute", "displayName": "Option", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "DEFAULT_PATH_LEAF_TO_NULL", "ALWAYS_RETURN_LIST", "AS_PATH_LIST", "SUPPRESS_EXCEPTIONS", "REQUIRE_PROPERTIES" ], "deprecated": false, "autowired": false, "secret": false, "description": "To configure additional options on JSONPath. Multiple values can be separated by comma." },
- "headerName": { "index": 8, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
- "propertyName": { "index": 9, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
- "resultType": { "index": 10, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
- "trim": { "index": 11, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
+ "variableName": { "index": 8, "kind": "attribute", "displayName": "Variable Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to use as input, instead of the message body It has as higher precedent if other are set." },
+ "headerName": { "index": 9, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
+ "propertyName": { "index": 10, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
+ "resultType": { "index": 11, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
+ "trim": { "index": 12, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
}
}
diff --git a/components/camel-jsonpath/src/main/java/org/apache/camel/jsonpath/JsonPathExpression.java b/components/camel-jsonpath/src/main/java/org/apache/camel/jsonpath/JsonPathExpression.java
index 1c8b9cccc29..f0c27d7cd4a 100644
--- a/components/camel-jsonpath/src/main/java/org/apache/camel/jsonpath/JsonPathExpression.java
+++ b/components/camel-jsonpath/src/main/java/org/apache/camel/jsonpath/JsonPathExpression.java
@@ -43,6 +43,7 @@ public class JsonPathExpression extends ExpressionAdapter {
private boolean allowEasyPredicate = true;
private boolean writeAsString;
private boolean unpackArray;
+ private String variableName;
private String headerName;
private String propertyName;
private Option[] options;
@@ -129,6 +130,17 @@ public class JsonPathExpression extends ExpressionAdapter {
this.unpackArray = unpackArray;
}
+ public String getVariableName() {
+ return variableName;
+ }
+
+ /**
+ * Name of variable to use as input, instead of the message body
+ */
+ public void setVariableName(String variableName) {
+ this.variableName = variableName;
+ }
+
public String getHeaderName() {
return headerName;
}
diff --git a/components/camel-jsonpath/src/main/java/org/apache/camel/jsonpath/JsonPathLanguage.java b/components/camel-jsonpath/src/main/java/org/apache/camel/jsonpath/JsonPathLanguage.java
index 1dc16711993..b8879cfcbec 100644
--- a/components/camel-jsonpath/src/main/java/org/apache/camel/jsonpath/JsonPathLanguage.java
+++ b/components/camel-jsonpath/src/main/java/org/apache/camel/jsonpath/JsonPathLanguage.java
@@ -102,9 +102,10 @@ public class JsonPathLanguage extends SingleInputTypedLanguageSupport implements
answer.setSuppressExceptions(suppressExceptions);
answer.setAllowSimple(allowSimple);
answer.setAllowEasyPredicate(allowEasyPredicate);
- answer.setHeaderName(getHeaderName());
answer.setWriteAsString(writeAsString);
answer.setUnpackArray(unpackArray);
+ answer.setVariableName(getVariableName());
+ answer.setHeaderName(getHeaderName());
answer.setPropertyName(getPropertyName());
answer.setOptions(options);
answer.init(getCamelContext());
@@ -137,6 +138,7 @@ public class JsonPathLanguage extends SingleInputTypedLanguageSupport implements
answer.setOptions(list.toArray(new Option[0]));
}
answer.setPropertyName(property(String.class, properties, 8, getPropertyName()));
+ answer.setVariableName(property(String.class, properties, 9, getVariableName()));
answer.init(getCamelContext());
return answer;
}
@@ -178,6 +180,10 @@ public class JsonPathLanguage extends SingleInputTypedLanguageSupport implements
case "allowEasyPredicate":
setAllowEasyPredicate(PropertyConfigurerSupport.property(camelContext, boolean.class, value));
return true;
+ case "variablename":
+ case "variableName":
+ setVariableName(PropertyConfigurerSupport.property(camelContext, String.class, value));
+ return true;
case "headername":
case "headerName":
setHeaderName(PropertyConfigurerSupport.property(camelContext, String.class, value));
diff --git a/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/processor/FromVariableTest.xml b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/processor/FromVariableTest.xml
index 1f578ec457d..595d382242e 100644
--- a/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/processor/FromVariableTest.xml
+++ b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/processor/FromVariableTest.xml
@@ -29,6 +29,8 @@
<jmxAgent id="jmx" disabled="true"/>
<route>
<from uri="direct:start" variableReceive="myKey"/>
+ <setHeader name="foo"><constant>456</constant></setHeader>
+ <setHeader name="bar"><constant>Murphy</constant></setHeader>
<transform><simple>Bye ${body}</simple></transform>
<to uri="mock:foo"/>
<setBody>
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 3aa5175e076..3495a865391 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
@@ -64,7 +64,7 @@ import org.apache.camel.spi.annotations.ConstantProvider;
* details.
*/
@ConstantProvider("org.apache.camel.ExchangeConstantProvider")
-public interface Exchange {
+public interface Exchange extends VariableAware {
String AUTHENTICATION = "CamelAuthentication";
String AUTHENTICATION_FAILURE_POLICY_ID = "CamelAuthenticationFailurePolicyId";
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/VariableAware.java
similarity index 61%
copy from core/camel-api/src/main/java/org/apache/camel/spi/VariableRepository.java
copy to core/camel-api/src/main/java/org/apache/camel/VariableAware.java
index 153b3502135..ab82303117c 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/VariableRepository.java
+++ b/core/camel-api/src/main/java/org/apache/camel/VariableAware.java
@@ -14,27 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.spi;
-
-import org.apache.camel.StaticService;
+package org.apache.camel;
/**
- * Repository for storing and accessing variables.
+ * An interface to represent an object that supports variables.
*/
-public interface VariableRepository extends StaticService {
-
- /**
- * The id of this repository.
- */
- String getId();
+public interface VariableAware {
/**
* Returns a variable by name.
*
- * If the variable is of type {@link org.apache.camel.StreamCache} then the repository should ensure to reset the
- * stream cache before returning the value, to ensure the content can be read by the Camel end user and would be
- * re-readable next time.
- *
* @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
*/
@@ -48,12 +37,4 @@ public interface VariableRepository extends StaticService {
*/
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/StreamCachingStrategy.java b/core/camel-api/src/main/java/org/apache/camel/spi/StreamCachingStrategy.java
index 68de83dd718..267949c9ba6 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/StreamCachingStrategy.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/StreamCachingStrategy.java
@@ -282,4 +282,12 @@ public interface StreamCachingStrategy extends StaticService {
*/
StreamCache cache(Message message);
+ /**
+ * Caches the value aas a {@link StreamCache}.
+ *
+ * @param value the value
+ * @return the value cached as a {@link StreamCache}, or <tt>null</tt> if not possible or no need to cache
+ */
+ StreamCache cache(Object value);
+
}
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
index 153b3502135..fba280fcda1 100644
--- 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
@@ -17,11 +17,12 @@
package org.apache.camel.spi;
import org.apache.camel.StaticService;
+import org.apache.camel.VariableAware;
/**
* Repository for storing and accessing variables.
*/
-public interface VariableRepository extends StaticService {
+public interface VariableRepository extends StaticService, VariableAware {
/**
* The id of this repository.
@@ -40,14 +41,6 @@ public interface VariableRepository extends StaticService {
*/
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
*
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultStreamCachingStrategy.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultStreamCachingStrategy.java
index 4c0919f7b7e..92df0417bd8 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultStreamCachingStrategy.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultStreamCachingStrategy.java
@@ -249,21 +249,33 @@ public class DefaultStreamCachingStrategy extends ServiceSupport implements Came
@Override
public StreamCache cache(Exchange exchange) {
- return cache(exchange.getMessage());
+ return doCache(exchange.getMessage().getBody(), exchange);
}
@Override
public StreamCache cache(Message message) {
+ return doCache(message.getBody(), message.getExchange());
+ }
+
+ @Override
+ public StreamCache cache(Object body) {
+ return doCache(body, null);
+ }
+
+ private StreamCache doCache(Object body, Exchange exchange) {
StreamCache cache = null;
// try convert to stream cache
- Object body = message.getBody();
if (body != null) {
boolean allowed = allowClasses == null && denyClasses == null;
if (!allowed) {
allowed = checkAllowDenyList(body);
}
if (allowed) {
- cache = camelContext.getTypeConverter().convertTo(StreamCache.class, message.getExchange(), body);
+ if (exchange != null) {
+ cache = camelContext.getTypeConverter().convertTo(StreamCache.class, exchange, body);
+ } else {
+ cache = camelContext.getTypeConverter().convertTo(StreamCache.class, body);
+ }
}
}
if (cache != null) {
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 9a663faf367..acb01a71d40 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
@@ -274,12 +274,26 @@ The algorithm can be SHA-256 (default) or SHA3-256.
|jsonpath(exp) | Object | When working with JSon data, then this allows to use the JsonPath language
for example to extract data from the message body (in JSon format). This requires having camel-jsonpath JAR on the classpath.
+|jsonpath(input,exp) | Object | When working with JSon data, then this allows to use the JsonPath language
+for example to extract data from the message body (in JSon format). This requires having camel-jsonpath JAR on the classpath.
+For _input_ you can choose `header:key`, `exchangeProperty:key` or `variable:key` to use as input for the JSon payload instead of the message body.
+
|jq(exp) | Object | When working with JSon data, then this allows to use the JQ language
for example to extract data from the message body (in JSon format). This requires having camel-jq JAR on the classpath.
+|jq(input,exp) | Object | When working with JSon data, then this allows to use the JQ language
+for example to extract data from the message body (in JSon format). This requires having camel-jq JAR on the classpath.
+For _input_ you can choose `header:key`, `exchangeProperty:key` or `variable:key` to use as input for the JSon payload instead of the message body.
+
|xpath(exp) | Object | When working with XML data, then this allows to use the XPath language
for example to extract data from the message body (in XML format). This requires having camel-xpath JAR on the classpath.
+|xpath(input,exp) | Object | When working with XML data, then this allows to use the XPath language
+for example to extract data from the message body (in XML format). This requires having camel-xpath JAR on the classpath.
+For _input_ you can choose `header:key`, `exchangeProperty:key` or `variable:key` to use as input for the JSon payload instead of the message body.
+
+|pretty(exp) | String | Converts the inlined expression to a String, and attempts to pretty print if JSon or XML, otherwise the expression is returned as the String value.
+
|=======================================================================
== OGNL expression support
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 20b07a3d12b..a9276250d2e 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
@@ -175,6 +175,18 @@ public class SimpleFunctionExpression extends LiteralExpression {
return SimpleExpressionBuilder.exchangeOgnlExpression(remainder);
}
+ // pretty
+ remainder = ifStartsWithReturnRemainder("pretty(", function);
+ if (remainder != null) {
+ String exp = StringHelper.beforeLast(remainder, ")");
+ if (exp == null) {
+ throw new SimpleParserException("Valid syntax: ${pretty(exp)} was: " + function, token.getIndex());
+ }
+ exp = StringHelper.removeQuotes(exp);
+ Expression inlined = camelContext.resolveLanguage("simple").createExpression(exp);
+ return ExpressionBuilder.prettyExpression(inlined);
+ }
+
// file: prefix
remainder = ifStartsWithReturnRemainder("file:", function);
if (remainder != null) {
@@ -522,6 +534,12 @@ public class SimpleFunctionExpression extends LiteralExpression {
throw new SimpleParserException("Valid syntax: ${jq(exp)} was: " + function, token.getIndex());
}
exp = StringHelper.removeQuotes(exp);
+ if (exp.startsWith("header:") || exp.startsWith("property:") || exp.startsWith("exchangeProperty:")
+ || exp.startsWith("variable:")) {
+ String input = StringHelper.before(exp, ",");
+ exp = StringHelper.after(exp, ",");
+ return ExpressionBuilder.singleInputLanguageExpression("jq", exp, input);
+ }
return ExpressionBuilder.languageExpression("jq", exp);
}
// jsonpath
@@ -532,6 +550,12 @@ public class SimpleFunctionExpression extends LiteralExpression {
throw new SimpleParserException("Valid syntax: ${jsonpath(exp)} was: " + function, token.getIndex());
}
exp = StringHelper.removeQuotes(exp);
+ if (exp.startsWith("header:") || exp.startsWith("property:") || exp.startsWith("exchangeProperty:")
+ || exp.startsWith("variable:")) {
+ String input = StringHelper.before(exp, ",");
+ exp = StringHelper.after(exp, ",");
+ return ExpressionBuilder.singleInputLanguageExpression("jq", exp, input);
+ }
return ExpressionBuilder.languageExpression("jsonpath", exp);
}
remainder = ifStartsWithReturnRemainder("xpath(", function);
@@ -541,6 +565,12 @@ public class SimpleFunctionExpression extends LiteralExpression {
throw new SimpleParserException("Valid syntax: ${xpath(exp)} was: " + function, token.getIndex());
}
exp = StringHelper.removeQuotes(exp);
+ if (exp.startsWith("header:") || exp.startsWith("property:") || exp.startsWith("exchangeProperty:")
+ || exp.startsWith("variable:")) {
+ String input = StringHelper.before(exp, ",");
+ exp = StringHelper.after(exp, ",");
+ return ExpressionBuilder.singleInputLanguageExpression("jq", exp, input);
+ }
return ExpressionBuilder.languageExpression("xpath", exp);
}
diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java b/core/camel-core-languages/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
index 0d9b0da25f8..3662e1b0284 100644
--- a/core/camel-core-languages/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
+++ b/core/camel-core-languages/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
@@ -133,7 +133,8 @@ public class TokenizeLanguage extends SingleInputLanguageSupport implements Prop
if (answer == null) {
// use the regular tokenizer
- final Expression exp = ExpressionBuilder.singleInputExpression(getHeaderName(), getPropertyName());
+ final Expression exp
+ = ExpressionBuilder.singleInputExpression(getVariableName(), getHeaderName(), getPropertyName());
if (regex) {
answer = ExpressionBuilder.regexTokenizeExpression(exp, token);
} else {
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/hl7terser.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/hl7terser.json
index c21ace421f3..175a11f5b72 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/hl7terser.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/hl7terser.json
@@ -15,9 +15,10 @@
"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" },
"expression": { "index": 1, "kind": "value", "displayName": "Expression", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The expression value in your chosen language syntax" },
- "headerName": { "index": 2, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
- "propertyName": { "index": 3, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
- "resultType": { "index": 4, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
- "trim": { "index": 5, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
+ "variableName": { "index": 2, "kind": "attribute", "displayName": "Variable Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to use as input, instead of the message body It has as higher precedent if other are set." },
+ "headerName": { "index": 3, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
+ "propertyName": { "index": 4, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
+ "resultType": { "index": 5, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
+ "trim": { "index": 6, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
}
}
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jq.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jq.json
index c0d966613c3..04fb7ca5648 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jq.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jq.json
@@ -15,9 +15,10 @@
"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" },
"expression": { "index": 1, "kind": "value", "displayName": "Expression", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The expression value in your chosen language syntax" },
- "headerName": { "index": 2, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
- "propertyName": { "index": 3, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
- "resultType": { "index": 4, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
- "trim": { "index": 5, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
+ "variableName": { "index": 2, "kind": "attribute", "displayName": "Variable Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to use as input, instead of the message body It has as higher precedent if other are set." },
+ "headerName": { "index": 3, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
+ "propertyName": { "index": 4, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
+ "resultType": { "index": 5, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
+ "trim": { "index": 6, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
}
}
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jsonpath.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jsonpath.json
index 18ebc270c0c..7a139068350 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jsonpath.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/language/jsonpath.json
@@ -21,9 +21,10 @@
"writeAsString": { "index": 5, "kind": "attribute", "displayName": "Write As String", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to write the output of each row\/element as a JSON String value instead of a Map\/POJO value." },
"unpackArray": { "index": 6, "kind": "attribute", "displayName": "Unpack Array", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to unpack a single element json-array into an object." },
"option": { "index": 7, "kind": "attribute", "displayName": "Option", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "DEFAULT_PATH_LEAF_TO_NULL", "ALWAYS_RETURN_LIST", "AS_PATH_LIST", "SUPPRESS_EXCEPTIONS", "REQUIRE_PROPERTIES" ], "deprecated": false, "autowired": false, "secret": false, "description": "To configure additional options on JSONPath. Multiple values can be separated by comma." },
- "headerName": { "index": 8, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
- "propertyName": { "index": 9, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
- "resultType": { "index": 10, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
- "trim": { "index": 11, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
+ "variableName": { "index": 8, "kind": "attribute", "displayName": "Variable Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of variable to use as input, instead of the message body It has as higher precedent if other are set." },
+ "headerName": { "index": 9, "kind": "attribute", "displayName": "Header Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of header to use as input, instead of the message body It has as higher precedent than the propertyName if both are set." },
+ "propertyName": { "index": 10, "kind": "attribute", "displayName": "Property Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set." },
+ "resultType": { "index": 11, "kind": "attribute", "displayName": "Result Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the class of the result type (type from output)" },
+ "trim": { "index": 12, "kind": "attribute", "displayName": "Trim", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to trim the value to remove leading and trailing whitespaces and line breaks" }
}
}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/Builder.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/Builder.java
index 042812ab99c..1b0ffec14c8 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/Builder.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/Builder.java
@@ -28,8 +28,8 @@ import org.apache.camel.model.language.JsonPathExpression;
import org.apache.camel.model.language.LanguageExpression;
import org.apache.camel.model.language.MethodCallExpression;
import org.apache.camel.model.language.SimpleExpression;
-import org.apache.camel.model.language.WasmExpression;
import org.apache.camel.model.language.VariableExpression;
+import org.apache.camel.model.language.WasmExpression;
import org.apache.camel.util.ObjectHelper;
/**
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/DataFormatClause.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/DataFormatClause.java
index 63f314a77b9..4855d3502ff 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/DataFormatClause.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/DataFormatClause.java
@@ -186,8 +186,9 @@ public class DataFormatClause<T extends ProcessorDefinition<?>> {
/**
* Uses the beanio data format
*/
- public T beanio(String mapping, String streamName, String encoding, boolean ignoreUnidentifiedRecords,
- boolean ignoreUnexpectedRecords, boolean ignoreInvalidRecords) {
+ public T beanio(
+ String mapping, String streamName, String encoding, boolean ignoreUnidentifiedRecords,
+ boolean ignoreUnexpectedRecords, boolean ignoreInvalidRecords) {
BeanioDataFormat dataFormat = new BeanioDataFormat();
dataFormat.setMapping(mapping);
dataFormat.setStreamName(streamName);
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
index 1efd4b30997..fd3e07ad584 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
@@ -44,8 +44,8 @@ import org.apache.camel.model.language.RefExpression;
import org.apache.camel.model.language.SimpleExpression;
import org.apache.camel.model.language.SpELExpression;
import org.apache.camel.model.language.TokenizerExpression;
-import org.apache.camel.model.language.WasmExpression;
import org.apache.camel.model.language.VariableExpression;
+import org.apache.camel.model.language.WasmExpression;
import org.apache.camel.model.language.XMLTokenizerExpression;
import org.apache.camel.model.language.XPathExpression;
import org.apache.camel.model.language.XQueryExpression;
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/LanguageBuilderFactory.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/LanguageBuilderFactory.java
index 4b225993b8a..d3cd60dc6cd 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/LanguageBuilderFactory.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/LanguageBuilderFactory.java
@@ -37,8 +37,8 @@ import org.apache.camel.model.language.RefExpression;
import org.apache.camel.model.language.SimpleExpression;
import org.apache.camel.model.language.SpELExpression;
import org.apache.camel.model.language.TokenizerExpression;
-import org.apache.camel.model.language.WasmExpression;
import org.apache.camel.model.language.VariableExpression;
+import org.apache.camel.model.language.WasmExpression;
import org.apache.camel.model.language.XMLTokenizerExpression;
import org.apache.camel.model.language.XPathExpression;
import org.apache.camel.model.language.XQueryExpression;
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/BeanioDataFormat.java b/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/BeanioDataFormat.java
index 744b647454b..0b175a8b50f 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/BeanioDataFormat.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/BeanioDataFormat.java
@@ -21,6 +21,7 @@ import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlTransient;
+
import org.apache.camel.builder.DataFormatBuilder;
import org.apache.camel.model.DataFormatDefinition;
import org.apache.camel.spi.Metadata;
@@ -183,8 +184,8 @@ public class BeanioDataFormat extends DataFormatDefinition {
private String unmarshalSingleObject;
/**
- * The BeanIO mapping file. Is by default loaded from the classpath. You can prefix with file:, http:, or classpath:
- * to denote from where to load the mapping file.
+ * The BeanIO mapping file. Is by default loaded from the classpath. You can prefix with file:, http:, or
+ * classpath: to denote from where to load the mapping file.
*/
public BeanioDataFormat.Builder mapping(String mapping) {
this.mapping = mapping;
@@ -258,8 +259,8 @@ public class BeanioDataFormat extends DataFormatDefinition {
}
/**
- * To use a custom org.apache.camel.dataformat.beanio.BeanIOErrorHandler as error handler while parsing. Configure
- * the fully qualified class name of the error handler. Notice the options ignoreUnidentifiedRecords,
+ * To use a custom org.apache.camel.dataformat.beanio.BeanIOErrorHandler as error handler while parsing.
+ * Configure the fully qualified class name of the error handler. Notice the options ignoreUnidentifiedRecords,
* ignoreUnexpectedRecords, and ignoreInvalidRecords may not be in use when you use a custom error handler.
*/
public BeanioDataFormat.Builder beanReaderErrorHandlerType(String beanReaderErrorHandlerType) {
@@ -293,4 +294,4 @@ public class BeanioDataFormat extends DataFormatDefinition {
}
}
-}
\ No newline at end of file
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/SingleInputTypedExpressionDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/SingleInputTypedExpressionDefinition.java
index 8f4e30204da..148d26a6e3b 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/SingleInputTypedExpressionDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/SingleInputTypedExpressionDefinition.java
@@ -27,6 +27,8 @@ import org.apache.camel.spi.Metadata;
*/
public abstract class SingleInputTypedExpressionDefinition extends TypedExpressionDefinition {
+ @XmlAttribute
+ private String variableName;
@XmlAttribute
@Metadata(label = "advanced")
private String headerName;
@@ -47,10 +49,24 @@ public abstract class SingleInputTypedExpressionDefinition extends TypedExpressi
protected SingleInputTypedExpressionDefinition(AbstractBuilder<?, ?> builder) {
super(builder);
+ this.variableName = builder.variableName;
this.headerName = builder.headerName;
this.propertyName = builder.propertyName;
}
+ public String getVariableName() {
+ return variableName;
+ }
+
+ /**
+ * Name of variable to use as input, instead of the message body
+ * </p>
+ * It has as higher precedent if other are set.
+ */
+ public void setVariableName(String variableName) {
+ this.variableName = variableName;
+ }
+
public String getHeaderName() {
return headerName;
}
@@ -86,9 +102,20 @@ public abstract class SingleInputTypedExpressionDefinition extends TypedExpressi
T extends AbstractBuilder<T, E>, E extends SingleInputTypedExpressionDefinition>
extends TypedExpressionDefinition.AbstractBuilder<T, E> {
+ private String variableName;
private String headerName;
private String propertyName;
+ /**
+ * Name of variable to use as input, instead of the message body
+ * </p>
+ * It has as higher precedent if other are set.
+ */
+ public T variableName(String variableName) {
+ this.variableName = variableName;
+ return (T) this;
+ }
+
/**
* Name of header to use as input, instead of the message body
* </p>
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/WasmExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/WasmExpression.java
index 65c608cb5f5..f1b898477f7 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/WasmExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/WasmExpression.java
@@ -21,6 +21,7 @@ import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlTransient;
+
import org.apache.camel.spi.Metadata;
/**
@@ -42,7 +43,6 @@ public class WasmExpression extends TypedExpressionDefinition {
super(expression);
}
-
public WasmExpression(String expression, String module) {
super(expression);
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/Enricher.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/Enricher.java
index bb8350971ec..5dcabc96fac 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/Enricher.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/Enricher.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.processor;
+import java.util.Map;
+
import org.apache.camel.AggregationStrategy;
import org.apache.camel.AsyncCallback;
import org.apache.camel.CamelContext;
@@ -26,6 +28,7 @@ import org.apache.camel.ExchangePattern;
import org.apache.camel.ExchangePropertyKey;
import org.apache.camel.Expression;
import org.apache.camel.spi.EndpointUtilizationStatistics;
+import org.apache.camel.spi.HeadersMapFactory;
import org.apache.camel.spi.IdAware;
import org.apache.camel.spi.ProcessorExchangeFactory;
import org.apache.camel.spi.RouteIdAware;
@@ -63,6 +66,7 @@ public class Enricher extends AsyncProcessorSupport implements IdAware, RouteIdA
private boolean ignoreInvalidEndpoint;
private boolean allowOptimisedComponents = true;
private boolean autoStartupComponents = true;
+ private HeadersMapFactory headersMapFactory;
private ProcessorExchangeFactory processorExchangeFactory;
private SendDynamicProcessor sendDynamicProcessor;
@@ -188,9 +192,12 @@ public class Enricher extends AsyncProcessorSupport implements IdAware, RouteIdA
// if we should store the received message body in a variable,
// then we need to preserve the original message body
Object body = null;
+ Map<String, Object> headers = null;
if (variableReceive != null) {
try {
body = exchange.getMessage().getBody();
+ // do a defensive copy of the headers
+ headers = headersMapFactory.newMap(exchange.getMessage().getHeaders());
} catch (Exception throwable) {
exchange.setException(throwable);
callback.done(true);
@@ -198,6 +205,7 @@ public class Enricher extends AsyncProcessorSupport implements IdAware, RouteIdA
}
}
final Object originalBody = body;
+ final Map<String, Object> originalHeaders = headers;
return sendDynamicProcessor.process(resourceExchange, new AsyncCallback() {
@Override
@@ -216,9 +224,10 @@ public class Enricher extends AsyncProcessorSupport implements IdAware, RouteIdA
if (aggregatedExchange != null) {
if (variableReceive != null) {
// result should be stored in variable instead of message body
- Object value = aggregatedExchange.getMessage().getBody();
- ExchangeHelper.setVariable(exchange, variableReceive, value);
- aggregatedExchange.getMessage().setBody(originalBody);
+ ExchangeHelper.setVariableFromMessageBodyAndHeaders(exchange, variableReceive,
+ exchange.getMessage());
+ exchange.getMessage().setBody(originalBody);
+ exchange.getMessage().setHeaders(originalHeaders);
}
// copy aggregation result onto original exchange (preserving pattern)
copyResultsWithoutCorrelationId(exchange, aggregatedExchange);
@@ -302,6 +311,11 @@ public class Enricher extends AsyncProcessorSupport implements IdAware, RouteIdA
ServiceHelper.buildService(processorExchangeFactory, sendDynamicProcessor);
}
+ @Override
+ protected void doInit() throws Exception {
+ headersMapFactory = camelContext.getCamelContextExtension().getHeadersMapFactory();
+ }
+
@Override
protected void doStart() throws Exception {
ServiceHelper.startService(processorExchangeFactory, aggregationStrategy, sendDynamicProcessor);
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/PollEnricher.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/PollEnricher.java
index 21759c73f24..d939963dd26 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/PollEnricher.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/PollEnricher.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.processor;
+import java.util.Map;
+
import org.apache.camel.AggregationStrategy;
import org.apache.camel.AsyncCallback;
import org.apache.camel.CamelContext;
@@ -32,6 +34,7 @@ import org.apache.camel.PollingConsumer;
import org.apache.camel.spi.ConsumerCache;
import org.apache.camel.spi.EndpointUtilizationStatistics;
import org.apache.camel.spi.ExceptionHandler;
+import org.apache.camel.spi.HeadersMapFactory;
import org.apache.camel.spi.IdAware;
import org.apache.camel.spi.NormalizedEndpointUri;
import org.apache.camel.spi.RouteIdAware;
@@ -64,7 +67,8 @@ public class PollEnricher extends AsyncProcessorSupport implements IdAware, Rout
private CamelContext camelContext;
private ConsumerCache consumerCache;
- protected volatile String scheme;
+ private HeadersMapFactory headersMapFactory;
+ private volatile String scheme;
private String id;
private String routeId;
private String variableReceive;
@@ -320,9 +324,12 @@ public class PollEnricher extends AsyncProcessorSupport implements IdAware, Rout
// if we should store the received message body in a variable,
// then we need to preserve the original message body
Object originalBody = null;
+ Map<String, Object> originalHeaders = null;
if (variableReceive != null) {
try {
originalBody = exchange.getMessage().getBody();
+ // do a defensive copy of the headers
+ originalHeaders = headersMapFactory.newMap(exchange.getMessage().getHeaders());
} catch (Exception throwable) {
exchange.setException(throwable);
callback.done(true);
@@ -345,9 +352,9 @@ public class PollEnricher extends AsyncProcessorSupport implements IdAware, Rout
if (aggregatedExchange != null) {
if (variableReceive != null) {
// result should be stored in variable instead of message body
- Object value = aggregatedExchange.getMessage().getBody();
- ExchangeHelper.setVariable(exchange, variableReceive, value);
- aggregatedExchange.getMessage().setBody(originalBody);
+ ExchangeHelper.setVariableFromMessageBodyAndHeaders(exchange, variableReceive, exchange.getMessage());
+ exchange.getMessage().setBody(originalBody);
+ exchange.getMessage().setHeaders(originalHeaders);
}
// copy aggregation result onto original exchange (preserving pattern)
copyResultsPreservePattern(exchange, aggregatedExchange);
@@ -485,6 +492,8 @@ public class PollEnricher extends AsyncProcessorSupport implements IdAware, Rout
scheme = ExchangeHelper.resolveScheme(u);
}
+ headersMapFactory = camelContext.getCamelContextExtension().getHeadersMapFactory();
+
ServiceHelper.initService(consumerCache, aggregationStrategy);
}
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendDynamicProcessor.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendDynamicProcessor.java
index 13620cc6ce6..d877f180684 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendDynamicProcessor.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendDynamicProcessor.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.processor;
+import java.util.Map;
+
import org.apache.camel.AsyncCallback;
import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
@@ -29,6 +31,7 @@ import org.apache.camel.NoTypeConversionAvailableException;
import org.apache.camel.Processor;
import org.apache.camel.ResolveEndpointFailedException;
import org.apache.camel.spi.EndpointUtilizationStatistics;
+import org.apache.camel.spi.HeadersMapFactory;
import org.apache.camel.spi.IdAware;
import org.apache.camel.spi.NormalizedEndpointUri;
import org.apache.camel.spi.ProducerCache;
@@ -62,6 +65,7 @@ public class SendDynamicProcessor extends AsyncProcessorSupport implements IdAwa
protected String variableReceive;
protected ExchangePattern pattern;
protected ProducerCache producerCache;
+ protected HeadersMapFactory headersMapFactory;
protected String id;
protected String routeId;
protected boolean ignoreInvalidEndpoint;
@@ -101,8 +105,6 @@ public class SendDynamicProcessor extends AsyncProcessorSupport implements IdAwa
@Override
public boolean process(Exchange exchange, final AsyncCallback callback) {
- // TODO: variables
-
if (!isStarted()) {
exchange.setException(new IllegalStateException("SendProcessor has not been started: " + this));
callback.done(true);
@@ -179,9 +181,12 @@ public class SendDynamicProcessor extends AsyncProcessorSupport implements IdAwa
// if we should store the received message body in a variable,
// then we need to preserve the original message body
Object body = null;
+ Map<String, Object> headers = null;
if (variableReceive != null) {
try {
body = exchange.getMessage().getBody();
+ // do a defensive copy of the headers
+ headers = headersMapFactory.newMap(exchange.getMessage().getHeaders());
} catch (Exception throwable) {
exchange.setException(throwable);
callback.done(true);
@@ -189,6 +194,7 @@ public class SendDynamicProcessor extends AsyncProcessorSupport implements IdAwa
}
}
final Object originalBody = body;
+ final Map<String, Object> originalHeaders = headers;
// send the exchange to the destination using the producer cache
final Processor preProcessor = preAwareProcessor;
@@ -204,7 +210,6 @@ public class SendDynamicProcessor extends AsyncProcessorSupport implements IdAwa
}
// replace message body with variable
if (variableSend != null) {
- // it may be a global variable
Object value = ExchangeHelper.getVariable(exchange, variableSend);
exchange.getMessage().setBody(value);
}
@@ -217,30 +222,28 @@ public class SendDynamicProcessor extends AsyncProcessorSupport implements IdAwa
}
LOG.debug(">>>> {} {}", endpoint, e);
- return p.process(target, new AsyncCallback() {
- public void done(boolean doneSync) {
- // restore previous MEP
- target.setPattern(existingPattern);
- try {
- if (postProcessor != null) {
- postProcessor.process(target);
- }
- } catch (Exception e) {
- target.setException(e);
- }
- // stop endpoint if prototype as it was only used once
- if (stopEndpoint) {
- ServiceHelper.stopAndShutdownService(endpoint);
- }
- // result should be stored in variable instead of message body
- if (variableReceive != null) {
- Object value = exchange.getMessage().getBody();
- ExchangeHelper.setVariable(exchange, variableReceive, value);
- exchange.getMessage().setBody(originalBody);
+ return p.process(target, doneSync -> {
+ // restore previous MEP
+ target.setPattern(existingPattern);
+ try {
+ if (postProcessor != null) {
+ postProcessor.process(target);
}
- // signal we are done
- c.done(doneSync);
+ } catch (Exception e1) {
+ target.setException(e1);
+ }
+ // stop endpoint if prototype as it was only used once
+ if (stopEndpoint) {
+ ServiceHelper.stopAndShutdownService(endpoint);
}
+ // result should be stored in variable instead of message body
+ if (variableReceive != null) {
+ ExchangeHelper.setVariableFromMessageBodyAndHeaders(exchange, variableReceive, exchange.getMessage());
+ exchange.getMessage().setBody(originalBody);
+ exchange.getMessage().setHeaders(originalHeaders);
+ }
+ // signal we are done
+ c.done(doneSync);
});
});
}
@@ -379,6 +382,8 @@ public class SendDynamicProcessor extends AsyncProcessorSupport implements IdAwa
}
}
ServiceHelper.initService(dynamicAware);
+
+ headersMapFactory = camelContext.getCamelContextExtension().getHeadersMapFactory();
}
@Override
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendProcessor.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendProcessor.java
index 960450d8d44..b04e75a88fb 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendProcessor.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendProcessor.java
@@ -16,6 +16,7 @@
*/
package org.apache.camel.processor;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.camel.AsyncCallback;
@@ -27,6 +28,7 @@ import org.apache.camel.Exchange;
import org.apache.camel.ExchangePattern;
import org.apache.camel.ExchangePropertyKey;
import org.apache.camel.Traceable;
+import org.apache.camel.spi.HeadersMapFactory;
import org.apache.camel.spi.IdAware;
import org.apache.camel.spi.ProducerCache;
import org.apache.camel.spi.RouteIdAware;
@@ -56,6 +58,7 @@ public class SendProcessor extends AsyncProcessorSupport implements Traceable, E
protected final ExchangePattern pattern;
protected ProducerCache producerCache;
protected AsyncProducer producer;
+ protected HeadersMapFactory headersMapFactory;
protected final Endpoint destination;
protected String variableSend;
protected String variableReceive;
@@ -128,12 +131,14 @@ public class SendProcessor extends AsyncProcessorSupport implements Traceable, E
// if you want to permanently to change the MEP then use .setExchangePattern in the DSL
final ExchangePattern existingPattern = exchange.getPattern();
- // if we should store the received message body in a variable,
- // then we need to preserve the original message body
+ // when using variables then we need to remember original data
Object body = null;
- if (variableReceive != null) {
+ Map<String, Object> headers = null;
+ if (variableSend != null || variableReceive != null) {
try {
body = exchange.getMessage().getBody();
+ // do a defensive copy of the headers
+ headers = headersMapFactory.newMap(exchange.getMessage().getHeaders());
} catch (Exception throwable) {
exchange.setException(throwable);
callback.done(true);
@@ -141,6 +146,7 @@ public class SendProcessor extends AsyncProcessorSupport implements Traceable, E
}
}
final Object originalBody = body;
+ final Map<String, Object> originalHeaders = headers;
if (extendedStatistics) {
counter.incrementAndGet();
@@ -172,11 +178,12 @@ public class SendProcessor extends AsyncProcessorSupport implements Traceable, E
if (newCallback) {
ac = doneSync -> {
try {
- // result should be stored in variable instead of message body
+ // result should be stored in variable instead of message body/headers
if (variableReceive != null) {
- Object value = exchange.getMessage().getBody();
- ExchangeHelper.setVariable(exchange, variableReceive, value);
+ ExchangeHelper.setVariableFromMessageBodyAndHeaders(exchange, variableReceive,
+ exchange.getMessage());
exchange.getMessage().setBody(originalBody);
+ exchange.getMessage().setHeaders(originalHeaders);
}
// restore previous MEP
target.setPattern(existingPattern);
@@ -193,9 +200,10 @@ public class SendProcessor extends AsyncProcessorSupport implements Traceable, E
try {
// replace message body with variable
if (variableSend != null) {
- // it may be a global variable
Object value = ExchangeHelper.getVariable(exchange, variableSend);
exchange.getMessage().setBody(value);
+ // TODO: empty headers or
+
}
LOG.debug(">>>> {} {}", destination, exchange);
@@ -220,7 +228,6 @@ public class SendProcessor extends AsyncProcessorSupport implements Traceable, E
// replace message body with variable
if (variableSend != null) {
- // it may be a global variable
Object value = ExchangeHelper.getVariable(exchange, variableSend);
exchange.getMessage().setBody(value);
}
@@ -232,11 +239,12 @@ public class SendProcessor extends AsyncProcessorSupport implements Traceable, E
(producer, ex, cb) -> producer.process(ex, doneSync -> {
// restore previous MEP
exchange.setPattern(existingPattern);
- // result should be stored in variable instead of message body
+ // result should be stored in variable instead of message body/headers
if (variableReceive != null) {
- Object value = exchange.getMessage().getBody();
- ExchangeHelper.setVariable(exchange, variableReceive, value);
+ ExchangeHelper.setVariableFromMessageBodyAndHeaders(exchange, variableReceive,
+ exchange.getMessage());
exchange.getMessage().setBody(originalBody);
+ exchange.getMessage().setHeaders(originalHeaders);
}
// signal we are done
cb.done(doneSync);
@@ -292,6 +300,8 @@ public class SendProcessor extends AsyncProcessorSupport implements Traceable, E
producerCache = new DefaultProducerCache(this, camelContext, 0);
// do not add as service as we do not want to manage the producer cache
}
+
+ headersMapFactory = camelContext.getCamelContextExtension().getHeadersMapFactory();
}
@Override
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java
index d53870207a7..31a92c2582e 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java
@@ -422,7 +422,7 @@ public class RouteReifier extends ProcessorReifier<RouteDefinition> {
}
/**
- * Advice for copying the message body into a variable
+ * Advice for moving message body into a variable when using variableReceive mode
*/
private static class VariableAdvice implements CamelInternalProcessorAdvice<Object> {
@@ -434,8 +434,9 @@ public class RouteReifier extends ProcessorReifier<RouteDefinition> {
@Override
public Object before(Exchange exchange) throws Exception {
- Object body = exchange.getMessage().getBody();
- ExchangeHelper.setVariable(exchange, name, body);
+ // move body to variable
+ ExchangeHelper.setVariableFromMessageBodyAndHeaders(exchange, name, exchange.getMessage());
+ exchange.getMessage().setBody(null);
return null;
}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/dataformat/BeanioDataFormatReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/dataformat/BeanioDataFormatReifier.java
index 1e49560407a..bd9708e3612 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/dataformat/BeanioDataFormatReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/dataformat/BeanioDataFormatReifier.java
@@ -16,12 +16,12 @@
*/
package org.apache.camel.reifier.dataformat;
+import java.util.Map;
+
import org.apache.camel.CamelContext;
import org.apache.camel.model.DataFormatDefinition;
import org.apache.camel.model.dataformat.BeanioDataFormat;
-import java.util.Map;
-
public class BeanioDataFormatReifier extends DataFormatReifier<BeanioDataFormat> {
public BeanioDataFormatReifier(CamelContext camelContext, DataFormatDefinition definition) {
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/JsonPathExpressionReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/JsonPathExpressionReifier.java
index 71e3562bb8b..270c7364273 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/JsonPathExpressionReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/JsonPathExpressionReifier.java
@@ -28,7 +28,7 @@ public class JsonPathExpressionReifier extends SingleInputTypedExpressionReifier
@Override
protected Object[] createProperties() {
- Object[] properties = new Object[9];
+ Object[] properties = new Object[10];
properties[0] = definition.getResultType();
properties[1] = parseBoolean(definition.getSuppressExceptions());
properties[2] = parseBoolean(definition.getAllowSimple());
@@ -38,6 +38,7 @@ public class JsonPathExpressionReifier extends SingleInputTypedExpressionReifier
properties[6] = parseString(definition.getHeaderName());
properties[7] = parseString(definition.getOption());
properties[8] = parseString(definition.getPropertyName());
+ properties[9] = parseString(definition.getVariableName());
return properties;
}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/SingleInputTypedExpressionReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/SingleInputTypedExpressionReifier.java
index 3eab302ec6b..623d774a473 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/SingleInputTypedExpressionReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/SingleInputTypedExpressionReifier.java
@@ -35,10 +35,11 @@ class SingleInputTypedExpressionReifier<T extends SingleInputTypedExpressionDefi
@Override
protected Object[] createProperties() {
- Object[] properties = new Object[3];
+ Object[] properties = new Object[4];
properties[0] = definition.getResultType();
- properties[1] = parseString(definition.getHeaderName());
- properties[2] = parseString(definition.getPropertyName());
+ properties[1] = parseString(definition.getVariableName());
+ properties[2] = parseString(definition.getHeaderName());
+ properties[3] = parseString(definition.getPropertyName());
return properties;
}
}
diff --git a/core/camel-core/src/test/java/org/apache/camel/language/VariableTest.java b/core/camel-core/src/test/java/org/apache/camel/language/VariableTest.java
index 95486d2a77d..8a0de284b32 100644
--- a/core/camel-core/src/test/java/org/apache/camel/language/VariableTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/language/VariableTest.java
@@ -16,10 +16,15 @@
*/
package org.apache.camel.language;
+import java.util.Map;
+
import org.apache.camel.LanguageTestSupport;
import org.apache.camel.language.variable.VariableLanguage;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class VariableTest extends LanguageTestSupport {
@@ -39,6 +44,27 @@ public class VariableTest extends LanguageTestSupport {
assertPredicate("varLocal", false);
}
+ @Test
+ public void testVariableHeaders() throws Exception {
+ exchange.setVariable("header:myKey.foo", "abc");
+ exchange.setVariable("header:myKey.bar", 123);
+ exchange.setVariable("myOtherKey", "Hello Again");
+
+ assertEquals("abc", exchange.getVariable("header:myKey.foo"));
+ assertEquals(123, exchange.getVariable("header:myKey.bar"));
+
+ Map map = exchange.getVariable("header:myKey", Map.class);
+ assertNotNull(map);
+ assertEquals(2, map.size());
+ assertEquals("abc", map.get("foo"));
+ assertEquals(123, map.get("bar"));
+ }
+
+ @Test
+ public void testInvalidHeaderKey() {
+ Assertions.assertThrows(IllegalArgumentException.class, () -> exchange.getVariable("header:"));
+ }
+
@Test
public void testSingleton() {
VariableLanguage prop = new VariableLanguage();
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 7d3dd1f7bb3..fdcf759ffd7 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
@@ -2328,6 +2328,15 @@ public class SimpleTest extends LanguageTestSupport {
assertThrows(IllegalArgumentException.class, () -> evaluateExpression("${empty(unknownType)}", null));
}
+ @Test
+ public void testPretty() {
+ assertExpression(exchange, "${pretty('Hello')}", "Hello");
+ assertExpression(exchange, "${pretty(${body})}", "<hello id=\"m123\">\n</hello>");
+
+ exchange.getMessage().setBody("{\"name\": \"Jack\", \"id\": 123}");
+ assertExpression(exchange, "${pretty(${body})}", "{\n\t\"name\": \"Jack\",\n\t\"id\": 123\n}\n");
+ }
+
private void assertExpressionCreateNewEmpty(
String type, Class<?> expectedClass, java.util.function.Predicate<Object> isEmptyAssertion) {
Object value = evaluateExpression("${empty(%s)}".formatted(type), null);
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/EnrichVariableHeadersTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/EnrichVariableHeadersTest.java
new file mode 100644
index 00000000000..229e5c86d4e
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/EnrichVariableHeadersTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+
+public class EnrichVariableHeadersTest extends ContextTestSupport {
+
+ @Test
+ public void testSend() throws Exception {
+ getMockEndpoint("mock:before").expectedBodiesReceived("World");
+ getMockEndpoint("mock:before").expectedVariableReceived("hello", "Camel");
+ getMockEndpoint("mock:result").expectedBodiesReceived("Bye Camel");
+ getMockEndpoint("mock:result").expectedVariableReceived("hello", "Camel");
+ getMockEndpoint("mock:result").message(0).header("echo").isEqualTo("CamelCamel");
+
+ template.sendBody("direct:send", "World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testReceive() throws Exception {
+ getMockEndpoint("mock:after").expectedBodiesReceived("World");
+ getMockEndpoint("mock:after").expectedVariableReceived("bye", "Bye World");
+ getMockEndpoint("mock:after").message(0).header("echo").isNull();
+ getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+ getMockEndpoint("mock:result").expectedVariableReceived("bye", "Bye World");
+ getMockEndpoint("mock:result").message(0).header("echo").isNull();
+
+ template.sendBody("direct:receive", "World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testSendAndReceive() throws Exception {
+ getMockEndpoint("mock:before").expectedBodiesReceived("World");
+ getMockEndpoint("mock:before").expectedVariableReceived("hello", "Camel");
+ getMockEndpoint("mock:result").expectedBodiesReceived("World");
+ getMockEndpoint("mock:result").expectedVariableReceived("bye", "Bye Camel");
+ getMockEndpoint("mock:result").message(0).header("echo").isNull();
+
+ template.sendBody("direct:sendAndReceive", "World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:send")
+ .setVariable("hello", simple("Camel"))
+ .to("mock:before")
+ .enrich().constant("direct:foo").variableSend("hello")
+ .to("mock:result");
+
+ from("direct:receive")
+ .enrich().constant("direct:foo").variableReceive("bye")
+ .to("mock:after")
+ .setBody(simple("${variable:bye}"))
+ .to("mock:result");
+
+ from("direct:sendAndReceive")
+ .setVariable("hello", simple("Camel"))
+ .to("mock:before")
+ .enrich().constant("direct:foo").variableSend("hello").variableReceive("bye")
+ .to("mock:result");
+
+ from("direct:foo")
+ .setHeader("echo", simple("${body}${body}"))
+ .transform().simple("Bye ${body}");
+ }
+ };
+ }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/FromVariableTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/FromVariableTest.java
index 3dfc5800ee8..1d06aeabecb 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/FromVariableTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/FromVariableTest.java
@@ -16,15 +16,18 @@
*/
package org.apache.camel.processor;
+import java.util.Map;
+
import org.apache.camel.ContextTestSupport;
import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class FromVariableTest extends ContextTestSupport {
@Test
public void testOriginalBody() throws Exception {
- getMockEndpoint("mock:foo").expectedBodiesReceived("Bye World");
+ getMockEndpoint("mock:foo").expectedBodiesReceived("Bye ");
getMockEndpoint("mock:result").expectedBodiesReceived("World");
template.sendBody("direct:start", "World");
@@ -32,12 +35,33 @@ public class FromVariableTest extends ContextTestSupport {
assertMockEndpointsSatisfied();
}
+ @Test
+ public void testOriginalHeaders() throws Exception {
+ getMockEndpoint("mock:foo").expectedBodiesReceived("Bye ");
+ getMockEndpoint("mock:foo").expectedHeaderReceived("foo", 456);
+ getMockEndpoint("mock:foo").whenAnyExchangeReceived(e -> {
+ Map m = e.getVariable("header:myKey", Map.class);
+ Assertions.assertNotNull(m);
+ Assertions.assertEquals(1, m.size());
+ Assertions.assertEquals(123, m.get("foo"));
+ });
+
+ getMockEndpoint("mock:result").expectedBodiesReceived("World");
+ getMockEndpoint("mock:result").expectedHeaderReceived("foo", 456);
+
+ template.sendBodyAndHeader("direct:start", "World", "foo", 123);
+
+ assertMockEndpointsSatisfied();
+ }
+
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
fromV("direct:start", "myKey")
+ .setHeader("foo", constant(456))
+ .setHeader("bar", constant("Murphy"))
.transform().simple("Bye ${body}")
.to("mock:foo")
.setBody(simple("${variable:myKey}"))
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/FromVariableTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/PollEnrichVariableHeadersTest.java
similarity index 56%
copy from core/camel-core/src/test/java/org/apache/camel/processor/FromVariableTest.java
copy to core/camel-core/src/test/java/org/apache/camel/processor/PollEnrichVariableHeadersTest.java
index 3dfc5800ee8..cadd647e286 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/FromVariableTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/PollEnrichVariableHeadersTest.java
@@ -20,14 +20,20 @@ import org.apache.camel.ContextTestSupport;
import org.apache.camel.builder.RouteBuilder;
import org.junit.jupiter.api.Test;
-public class FromVariableTest extends ContextTestSupport {
+public class PollEnrichVariableHeadersTest extends ContextTestSupport {
@Test
- public void testOriginalBody() throws Exception {
- getMockEndpoint("mock:foo").expectedBodiesReceived("Bye World");
- getMockEndpoint("mock:result").expectedBodiesReceived("World");
+ public void testReceive() throws Exception {
+ template.sendBodyAndHeader("seda:foo", "Bye World", "echo", "CamelCamel");
- template.sendBody("direct:start", "World");
+ getMockEndpoint("mock:after").expectedBodiesReceived("World");
+ getMockEndpoint("mock:after").expectedVariableReceived("bye", "Bye World");
+ getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+ getMockEndpoint("mock:result").expectedVariableReceived("bye", "Bye World");
+ getMockEndpoint("mock:result").expectedVariableReceived("header:bye.echo", "CamelCamel");
+ getMockEndpoint("mock:result").message(0).header("echo").isNull();
+
+ template.sendBody("direct:receive", "World");
assertMockEndpointsSatisfied();
}
@@ -37,10 +43,10 @@ public class FromVariableTest extends ContextTestSupport {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
- fromV("direct:start", "myKey")
- .transform().simple("Bye ${body}")
- .to("mock:foo")
- .setBody(simple("${variable:myKey}"))
+ from("direct:receive")
+ .pollEnrich().constant("seda:foo").timeout(1000).variableReceive("bye")
+ .to("mock:after")
+ .setBody(simple("${variable:bye}"))
.to("mock:result");
}
};
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/ToDynamicVariableHeadersTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/ToDynamicVariableHeadersTest.java
new file mode 100644
index 00000000000..12e4c1cafc4
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/ToDynamicVariableHeadersTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+
+public class ToDynamicVariableHeadersTest extends ContextTestSupport {
+
+ @Test
+ public void testSend() throws Exception {
+ getMockEndpoint("mock:before").expectedBodiesReceived("World");
+ getMockEndpoint("mock:before").expectedVariableReceived("hello", "Camel");
+ getMockEndpoint("mock:result").expectedBodiesReceived("Bye Camel");
+ getMockEndpoint("mock:result").expectedVariableReceived("hello", "Camel");
+ getMockEndpoint("mock:result").message(0).header("echo").isEqualTo("CamelCamel");
+
+ template.sendBodyAndHeader("direct:send", "World", "where", "foo");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testReceive() throws Exception {
+ getMockEndpoint("mock:after").expectedBodiesReceived("World");
+ getMockEndpoint("mock:after").expectedVariableReceived("bye", "Bye World");
+ getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+ getMockEndpoint("mock:result").expectedVariableReceived("bye", "Bye World");
+ getMockEndpoint("mock:result").message(0).header("echo").isNull();
+
+ template.sendBodyAndHeader("direct:receive", "World", "where", "foo");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testSendAndReceive() throws Exception {
+ getMockEndpoint("mock:before").expectedBodiesReceived("World");
+ getMockEndpoint("mock:before").expectedVariableReceived("hello", "Camel");
+ getMockEndpoint("mock:result").expectedBodiesReceived("World");
+ getMockEndpoint("mock:result").expectedVariableReceived("bye", "Bye Camel");
+ getMockEndpoint("mock:result").message(0).header("echo").isNull();
+
+ template.sendBodyAndHeader("direct:sendAndReceive", "World", "where", "foo");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:send")
+ .setVariable("hello", simple("Camel"))
+ .to("mock:before")
+ .toD("direct:${header.where}", "hello", null)
+ .to("mock:result");
+
+ from("direct:receive")
+ .toD("direct:${header.where}", null, "bye")
+ .to("mock:after")
+ .setBody(simple("${variable:bye}"))
+ .to("mock:result");
+
+ from("direct:sendAndReceive")
+ .setVariable("hello", simple("Camel"))
+ .to("mock:before")
+ .toD("direct:${header.where}", "hello", "bye")
+ .to("mock:result");
+
+ from("direct:foo")
+ .setHeader("echo", simple("${body}${body}"))
+ .transform().simple("Bye ${body}");
+ }
+ };
+ }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/ToVariableHeadersTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/ToVariableHeadersTest.java
new file mode 100644
index 00000000000..dbadd6732e7
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/ToVariableHeadersTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+
+public class ToVariableHeadersTest extends ContextTestSupport {
+
+ @Test
+ public void testSend() throws Exception {
+ getMockEndpoint("mock:before").expectedBodiesReceived("World");
+ getMockEndpoint("mock:before").expectedVariableReceived("hello", "Camel");
+ getMockEndpoint("mock:result").expectedBodiesReceived("Bye Camel");
+ getMockEndpoint("mock:result").expectedVariableReceived("hello", "Camel");
+ getMockEndpoint("mock:result").message(0).header("echo").isEqualTo("CamelCamel");
+
+ template.sendBody("direct:send", "World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testReceive() throws Exception {
+ getMockEndpoint("mock:after").expectedBodiesReceived("World");
+ getMockEndpoint("mock:after").expectedVariableReceived("bye", "Bye World");
+ getMockEndpoint("mock:after").message(0).header("echo").isNull();
+ getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+ getMockEndpoint("mock:result").expectedVariableReceived("bye", "Bye World");
+ getMockEndpoint("mock:result").message(0).header("echo").isNull();
+
+ template.sendBody("direct:receive", "World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testSendAndReceive() throws Exception {
+ getMockEndpoint("mock:before").expectedBodiesReceived("World");
+ getMockEndpoint("mock:before").expectedVariableReceived("hello", "Camel");
+ getMockEndpoint("mock:result").expectedBodiesReceived("World");
+ getMockEndpoint("mock:result").expectedVariableReceived("bye", "Bye Camel");
+ getMockEndpoint("mock:result").message(0).header("echo").isNull();
+
+ template.sendBody("direct:sendAndReceive", "World");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:send")
+ .setVariable("hello", simple("Camel"))
+ .to("mock:before")
+ .toV("direct:foo", "hello", null)
+ .to("mock:result");
+
+ from("direct:receive")
+ .toV("direct:foo", null, "bye")
+ .to("mock:after")
+ .setBody(variable("bye"))
+ .to("mock:result");
+
+ from("direct:sendAndReceive")
+ .setVariable("hello", simple("Camel"))
+ .to("mock:before")
+ .toV("direct:foo", "hello", "bye")
+ .to("mock:result");
+
+ from("direct:foo")
+ .setHeader("echo", simple("${body}${body}"))
+ .transform().simple("Bye ${body}");
+ }
+ };
+ }
+}
diff --git a/core/camel-support/src/main/java/org/apache/camel/converter/stream/CachedOutputStream.java b/core/camel-support/src/main/java/org/apache/camel/converter/stream/CachedOutputStream.java
index 865f0f2a240..49a8c9d7f0e 100644
--- a/core/camel-support/src/main/java/org/apache/camel/converter/stream/CachedOutputStream.java
+++ b/core/camel-support/src/main/java/org/apache/camel/converter/stream/CachedOutputStream.java
@@ -25,6 +25,7 @@ import org.apache.camel.Exchange;
import org.apache.camel.StreamCache;
import org.apache.camel.converter.stream.FileInputStreamCache.TempFileManager;
import org.apache.camel.spi.StreamCachingStrategy;
+import org.apache.camel.util.IOHelper;
/**
* This output stream will store the content into a File if the stream context size is exceed the THRESHOLD value. The
@@ -165,9 +166,10 @@ public class CachedOutputStream extends OutputStream {
}
// This class will close the CachedOutputStream when it is closed
- private static class WrappedInputStream extends InputStream {
+ private static class WrappedInputStream extends InputStream implements StreamCache {
private final CachedOutputStream cachedOutputStream;
private final InputStream inputStream;
+ private long pos;
WrappedInputStream(CachedOutputStream cos, InputStream is) {
cachedOutputStream = cos;
@@ -176,6 +178,7 @@ public class CachedOutputStream extends OutputStream {
@Override
public int read() throws IOException {
+ pos++;
return inputStream.read();
}
@@ -185,8 +188,37 @@ public class CachedOutputStream extends OutputStream {
}
@Override
- public synchronized void reset() throws IOException {
- inputStream.reset();
+ public synchronized void reset() {
+ try {
+ inputStream.reset();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+
+ @Override
+ public void writeTo(OutputStream os) throws IOException {
+ IOHelper.copy(this, os);
+ }
+
+ @Override
+ public StreamCache copy(Exchange exchange) throws IOException {
+ return cachedOutputStream.newStreamCache();
+ }
+
+ @Override
+ public boolean inMemory() {
+ return cachedOutputStream.inMemory;
+ }
+
+ @Override
+ public long length() {
+ return cachedOutputStream.totalLength;
+ }
+
+ @Override
+ public long position() {
+ return pos;
}
@Override
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 c1aece49c88..a0367cd5400 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
@@ -126,10 +126,9 @@ abstract class AbstractExchange implements Exchange {
if (parent.hasVariables()) {
if (this.variableRepository == null) {
- this.variableRepository = new ExchangeVariableRepository();
+ this.variableRepository = new ExchangeVariableRepository(getContext());
}
- this.variableRepository.setVariables(parent.getVariables());
-
+ this.variableRepository.copyFrom(parent.variableRepository);
}
if (parent.hasProperties()) {
this.properties = safeCopyProperties(parent.properties);
@@ -403,7 +402,7 @@ abstract class AbstractExchange implements Exchange {
@Override
public void setVariable(String name, Object value) {
if (variableRepository == null) {
- variableRepository = new ExchangeVariableRepository();
+ variableRepository = new ExchangeVariableRepository(getContext());
}
variableRepository.setVariable(name, value);
}
@@ -424,7 +423,7 @@ abstract class AbstractExchange implements Exchange {
public Map<String, Object> getVariables() {
if (variableRepository == null) {
// force creating variables
- variableRepository = new ExchangeVariableRepository();
+ variableRepository = new ExchangeVariableRepository(getContext());
}
return variableRepository.getVariables();
}
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/AbstractVariableRepository.java
similarity index 56%
copy from core/camel-support/src/main/java/org/apache/camel/support/ExchangeVariableRepository.java
copy to core/camel-support/src/main/java/org/apache/camel/support/AbstractVariableRepository.java
index 14f74be0760..ba6655b0541 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/ExchangeVariableRepository.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/AbstractVariableRepository.java
@@ -20,23 +20,32 @@ 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.CamelContext;
+import org.apache.camel.CamelContextAware;
import org.apache.camel.StreamCache;
+import org.apache.camel.StreamCacheException;
import org.apache.camel.spi.BrowsableVariableRepository;
-import org.apache.camel.spi.VariableRepository;
+import org.apache.camel.spi.StreamCachingStrategy;
import org.apache.camel.support.service.ServiceSupport;
/**
- * {@link VariableRepository} which is local per {@link Exchange} to hold request-scoped variables.
+ * Base class for {@link org.apache.camel.spi.VariableRepository} implementations that store variables in memory.
*/
-class ExchangeVariableRepository extends ServiceSupport implements BrowsableVariableRepository, NonManagedService {
+public abstract class AbstractVariableRepository extends ServiceSupport
+ implements BrowsableVariableRepository, CamelContextAware {
private final Map<String, Object> variables = new ConcurrentHashMap<>(8);
+ private CamelContext camelContext;
+ private StreamCachingStrategy strategy;
@Override
- public String getId() {
- return "exchange";
+ public CamelContext getCamelContext() {
+ return camelContext;
+ }
+
+ @Override
+ public void setCamelContext(CamelContext camelContext) {
+ this.camelContext = camelContext;
}
@Override
@@ -51,6 +60,12 @@ class ExchangeVariableRepository extends ServiceSupport implements BrowsableVari
@Override
public void setVariable(String name, Object value) {
+ if (value != null && strategy != null) {
+ StreamCache sc = convertToStreamCache(value);
+ if (sc != null) {
+ value = sc;
+ }
+ }
if (value != null) {
// avoid the NullPointException
variables.put(name, value);
@@ -91,4 +106,36 @@ class ExchangeVariableRepository extends ServiceSupport implements BrowsableVari
}
return variables.remove(name);
}
+
+ @Override
+ protected void doInit() throws Exception {
+ super.doInit();
+
+ if (camelContext != null && camelContext.isStreamCaching()) {
+ strategy = camelContext.getStreamCachingStrategy();
+ }
+ }
+
+ protected StreamCache convertToStreamCache(Object body) {
+ // check if body is already cached
+ if (body == null) {
+ return null;
+ } else if (body instanceof StreamCache) {
+ StreamCache sc = (StreamCache) body;
+ // reset so the cache is ready to be used before processing
+ sc.reset();
+ return sc;
+ }
+ return tryStreamCache(body);
+ }
+
+ protected StreamCache tryStreamCache(Object body) {
+ try {
+ // cache the body and if we could do that replace it as the new body
+ return strategy.cache(body);
+ } catch (Exception e) {
+ throw new StreamCacheException(body, e);
+ }
+ }
+
}
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 d55f4e1ce57..7dd9f30b93e 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
@@ -47,6 +47,7 @@ import org.apache.camel.NoTypeConversionAvailableException;
import org.apache.camel.Route;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.TypeConversionException;
+import org.apache.camel.VariableAware;
import org.apache.camel.WrappedFile;
import org.apache.camel.spi.NormalizedEndpointUri;
import org.apache.camel.spi.UnitOfWork;
@@ -1085,20 +1086,59 @@ public final class ExchangeHelper {
* @param value the value of the variable
*/
public static void setVariable(Exchange exchange, String name, Object value) {
+ VariableRepository repo = null;
String id = StringHelper.before(name, ":");
+ // header and exchange is reserved
+ if ("header".equals(id) || "exchange".equals(id)) {
+ id = null;
+ }
if (id != null) {
VariableRepositoryFactory factory
= exchange.getContext().getCamelContextExtension().getContextPlugin(VariableRepositoryFactory.class);
- VariableRepository repo = factory.getVariableRepository(id);
+ repo = factory.getVariableRepository(id);
if (repo != null) {
name = StringHelper.after(name, ":");
- repo.setVariable(name, value);
} else {
- exchange.setException(
- new IllegalArgumentException("VariableRepository with id: " + id + " does not exist"));
+ throw new IllegalArgumentException("VariableRepository with id: " + id + " does not exist");
}
- } else {
- exchange.setVariable(name, value);
+ }
+ VariableAware va = repo != null ? repo : exchange;
+ va.setVariable(name, value);
+ }
+
+ /**
+ * Sets the variable from the given message body and headers
+ *
+ * @param exchange the exchange
+ * @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 the variable is set on the exchange
+ * @param message the message with the body and headers as source values
+ */
+ public static void setVariableFromMessageBodyAndHeaders(Exchange exchange, String name, Message message) {
+ VariableRepository repo = null;
+ String id = StringHelper.before(name, ":");
+ // header and exchange is reserved
+ if ("header".equals(id) || "exchange".equals(id)) {
+ id = null;
+ }
+ if (id != null) {
+ VariableRepositoryFactory factory
+ = exchange.getContext().getCamelContextExtension().getContextPlugin(VariableRepositoryFactory.class);
+ repo = factory.getVariableRepository(id);
+ if (repo == null) {
+ throw new IllegalArgumentException("VariableRepository with id: " + id + " does not exist");
+ }
+ name = StringHelper.after(name, ":");
+ }
+ VariableAware va = repo != null ? repo : exchange;
+
+ // set body and headers as variables
+ Object body = message.getBody();
+ va.setVariable(name, body);
+ for (Map.Entry<String, Object> header : message.getHeaders().entrySet()) {
+ String key = "header:" + name + "." + header.getKey();
+ Object value = header.getValue();
+ va.setVariable(key, value);
}
}
@@ -1111,22 +1151,24 @@ public final class ExchangeHelper {
* @return the variable
*/
public static Object getVariable(Exchange exchange, String name) {
- Object answer;
+ VariableRepository repo = null;
String id = StringHelper.before(name, ":");
+ // header and exchange is reserved
+ if ("header".equals(id) || "exchange".equals(id)) {
+ id = null;
+ }
if (id != null) {
VariableRepositoryFactory factory
= exchange.getContext().getCamelContextExtension().getContextPlugin(VariableRepositoryFactory.class);
- VariableRepository repo = factory.getVariableRepository(id);
+ repo = factory.getVariableRepository(id);
if (repo != null) {
name = StringHelper.after(name, ":");
- answer = repo.getVariable(name);
} else {
throw new IllegalArgumentException("VariableRepository with id: " + id + " does not exist");
}
- } else {
- answer = exchange.getVariable(name);
}
- return answer;
+ VariableAware va = repo != null ? repo : exchange;
+ return va.getVariable(name);
}
/**
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
index 14f74be0760..0e144ce3627 100644
--- 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
@@ -18,77 +18,95 @@ package org.apache.camel.support;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Stream;
+import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
-import org.apache.camel.NonManagedService;
-import org.apache.camel.StreamCache;
-import org.apache.camel.spi.BrowsableVariableRepository;
import org.apache.camel.spi.VariableRepository;
-import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.support.service.ServiceHelper;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.util.StringHelper;
/**
* {@link VariableRepository} which is local per {@link Exchange} to hold request-scoped variables.
*/
-class ExchangeVariableRepository extends ServiceSupport implements BrowsableVariableRepository, NonManagedService {
+final class ExchangeVariableRepository extends AbstractVariableRepository {
- private final Map<String, Object> variables = new ConcurrentHashMap<>(8);
+ private final Map<String, Object> headers = new ConcurrentHashMap<>(8);
- @Override
- public String getId() {
- return "exchange";
+ public ExchangeVariableRepository(CamelContext camelContext) {
+ setCamelContext(camelContext);
+ // ensure its started
+ ServiceHelper.startService(this);
+ }
+
+ void copyFrom(ExchangeVariableRepository source) {
+ setVariables(source.getVariables());
+ this.headers.putAll(source.headers);
}
@Override
public Object getVariable(String name) {
- Object answer = variables.get(name);
- if (answer instanceof StreamCache sc) {
- // reset so the cache is ready to be used as a variable
- sc.reset();
+ String id = StringHelper.before(name, ":");
+ if ("header".equals(id)) {
+ String prefix = StringHelper.after(name, ":");
+ if (prefix == null || prefix.isBlank()) {
+ throw new IllegalArgumentException("Variable " + name + " must have header key");
+ }
+ if (!prefix.contains(".")) {
+ prefix = prefix + ".";
+ // we want all headers for a given variable
+ Map<String, Object> map = new CaseInsensitiveMap();
+ for (Map.Entry<String, Object> entry : headers.entrySet()) {
+ String key = entry.getKey();
+ if (key.startsWith(prefix)) {
+ key = StringHelper.after(key, prefix);
+ map.put(key, entry.getValue());
+ }
+ }
+ return map;
+ } else {
+ return headers.get(prefix);
+ }
}
- return answer;
+ return super.getVariable(name);
}
@Override
public void setVariable(String name, Object value) {
- if (value != null) {
- // avoid the NullPointException
- variables.put(name, value);
+ String id = StringHelper.before(name, ":");
+ if ("header".equals(id)) {
+ name = StringHelper.after(name, ":");
+ if (value != null) {
+ // avoid the NullPointException
+ headers.put(name, value);
+ } else {
+ // if the value is null, we just remove the key from the map
+ headers.remove(name);
+ }
} else {
- // if the value is null, we just remove the key from the map
- variables.remove(name);
+ super.setVariable(name, value);
}
}
- 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);
+ @Override
+ public Object removeVariable(String name) {
+ String id = StringHelper.before(name, ":");
+ if ("header".equals(id)) {
+ name = StringHelper.after(name, ":");
+ return headers.remove(name);
+ }
+ return super.removeVariable(name);
}
+ @Override
public void clear() {
- variables.clear();
+ super.clear();
+ headers.clear();
}
@Override
- public Object removeVariable(String name) {
- if (!hasVariables()) {
- return null;
- }
- return variables.remove(name);
+ public String getId() {
+ return "exchange";
}
+
}
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
index 09f1e7d7270..cf7abcd1fd8 100644
--- 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
@@ -17,75 +17,17 @@
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.StreamCache;
-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<>();
+public final class GlobalVariableRepository extends AbstractVariableRepository {
@Override
public String getId() {
return "global";
}
- @Override
- public Object getVariable(String name) {
- Object answer = variables.get(name);
- if (answer instanceof StreamCache sc) {
- // reset so the cache is ready to be used as a variable
- sc.reset();
- }
- return answer;
- }
-
- @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/HeaderVariableRepository.java b/core/camel-support/src/main/java/org/apache/camel/support/HeaderVariableRepository.java
new file mode 100644
index 00000000000..21a691db9b7
--- /dev/null
+++ b/core/camel-support/src/main/java/org/apache/camel/support/HeaderVariableRepository.java
@@ -0,0 +1,68 @@
+/*
+ * 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 org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.StreamCache;
+import org.apache.camel.spi.VariableRepository;
+import org.apache.camel.support.service.ServiceHelper;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.util.StringHelper;
+
+/**
+ * {@link VariableRepository} which is local per {@link Exchange} to hold request-scoped variables for message headers.
+ */
+final class HeaderVariableRepository extends AbstractVariableRepository {
+
+ public HeaderVariableRepository(CamelContext camelContext) {
+ setCamelContext(camelContext);
+ // ensure its started
+ ServiceHelper.startService(this);
+ }
+
+ @Override
+ public String getId() {
+ return "header";
+ }
+
+ @Override
+ public Object getVariable(String name) {
+ Object answer = super.getVariable(name);
+ if (answer == null && !name.contains(".")) {
+ String prefix = name + ".";
+ // we want all headers for a given variable
+ Map<String, Object> map = new CaseInsensitiveMap();
+ for (Map.Entry<String, Object> entry : getVariables().entrySet()) {
+ String key = entry.getKey();
+ if (key.startsWith(prefix)) {
+ key = StringHelper.after(key, prefix);
+ map.put(key, entry.getValue());
+ }
+ }
+ return map;
+ }
+ if (answer instanceof StreamCache sc) {
+ // reset so the cache is ready to be used as a variable
+ sc.reset();
+ }
+ return answer;
+ }
+
+}
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/SingleInputLanguageSupport.java b/core/camel-support/src/main/java/org/apache/camel/support/SingleInputLanguageSupport.java
index 86703cea8f5..eabffb5a5a7 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/SingleInputLanguageSupport.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/SingleInputLanguageSupport.java
@@ -23,16 +23,20 @@ import org.apache.camel.spi.Language;
*/
public abstract class SingleInputLanguageSupport extends LanguageSupport {
- /**
- * Name of header to use as input, instead of the message body
- */
+ private String variableName;
private String headerName;
+ private String propertyName;
+
+ public String getVariableName() {
+ return variableName;
+ }
+
/**
- * Name of property to use as input, instead of the message body.
- * <p>
- * It has a lower precedent than the name of header if both are set.
+ * Name of variable to use as input, instead of the message body
*/
- private String propertyName;
+ public void setVariableName(String variableName) {
+ this.variableName = variableName;
+ }
public String getHeaderName() {
return headerName;
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/SingleInputTypedLanguageSupport.java b/core/camel-support/src/main/java/org/apache/camel/support/SingleInputTypedLanguageSupport.java
index 3965287b485..9e1f98a8805 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/SingleInputTypedLanguageSupport.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/SingleInputTypedLanguageSupport.java
@@ -25,16 +25,22 @@ import org.apache.camel.support.builder.ExpressionBuilder;
*/
public abstract class SingleInputTypedLanguageSupport extends TypedLanguageSupport {
- /**
- * Name of header to use as input, instead of the message body
- */
+ private String variableName;
private String headerName;
+ private String propertyName;
+
+ public String getVariableName() {
+ return variableName;
+ }
+
/**
- * Name of property to use as input, instead of the message body.
- * <p>
- * It has a lower precedent than the name of header if both are set.
+ * Name of variable to use as input, instead of the message body
+ * </p>
+ * It has as higher precedent if other are set.
*/
- private String propertyName;
+ public void setVariableName(String variableName) {
+ this.variableName = variableName;
+ }
public String getHeaderName() {
return headerName;
@@ -63,9 +69,10 @@ public abstract class SingleInputTypedLanguageSupport extends TypedLanguageSuppo
@Override
public Expression createExpression(String expression, Object[] properties) {
Class<?> type = property(Class.class, properties, 0, getResultType());
- String header = property(String.class, properties, 1, getHeaderName());
- String property = property(String.class, properties, 2, getPropertyName());
- Expression source = ExpressionBuilder.singleInputExpression(header, property);
+ String variable = property(String.class, properties, 1, getVariableName());
+ String header = property(String.class, properties, 2, getHeaderName());
+ String property = property(String.class, properties, 3, getPropertyName());
+ Expression source = ExpressionBuilder.singleInputExpression(variable, header, property);
if (type == null || type == Object.class) {
return createExpression(source, expression, properties);
}
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 12271bde384..0f3bb477721 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
@@ -53,6 +53,7 @@ import org.apache.camel.support.GroupIterator;
import org.apache.camel.support.GroupTokenIterator;
import org.apache.camel.support.LanguageHelper;
import org.apache.camel.support.LanguageSupport;
+import org.apache.camel.support.SingleInputTypedLanguageSupport;
import org.apache.camel.util.InetAddressUtil;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.StringHelper;
@@ -957,6 +958,70 @@ public class ExpressionBuilder {
};
}
+ /**
+ * Returns an expression for evaluating the expression/predicate using the given language
+ *
+ * @param expression the expression or predicate
+ * @param input input to use instead of message body
+ * @return an expression object which will evaluate the expression/predicate using the given language
+ */
+ public static Expression singleInputLanguageExpression(final String language, final String expression, final String input) {
+ return new ExpressionAdapter() {
+ private Expression expr;
+ private Predicate pred;
+
+ @Override
+ public Object evaluate(Exchange exchange) {
+ return expr.evaluate(exchange, Object.class);
+ }
+
+ @Override
+ public boolean matches(Exchange exchange) {
+ return pred.matches(exchange);
+ }
+
+ @Override
+ public void init(CamelContext context) {
+ super.init(context);
+ Language lan = context.resolveLanguage(language);
+ if (lan != null) {
+ if (input != null && lan instanceof SingleInputTypedLanguageSupport sil) {
+ String prefix = StringHelper.before(input, ":");
+ String source = StringHelper.after(input, ":");
+ if (prefix != null) {
+ prefix = prefix.trim();
+ }
+ if (source != null) {
+ source = source.trim();
+ }
+ if ("header".equals(prefix)) {
+ sil.setHeaderName(source);
+ } else if ("property".equals(prefix) || "exchangeProperty".equals(prefix)) {
+ sil.setPropertyName(source);
+ } else if ("variable".equals(prefix)) {
+ sil.setVariableName(source);
+ } else {
+ throw new IllegalArgumentException(
+ "Invalid input source for language. Should either be header:key, exchangeProperty:key, or variable:key, was: "
+ + input);
+ }
+ }
+ pred = lan.createPredicate(expression);
+ pred.init(context);
+ expr = lan.createExpression(expression);
+ expr.init(context);
+ } else {
+ throw new NoSuchLanguageException(language);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "language[" + language + ":" + expression + "]";
+ }
+ };
+ }
+
/**
* Returns the expression for the exchanges inbound message body
*/
@@ -1142,15 +1207,19 @@ public class ExpressionBuilder {
}
/**
+ * @param variableName the name of the variable from which the input data must be extracted if not empty.
* @param headerName the name of the header from which the input data must be extracted if not empty.
* @param propertyName the name of the property from which the input data must be extracted if not empty and
* {@code headerName} is empty.
- * @return a header expression if {@code headerName} is not empty, otherwise a property expression if
- * {@code propertyName} is not empty or finally a body expression.
+ * @return a variable expression if {@code variableName} is not empty, a header expression if
+ * {@code headerName} is not empty, otherwise a property expression if {@code propertyName} is
+ * not empty or finally a body expression.
*/
- public static Expression singleInputExpression(String headerName, String propertyName) {
+ public static Expression singleInputExpression(String variableName, String headerName, String propertyName) {
final Expression exp;
- if (ObjectHelper.isNotEmpty(headerName)) {
+ if (ObjectHelper.isNotEmpty(variableName)) {
+ exp = variableExpression(variableName);
+ } else if (ObjectHelper.isNotEmpty(headerName)) {
exp = headerExpression(headerName);
} else if (ObjectHelper.isNotEmpty(propertyName)) {
exp = exchangePropertyExpression(propertyName);
@@ -1163,7 +1232,6 @@ public class ExpressionBuilder {
/**
* Returns the expression for the current thread id
*/
-
public static Expression threadIdExpression() {
return new ExpressionAdapter() {
@Override
@@ -2306,6 +2374,32 @@ public class ExpressionBuilder {
};
}
+ /**
+ * Returns the expression as pretty formatted string
+ */
+ public static Expression prettyExpression(final Expression expression) {
+ return new ExpressionAdapter() {
+ @Override
+ public Object evaluate(Exchange exchange) {
+ String body = expression.evaluate(exchange, String.class);
+ if (body == null) {
+ return null;
+ } else if (body.startsWith("{") && body.endsWith("}") || body.startsWith("[") && body.endsWith("]")) {
+ return Jsoner.prettyPrint(body); //json
+ } else if (body.startsWith("<") && body.endsWith(">")) {
+ return ExpressionBuilder.prettyXml(body); //xml
+ }
+
+ return body;
+ }
+
+ @Override
+ public String toString() {
+ return "pretty(" + expression + ")";
+ }
+ };
+ }
+
/**
* Returns the expression for the message body as pretty formatted string
*/
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/processor/MarshalProcessor.java b/core/camel-support/src/main/java/org/apache/camel/support/processor/MarshalProcessor.java
index f1a299106ef..107180f753c 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/processor/MarshalProcessor.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/processor/MarshalProcessor.java
@@ -59,7 +59,6 @@ public class MarshalProcessor extends AsyncProcessorSupport implements Traceable
final Object originalBody = in.getBody();
Object body = originalBody;
if (variableSend != null) {
- // it may be a global variable
body = ExchangeHelper.getVariable(exchange, variableSend);
}
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/processor/UnmarshalProcessor.java b/core/camel-support/src/main/java/org/apache/camel/support/processor/UnmarshalProcessor.java
index dbfb9e7206c..8b93cabd473 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/processor/UnmarshalProcessor.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/processor/UnmarshalProcessor.java
@@ -68,7 +68,6 @@ public class UnmarshalProcessor extends AsyncProcessorSupport implements Traceab
final Object originalBody = in.getBody();
Object body = originalBody;
if (variableSend != null) {
- // it may be a global variable
body = ExchangeHelper.getVariable(exchange, variableSend);
}
final Message out;
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 60132d4ae6f..4ae07023836 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
@@ -2895,6 +2895,7 @@ public class ModelParser extends BaseParser {
switch (key) {
case "headerName": def.setHeaderName(val); break;
case "propertyName": def.setPropertyName(val); break;
+ case "variableName": def.setVariableName(val); break;
default: return typedExpressionDefinitionAttributeHandler().accept(def, key, val);
}
return true;
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 6399d61082a..d80ec03e463 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
@@ -4161,6 +4161,7 @@ public class ModelWriter extends BaseWriter {
throws IOException {
doWriteTypedExpressionDefinitionAttributes(def);
doWriteAttribute("headerName", def.getHeaderName());
+ doWriteAttribute("variableName", def.getVariableName());
doWriteAttribute("propertyName", def.getPropertyName());
}
protected void doWriteSingleInputTypedExpressionDefinition(
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 fdfcdce5f8b..0a61565954b 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
@@ -4161,6 +4161,7 @@ public class ModelWriter extends BaseWriter {
throws IOException {
doWriteTypedExpressionDefinitionAttributes(def);
doWriteAttribute("headerName", def.getHeaderName());
+ doWriteAttribute("variableName", def.getVariableName());
doWriteAttribute("propertyName", def.getPropertyName());
}
protected void doWriteSingleInputTypedExpressionDefinition(
diff --git a/docs/user-manual/modules/ROOT/pages/variables.adoc b/docs/user-manual/modules/ROOT/pages/variables.adoc
index 31bcc331faa..0e84edd115e 100644
--- a/docs/user-manual/modules/ROOT/pages/variables.adoc
+++ b/docs/user-manual/modules/ROOT/pages/variables.adoc
@@ -30,6 +30,8 @@ For example, you can build a custom repository that stores the variables in a da
Each repository must have its own unique id. However, it's also possible to replace the default `global` repository with another.
+IMPORTANT: The id `exchange` and `header` is reserved by Camel internally and should not be used as id for custom repositories.
+
== Getting and setting variables from Java API
To get a local variable from the current exchange, you can do this via Java API:
@@ -173,7 +175,7 @@ camel.variable.user-template = resource:file:/etc/user.json
== Using Variables with EIPs
The following commonly used EIPs for sending and receiving, and transforming messages, have
-first class support for using variables with the message body:
+special support for choosing to use variables over the current `Exchange`:
- from
- to
@@ -185,19 +187,50 @@ first class support for using variables with the message body:
- marshal
The intention is to make it more convenient and easy to _gather data_ from other systems without any ceremony to keep
-existing data by using techniques such as storing the data temporary using headers or exchange properties,
+existing data by using techniques such as storing the data temporary using headers, exchange properties,
or with the xref:components:eips:claimCheck-eip.adoc[Claim Check] EIP.
=== Important concept when using variables and EIPs
-It is **important** to understand that the variables only use the message **body** and does not have support for anything else such
-as message headers. This is on purpose to keep it simpler and only work with the message body as the user data. If you have need
-to use variables with both message body and headers, then you can use `setVariable` and `getVariable`.
+It is **important** to understand that the variables focuses the use of the message **body** only.
+This is on purpose to keep it simpler and primary work with the message body as the user data.
+
+The following table summarises what the EIP supports with variables:
+
+|===
+|*EIP* | *VariableSend* | *VariableReceive*
+| From | | yes
+| To | yes | yes
+| ToD | yes | yes
+| Enrich | yes | yes
+| PollEnrich | | yes
+| WireTap | yes |
+| Unmarshal | yes | yes
+| Marshal | yes | yes
+|===
The EIPs listed above have support for using variables when sending and receiving data. This is done by using the `variableSend` and `variableReceive` options
-to specify the name of the variable. When the EIP uses variables then the _data_ itself (i.e. message body) is only what is
-different from 'standard' Camel.
+to specify the name of the variable.
+
+The EIPs works in two modes where *variableSend* and *variableReceive* is a little bit different, so pay attention to the following table:
+
+|===
+| *VariableSend* | *VariableReceive*
+| *Sending Headers:* Message | *Received Headers:* Variable
+| *Sending Body:* Variable | *Received Body:* Variable
+|===
+The *VariableSend* is intended for sending as regular Camel where the sending headers are from the current `Message` and the body is
+from the variable. In other words it's only the message body that is taken from the variable instead of the current `Message` body.
+
+The *VariableReceive* works in a different mode. The idea is that all the received data is stored as variables. This means the current `Message`
+is not changed at all. The received body is stored in the variable, and the received headers (transport headers etc.) are stored as read-only
+headers as variables as well. The names of the variable is `header:variableName.headerName`. For example if the variable is `myVar` and the header is `Content-Type`
+then the header is stored as a variable with the full name `header:myVar.Content-Type`.
+
+=== Example using VariableReceive
+
+When the EIP is using *VariableReceive*, then the `Message` on the `Exchange` is not in use, but the body and headers will be from the variable.
For example given the following `Message` containing:
[source,properties]
@@ -207,7 +240,7 @@ header.bar=456
body=Hello World
----
-And a remote service is called via the route below, and this service returns a new header and body:
+And a remote service is called via the route below, and this service returns a new header (`level`) and body:
[tabs]
====
@@ -251,7 +284,8 @@ header.level=gold
body=Bye World
----
-However, if you use a variable (_myVar_) as the _sink_ to store the returned data from calling the remote service as shown:
+However, if you use *VariableReceive=myVar* to store the returned data from calling the remote service, into a variable, then
+the dynamics changes as follows:
[tabs]
====
@@ -287,27 +321,31 @@ from:
----
====
-Then the `Message` body is not changed, but everything else is changed as without using variables:
+Then the `Message` on the current `Exchange` is not changed:
[source,properties]
----
header.foo=123
header.bar=456
-header.level=gold
body=Hello World
----
-And the variable contains the data:
+And the variable contains all the data received from the remote HTTP service separated into two variables:
[source,properties]
----
myVar=Bye World
+header:myVar.level=gold
----
-=== Using variable to store a copy of the incoming message body
+IMPORTANT: Notice the headers are stored with the syntax `header:variable.key`. In the example above the variable name is `myVar`,
+and the header key is `level`, which gives: `header:myVar.level`.
-You can configure the `from` to store a copy of the message body into a variable. This makes it easy to have quick access
-to the original incoming message body via the variable.
+
+=== Using variable to store incoming message body
+
+You can configure the `from` to store the message body into a variable, instead of the `Message`. This makes it easy to have quick access
+to the original incoming message body via the variable. Notice that the body on the `Message` will be `null`.
The following example from a unit test shows how to do this. Notice how Java DSL uses `fromV` to make it possible to specify
the name of the variable. In XML and YAML DSL you specify this using the `variableReceive` parameter.
@@ -357,213 +395,6 @@ from:
----
====
-=== Using variables when sending and receiving messages to an endpoint
-
-You can configure the `to` to use variables for any of the following (or both) when sending and receiving:
-
-- variableSend - name of variable that contains the message body to send instead of the current message body on the `Exchange`.
-- variableReceive - name of variable that should store the returned message payload (will not change the message body on the `Exchange`).
-
-For example, you can use the `variableSend` to tell Camel to use the variable as the message body when sending to an endpoint.
-If the `variableReceive` is also configured, then the reply message will be stored in the variable instead of the `Exchange` message body.
-
-IMPORTANT: This is only the message body. Message headers keep acting as usual.
-
-In the following example, we use a variable named `hello` as the message body when sending to the `direct:foo` endpoint:
-
-[tabs]
-====
-Java::
-+
-[source,java]
-----
-from("direct:send")
- .setVariable("hello", simple("Camel"))
- .to("mock:before")
- .toV("direct:foo", "hello", null)
- .to("mock:result");
-
-from("direct:foo")
- .transform().simple("Bye ${body}");
-----
-XML::
-+
-[source,xml]
-----
-<route>
- <from uri="direct:send"/>
- <setVariable name="hello">
- <simple>Camel</simple>
- </setVariable>
- <to uri="mock:before"/>
- <to uri="direct:foo" variableSend="hello"/>
- <to uri="mock:result"/>
-</route>
-<route>
- <from uri="direct:foo"/>
- <transform>
- <simple>Bye ${body}</simple>
- </transform>
-</route>
-----
-YAML::
-+
-[source,yaml]
-----
-- route:
- from:
- uri: direct:send
- steps:
- - setVariable:
- name: hello
- simple:
- expression: Camel
- - to:
- uri: mock:before
- - to:
- uri: direct:foo
- variableSend: hello
- - to:
- uri: mock:result
-- route:
- from:
- uri: direct:foo
- steps:
- - transform:
- simple:
- expression: "Bye ${body}"
-----
-====
-
-If you only want to store the result in a variable instead of the current `Exchange` message body, then you should use `variableReceive`
-as shown in the following:
-
-[tabs]
-====
-Java::
-+
-[source,java]
-----
-from("direct:receive")
- .toV("direct:foo", null, "bye")
- .to("mock:after")
- .setBody(simple("${variable:bye}"))
- .to("mock:result");
+NOTE: In the examples above the transform `Bye $\{body}` will result as `Bye ` because the `Message` has no message body, as the incoming
+message body is stored in the variable `myKey` instead.
-from("direct:foo")
- .transform().simple("Bye ${body}");
-----
-XML::
-+
-[source,xml]
-----
-<route>
- <from uri="direct:receive"/>
- <to uri="direct:foo" variableReceive="bye"/>
- <to uri="mock:after"/>
- <setBody>
- <simple>${variable:bye}</simple>
- </setBody>
- <to uri="mock:result"/>
-</route>
-<route>
- <from uri="direct:foo"/>
- <transform>
- <simple>Bye ${body}</simple>
- </transform>
-</route>
-----
-YAML::
-+
-[source,yaml]
-----
-- route:
- from:
- uri: direct:receive
- steps:
- - to:
- uri: direct:foo
- variableReceive: bye
- - to:
- uri: mock:after
- - setBody:
- variable: bye
- - to:
- uri: mock:result
-- route:
- from:
- uri: direct:foo
- steps:
- - transform:
- simple:
- expression: "Bye ${body}"
-----
-====
-
-And you can also use both of them together which means you are using variables for both what to send, and to store the result in a variable.
-This means the current `Exchange` message body is not in use at all.
-
-[tabs]
-====
-Java::
-+
-[source,java]
-----
-from("direct:sendAndReceive")
- .setVariable("hello", simple("Camel"))
- .to("mock:before")
- .toV("direct:foo", "hello", "bye")
- .to("mock:result");
-
-from("direct:foo")
- .transform().simple("Bye ${body}");
-----
-XML::
-+
-[source,xml]
-----
-<route>
- <from uri="direct:sendAndReceive"/>
- <setVariable name="hello">
- <simple>Camel</simple>
- </setVariable>
- <to uri="mock:before"/>
- <to uri="direct:foo" variableSend="hello" variableReceive="bye"/>
- <to uri="mock:result"/>
-</route>
-<route>
- <from uri="direct:foo"/>
- <transform>
- <simple>Bye ${body}</simple>
- </transform>
-</route>
-----
-YAML::
-+
-[source,yaml]
-----
-- route:
- from:
- uri: direct:sendAndReceive
- steps:
- - setVariable:
- name: hello
- simple:
- expression: Camel
- - to:
- uri: mock:before
- - to:
- uri: direct:foo
- variableReceive: bye
- variableSend: hello
- - to:
- uri: mock:result
-- route:
- from:
- uri: direct:foo
- steps:
- - transform:
- simple:
- expression: "Bye ${body}"
-----
-====
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 2e7c0d1ff1e..5e10764e353 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
@@ -6871,7 +6871,8 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
@YamlProperty(name = "id", type = "string", description = "Sets the id of this node", displayName = "Id"),
@YamlProperty(name = "propertyName", type = "string", description = "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set.", displayName = "Property Name"),
@YamlProperty(name = "resultType", type = "string", description = "Sets the class of the result type (type from output)", displayName = "Result Type"),
- @YamlProperty(name = "trim", type = "boolean", description = "Whether to trim the value to remove leading and trailing whitespaces and line breaks", displayName = "Trim")
+ @YamlProperty(name = "trim", type = "boolean", description = "Whether to trim the value to remove leading and trailing whitespaces and line breaks", displayName = "Trim"),
+ @YamlProperty(name = "variableName", type = "string", description = "Name of variable to use as input, instead of the message body It has as higher precedent if other are set.", displayName = "Variable Name")
}
)
public static class Hl7TerserExpressionDeserializer extends YamlDeserializerBase<Hl7TerserExpression> {
@@ -6924,6 +6925,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
target.setTrim(val);
break;
}
+ case "variableName": {
+ String val = asText(node);
+ target.setVariableName(val);
+ break;
+ }
default: {
ExpressionDefinition ed = target.getExpressionType();
if (ed != null) {
@@ -7939,7 +7945,8 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
@YamlProperty(name = "id", type = "string", description = "Sets the id of this node", displayName = "Id"),
@YamlProperty(name = "propertyName", type = "string", description = "Name of property to use as input, instead of the message body. It has a lower precedent than the headerName if both are set.", displayName = "Property Name"),
@YamlProperty(name = "resultType", type = "string", description = "Sets the class of the result type (type from output)", displayName = "Result Type"),
- @YamlProperty(name = "trim", type = "boolean", description = "Whether to trim the value to remove leading and trailing whitespaces and line breaks", displayName = "Trim")
+ @YamlProperty(name = "trim", type = "boolean", description = "Whether to trim the value to remove leading and trailing whitespaces and line breaks", displayName = "Trim"),
+ @YamlProperty(name = "variableName", type = "string", description = "Name of variable to use as input, instead of the message body It has as higher precedent if other are set.", displayName = "Variable Name")
}
)
public static class JqExpressionDeserializer extends YamlDeserializerBase<JqExpression> {
@@ -7992,6 +7999,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
target.setTrim(val);
break;
}
+ case "variableName": {
+ String val = asText(node);
+ target.setVariableName(val);
+ break;
+ }
default: {
ExpressionDefinition ed = target.getExpressionType();
if (ed != null) {
@@ -8253,6 +8265,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
@YamlProperty(name = "suppressExceptions", type = "boolean", description = "Whether to suppress exceptions such as PathNotFoundException.", displayName = "Suppress Exceptions"),
@YamlProperty(name = "trim", type = "boolean", description = "Whether to trim the value to remove leading and trailing whitespaces and line breaks", displayName = "Trim"),
@YamlProperty(name = "unpackArray", type = "boolean", description = "Whether to unpack a single element json-array into an object.", displayName = "Unpack Array"),
+ @YamlProperty(name = "variableName", type = "string", description = "Name of variable to use as input, instead of the message body It has as higher precedent if other are set.", displayName = "Variable Name"),
@YamlProperty(name = "writeAsString", type = "boolean", description = "Whether to write the output of each row/element as a JSON String value instead of a Map/POJO value.", displayName = "Write As String")
}
)
@@ -8331,6 +8344,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
target.setUnpackArray(val);
break;
}
+ case "variableName": {
+ String val = asText(node);
+ target.setVariableName(val);
+ break;
+ }
case "writeAsString": {
String val = asText(node);
target.setWriteAsString(val);
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 6b37183070a..fdddfca3136 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
@@ -13063,6 +13063,11 @@
"type" : "boolean",
"title" : "Trim",
"description" : "Whether to trim the value to remove leading and trailing whitespaces and line breaks"
+ },
+ "variableName" : {
+ "type" : "string",
+ "title" : "Variable Name",
+ "description" : "Name of variable to use as input, instead of the message body It has as higher precedent if other are set."
}
}
} ],
@@ -13226,6 +13231,11 @@
"type" : "boolean",
"title" : "Trim",
"description" : "Whether to trim the value to remove leading and trailing whitespaces and line breaks"
+ },
+ "variableName" : {
+ "type" : "string",
+ "title" : "Variable Name",
+ "description" : "Name of variable to use as input, instead of the message body It has as higher precedent if other are set."
}
}
} ],
@@ -13296,6 +13306,11 @@
"title" : "Unpack Array",
"description" : "Whether to unpack a single element json-array into an object."
},
+ "variableName" : {
+ "type" : "string",
+ "title" : "Variable Name",
+ "description" : "Name of variable to use as input, instead of the message body It has as higher precedent if other are set."
+ },
"writeAsString" : {
"type" : "boolean",
"title" : "Write As String",
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/FromVariableTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/FromVariableTest.groovy
index 7316a4f874a..5112cb1a9ca 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/FromVariableTest.groovy
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/FromVariableTest.groovy
@@ -18,6 +18,7 @@ package org.apache.camel.dsl.yaml
import org.apache.camel.component.mock.MockEndpoint
import org.apache.camel.dsl.yaml.support.YamlTestSupport
+import org.junit.jupiter.api.Assertions
class FromVariableTest extends YamlTestSupport {
@@ -28,6 +29,12 @@ class FromVariableTest extends YamlTestSupport {
uri: "direct:start"
variableReceive: "myKey"
steps:
+ - setHeader:
+ name: foo
+ constant: "456"
+ - setHeader:
+ name: bar
+ constant: "Murphy"
- transform:
simple: "Bye ${body}"
- to: "mock:foo"
@@ -37,7 +44,13 @@ class FromVariableTest extends YamlTestSupport {
'''
withMock('mock:foo') {
- expectedBodiesReceived 'Bye World'
+ expectedBodiesReceived 'Bye '
+ whenAnyExchangeReceived { e -> {
+ Map m = e.getVariable("header:myKey", Map.class)
+ Assertions.assertNotNull(m)
+ Assertions.assertEquals(1, m.size())
+ Assertions.assertEquals(123, m.get("foo"))
+ }}
}
withMock('mock:result') {
expectedBodiesReceived 'World'
@@ -47,7 +60,7 @@ class FromVariableTest extends YamlTestSupport {
context.start()
withTemplate {
- to('direct:start').withBody('World').send()
+ to('direct:start').withBody('World').withHeader("foo", 123).send()
}
then: