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 711a2c8072ad CAMEL-22856: camel-core - Add substring before|after to
simple language (#20820)
711a2c8072ad is described below
commit 711a2c8072ad17429429e08a6e61aa882c81a101
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Jan 14 19:42:45 2026 +0100
CAMEL-22856: camel-core - Add substring before|after to simple language
(#20820)
* CAMEL-22856: camel-core - Add substring before|after to simple language
---
.../org/apache/camel/catalog/languages/simple.json | 54 ++++-----
.../language/csimple/joor/OriginalSimpleTest.java | 52 +++++++++
.../org/apache/camel/language/simple/simple.json | 54 ++++-----
.../modules/languages/pages/simple-language.adoc | 3 +
.../camel/language/csimple/CSimpleHelper.java | 18 +++
.../camel/language/simple/SimpleConstants.java | 6 +
.../language/simple/SimpleExpressionBuilder.java | 66 +++++++++++
.../simple/ast/SimpleFunctionExpression.java | 126 ++++++++++++++++++++-
.../apache/camel/language/simple/SimpleTest.java | 52 +++++++++
9 files changed, 378 insertions(+), 53 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
index 29debf063014..dc9b059cb0ae 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
@@ -70,31 +70,33 @@
"type:name.field": { "index": 44, "kind": "function", "displayName": "Java
Field Value", "group": "function", "label": "function", "required": false,
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "To refer to a type or
field by its classname. To refer to a field, you can append .FIELD_NAME. For
example, you can refer to the constant field from Exchange as:
`org.apache.camel.Exchange.FILE_NAME`", " [...]
"replace(from,to,exp)": { "index": 45, "kind": "function", "displayName":
"Replace String Values", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Replace all the string values in the message body\/expression. To make it
easier to replace single and double quotes, then you can use XML escaped values
`\\"` as double quote, `\\'` [...]
"substring(head,tail)": { "index": 46, "kind": "function", "displayName":
"Substring", "group": "function", "label": "function", "required": false,
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "Returns a substring of
the message body\/expression. If only one positive number, then the returned
string is clipped from the beginning. If only one negative number, then the
returned string is clipped fr [...]
- "random(min,max)": { "index": 47, "kind": "function", "displayName":
"Generate Random Number", "group": "function", "label": "function", "required":
false, "javaType": "int", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Returns a random number between min (included) and max (excluded).", "ognl":
false, "suffix": "}" },
- "skip(num)": { "index": 48, "kind": "function", "displayName": "Skip First
Items from the Message Body", "group": "function", "label": "function",
"required": false, "javaType": "java.util.Iterator", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The skip function iterates the message body and skips
the first number of items. This can be used with the Splitter EIP to split a
message body and skip the first N number of [...]
- "convertTo(exp,type)": { "index": 49, "kind": "function", "displayName":
"Convert To", "group": "function", "label": "function", "required": false,
"javaType": "", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "Converts the message body
(or expression) to the specified type.", "ognl": true, "suffix": "}" },
- "trim(exp)": { "index": 50, "kind": "function", "displayName": "Trim",
"group": "function", "label": "function", "required": false, "javaType":
"String", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The trim function trims
the message body (or expression) by removing all leading and trailing white
spaces.", "ognl": false, "suffix": "}" },
- "length(exp)": { "index": 51, "kind": "function", "displayName": "Length",
"group": "function", "label": "function", "required": false, "javaType": "int",
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The payload length (number of bytes) of the
message body (or expression).", "ognl": false, "suffix": "}" },
- "size(exp)": { "index": 52, "kind": "function", "displayName": "Size",
"group": "function", "label": "function", "required": false, "javaType": "int",
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The size of the message body (or expression).
If the payload is java.util.Collection or java.util.Map based then the size is
the number of elements; otherwise the payload size in bytes.", "ognl": false,
"suffix": "}" },
- "uppercase(exp)": { "index": 53, "kind": "function", "displayName":
"Uppercase", "group": "function", "label": "function", "required": false,
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "Uppercases the message
body (or expression)", "ognl": false, "suffix": "}" },
- "lowercase(exp)": { "index": 54, "kind": "function", "displayName":
"Lowercase", "group": "function", "label": "function", "required": false,
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "Lowercases the message
body (or expression)", "ognl": false, "suffix": "}" },
- "concat(exp,exp,separator)": { "index": 55, "kind": "function",
"displayName": "Concat", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Performs a string concat using two expressions (message body as default) with
optional separator", "ognl": false, "suffix": "}" },
- "collate(num)": { "index": 56, "kind": "function", "displayName": "Group
Message Body into Sub Lists", "group": "function", "label": "function",
"required": false, "javaType": "java.util.Iterator", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The collate function iterates the message body and
groups the data into sub lists of specified size. This can be used with the
Splitter EIP to split a message body and group\/ba [...]
- "join(separator,prefix,exp)": { "index": 57, "kind": "function",
"displayName": "Join", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
join function iterates the message body\/expression and joins the data into a
string. The separator is by default a comma. The prefix is optional. The join
uses the message body as source by default. [...]
- "messageHistory(boolean)": { "index": 58, "kind": "function",
"displayName": "Print Message History", "group": "function", "label":
"function", "required": false, "javaType": "String", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The message history of the current exchange (how it has
been routed). This is similar to the route stack-trace message history the
error handler logs in case of an unhandled exception. The b [...]
- "uuid(type)": { "index": 59, "kind": "function", "displayName": "Generate
UUID", "group": "function", "label": "function", "required": false, "javaType":
"String", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "Returns a UUID using the
Camel `UuidGenerator`. You can choose between `default`, `classic`, `short` and
`simple` as the type. If no type is given, the default is used. It is also
possible to use a custom `UuidG [...]
- "hash(exp,algorithm)": { "index": 60, "kind": "function", "displayName":
"Compute Hash Value", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Returns a hashed value (string in hex decimal) of the message body\/expression
using JDK MessageDigest. The algorithm can be SHA-256 (default) or SHA3-256.",
"ognl": false, "suffix": "}" },
- "empty(type)": { "index": 61, "kind": "function", "displayName": "Create
Empty Object", "group": "function", "label": "function", "required": false,
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "Creates a new empty
object (decided by type). Use `string` to create an empty String. Use `list` to
create an empty `java.util.ArrayList`. Use `map` to create an empty
`java.util.LinkedHashMap`.", "ognl": [...]
- "iif(predicate,trueExp,falseExp)": { "index": 62, "kind": "function",
"displayName": "If Then Else", "group": "function", "label": "function",
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Evaluates the predicate and returns the value of trueExp or falseExp. This
function is similar to the ternary operator in Java.", "ognl": false, "suffix":
"}" },
- "list(val...)": { "index": 63, "kind": "function", "displayName": "Create
List of values", "group": "function", "label": "function", "required": false,
"javaType": "java.util.ArrayList", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
list function creates an ArrayList with the given set of values.", "ognl":
false, "suffix": "}" },
- "map(key1,value1,...)": { "index": 64, "kind": "function", "displayName":
"Create Map of pairs", "group": "function", "label": "function", "required":
false, "javaType": "java.util.LinkedHashMap", "prefix": "${", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "The map function creates a LinkedHashMap with the given set of
pairs.", "ognl": false, "suffix": "}" },
- "attachments": { "index": 65, "kind": "function", "displayName":
"Attachments", "group": "function", "label": "function", "required": false,
"javaType": "java.util.Map", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "All
the attachments as a Map<String,DataHandler.", "ognl": false, "suffix": "}" },
- "attachments.size": { "index": 66, "kind": "function", "displayName":
"Attachments", "group": "function", "label": "function", "required": false,
"javaType": "int", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The number of attachments.
Is 0 if there are no attachments.", "ognl": false, "suffix": "}" },
- "attachmentContentAsText": { "index": 67, "kind": "function",
"displayName": "Attachment Content As Text", "group": "function", "label":
"function", "required": false, "javaType": "String", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment as text (ie String).",
"ognl": false, "suffix": "}" },
- "attachmentContent": { "index": 68, "kind": "function", "displayName":
"Attachment Content", "group": "function", "label": "function", "required":
false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
content of the attachment", "ognl": false, "suffix": "}" },
- "attachmentContentAs(type)": { "index": 69, "kind": "function",
"displayName": "Attachment Content As", "group": "function", "label":
"function", "required": false, "javaType": "Object", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment, converted to the given
type.", "ognl": false, "suffix": "}" },
- "attachmentHeader(key,name)": { "index": 70, "kind": "function",
"displayName": "Attachment Header", "group": "function", "label": "function",
"required": false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
attachment header with the given name.", "ognl": false, "suffix": "}" },
- "attachmentHeader(key,name,type)": { "index": 71, "kind": "function",
"displayName": "Attachment Header", "group": "function", "label": "function",
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
attachment header with the given name, converted to the given type.", "ognl":
false, "suffix": "}" },
- "attachment(key)": { "index": 72, "kind": "function", "displayName":
"Attachment", "group": "function", "label": "function", "required": false,
"javaType": "jakarta.activation.DataHandler", "prefix": "${", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "The DataHandler for the given attachment.", "ognl": true,
"suffix": "}" }
+ "substringBefore(exp,before)": { "index": 47, "kind": "function",
"displayName": "Substring Before", "group": "function", "label": "function",
"required": false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Returns a substring of the message body\/expression that comes before. Returns
null if nothing comes before.", "ognl": false, "suffix": "}" },
+ "substringAfter(exp,before)": { "index": 48, "kind": "function",
"displayName": "Substring After", "group": "function", "label": "function",
"required": false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Returns a substring of the message body\/expression that comes after. Returns
null if nothing comes after.", "ognl": false, "suffix": "}" },
+ "random(min,max)": { "index": 49, "kind": "function", "displayName":
"Generate Random Number", "group": "function", "label": "function", "required":
false, "javaType": "int", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Returns a random number between min (included) and max (excluded).", "ognl":
false, "suffix": "}" },
+ "skip(num)": { "index": 50, "kind": "function", "displayName": "Skip First
Items from the Message Body", "group": "function", "label": "function",
"required": false, "javaType": "java.util.Iterator", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The skip function iterates the message body and skips
the first number of items. This can be used with the Splitter EIP to split a
message body and skip the first N number of [...]
+ "convertTo(exp,type)": { "index": 51, "kind": "function", "displayName":
"Convert To", "group": "function", "label": "function", "required": false,
"javaType": "", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "Converts the message body
(or expression) to the specified type.", "ognl": true, "suffix": "}" },
+ "trim(exp)": { "index": 52, "kind": "function", "displayName": "Trim",
"group": "function", "label": "function", "required": false, "javaType":
"String", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The trim function trims
the message body (or expression) by removing all leading and trailing white
spaces.", "ognl": false, "suffix": "}" },
+ "length(exp)": { "index": 53, "kind": "function", "displayName": "Length",
"group": "function", "label": "function", "required": false, "javaType": "int",
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The payload length (number of bytes) of the
message body (or expression).", "ognl": false, "suffix": "}" },
+ "size(exp)": { "index": 54, "kind": "function", "displayName": "Size",
"group": "function", "label": "function", "required": false, "javaType": "int",
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The size of the message body (or expression).
If the payload is java.util.Collection or java.util.Map based then the size is
the number of elements; otherwise the payload size in bytes.", "ognl": false,
"suffix": "}" },
+ "uppercase(exp)": { "index": 55, "kind": "function", "displayName":
"Uppercase", "group": "function", "label": "function", "required": false,
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "Uppercases the message
body (or expression)", "ognl": false, "suffix": "}" },
+ "lowercase(exp)": { "index": 56, "kind": "function", "displayName":
"Lowercase", "group": "function", "label": "function", "required": false,
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "Lowercases the message
body (or expression)", "ognl": false, "suffix": "}" },
+ "concat(exp,exp,separator)": { "index": 57, "kind": "function",
"displayName": "Concat", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Performs a string concat using two expressions (message body as default) with
optional separator", "ognl": false, "suffix": "}" },
+ "collate(num)": { "index": 58, "kind": "function", "displayName": "Group
Message Body into Sub Lists", "group": "function", "label": "function",
"required": false, "javaType": "java.util.Iterator", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The collate function iterates the message body and
groups the data into sub lists of specified size. This can be used with the
Splitter EIP to split a message body and group\/ba [...]
+ "join(separator,prefix,exp)": { "index": 59, "kind": "function",
"displayName": "Join", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
join function iterates the message body\/expression and joins the data into a
string. The separator is by default a comma. The prefix is optional. The join
uses the message body as source by default. [...]
+ "messageHistory(boolean)": { "index": 60, "kind": "function",
"displayName": "Print Message History", "group": "function", "label":
"function", "required": false, "javaType": "String", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The message history of the current exchange (how it has
been routed). This is similar to the route stack-trace message history the
error handler logs in case of an unhandled exception. The b [...]
+ "uuid(type)": { "index": 61, "kind": "function", "displayName": "Generate
UUID", "group": "function", "label": "function", "required": false, "javaType":
"String", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "Returns a UUID using the
Camel `UuidGenerator`. You can choose between `default`, `classic`, `short` and
`simple` as the type. If no type is given, the default is used. It is also
possible to use a custom `UuidG [...]
+ "hash(exp,algorithm)": { "index": 62, "kind": "function", "displayName":
"Compute Hash Value", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Returns a hashed value (string in hex decimal) of the message body\/expression
using JDK MessageDigest. The algorithm can be SHA-256 (default) or SHA3-256.",
"ognl": false, "suffix": "}" },
+ "empty(type)": { "index": 63, "kind": "function", "displayName": "Create
Empty Object", "group": "function", "label": "function", "required": false,
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "Creates a new empty
object (decided by type). Use `string` to create an empty String. Use `list` to
create an empty `java.util.ArrayList`. Use `map` to create an empty
`java.util.LinkedHashMap`.", "ognl": [...]
+ "iif(predicate,trueExp,falseExp)": { "index": 64, "kind": "function",
"displayName": "If Then Else", "group": "function", "label": "function",
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Evaluates the predicate and returns the value of trueExp or falseExp. This
function is similar to the ternary operator in Java.", "ognl": false, "suffix":
"}" },
+ "list(val...)": { "index": 65, "kind": "function", "displayName": "Create
List of values", "group": "function", "label": "function", "required": false,
"javaType": "java.util.ArrayList", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
list function creates an ArrayList with the given set of values.", "ognl":
false, "suffix": "}" },
+ "map(key1,value1,...)": { "index": 66, "kind": "function", "displayName":
"Create Map of pairs", "group": "function", "label": "function", "required":
false, "javaType": "java.util.LinkedHashMap", "prefix": "${", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "The map function creates a LinkedHashMap with the given set of
pairs.", "ognl": false, "suffix": "}" },
+ "attachments": { "index": 67, "kind": "function", "displayName":
"Attachments", "group": "function", "label": "function", "required": false,
"javaType": "java.util.Map", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "All
the attachments as a Map<String,DataHandler.", "ognl": false, "suffix": "}" },
+ "attachments.size": { "index": 68, "kind": "function", "displayName":
"Attachments", "group": "function", "label": "function", "required": false,
"javaType": "int", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The number of attachments.
Is 0 if there are no attachments.", "ognl": false, "suffix": "}" },
+ "attachmentContentAsText": { "index": 69, "kind": "function",
"displayName": "Attachment Content As Text", "group": "function", "label":
"function", "required": false, "javaType": "String", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment as text (ie String).",
"ognl": false, "suffix": "}" },
+ "attachmentContent": { "index": 70, "kind": "function", "displayName":
"Attachment Content", "group": "function", "label": "function", "required":
false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
content of the attachment", "ognl": false, "suffix": "}" },
+ "attachmentContentAs(type)": { "index": 71, "kind": "function",
"displayName": "Attachment Content As", "group": "function", "label":
"function", "required": false, "javaType": "Object", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment, converted to the given
type.", "ognl": false, "suffix": "}" },
+ "attachmentHeader(key,name)": { "index": 72, "kind": "function",
"displayName": "Attachment Header", "group": "function", "label": "function",
"required": false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
attachment header with the given name.", "ognl": false, "suffix": "}" },
+ "attachmentHeader(key,name,type)": { "index": 73, "kind": "function",
"displayName": "Attachment Header", "group": "function", "label": "function",
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
attachment header with the given name, converted to the given type.", "ognl":
false, "suffix": "}" },
+ "attachment(key)": { "index": 74, "kind": "function", "displayName":
"Attachment", "group": "function", "label": "function", "required": false,
"javaType": "jakarta.activation.DataHandler", "prefix": "${", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "The DataHandler for the given attachment.", "ognl": true,
"suffix": "}" }
}
}
diff --git
a/components/camel-csimple-joor/src/test/java/org/apache/camel/language/csimple/joor/OriginalSimpleTest.java
b/components/camel-csimple-joor/src/test/java/org/apache/camel/language/csimple/joor/OriginalSimpleTest.java
index c27db33de42e..a46a23f10f35 100644
---
a/components/camel-csimple-joor/src/test/java/org/apache/camel/language/csimple/joor/OriginalSimpleTest.java
+++
b/components/camel-csimple-joor/src/test/java/org/apache/camel/language/csimple/joor/OriginalSimpleTest.java
@@ -2344,6 +2344,58 @@ public class OriginalSimpleTest extends
LanguageTestSupport {
assertEquals(f.length(), len);
}
+ @Test
+ public void testSubstringBefore() {
+ exchange.getMessage().setBody("Hello World");
+
+ Expression expression =
context.resolveLanguage("csimple").createExpression("${substringBefore('World')}");
+ String s = expression.evaluate(exchange, String.class);
+ assertEquals("Hello ", s);
+
+ expression =
context.resolveLanguage("csimple").createExpression("${substringBefore('
World')}");
+ s = expression.evaluate(exchange, String.class);
+ assertEquals("Hello", s);
+
+ expression =
context.resolveLanguage("csimple").createExpression("${substringBefore(${body},'World')}");
+ s = expression.evaluate(exchange, String.class);
+ assertEquals("Hello ", s);
+
+ expression =
context.resolveLanguage("csimple").createExpression("${substringBefore('Unknown')}");
+ s = expression.evaluate(exchange, String.class);
+ assertNull(s);
+
+ exchange.getMessage().setHeader("place", "World");
+ expression =
context.resolveLanguage("csimple").createExpression("${substringBefore(${body},${header.place})}");
+ s = expression.evaluate(exchange, String.class);
+ assertEquals("Hello ", s);
+ }
+
+ @Test
+ public void testSubstringAfter() {
+ exchange.getMessage().setBody("Hello World");
+
+ Expression expression =
context.resolveLanguage("csimple").createExpression("${substringAfter('Hello')}");
+ String s = expression.evaluate(exchange, String.class);
+ assertEquals(" World", s);
+
+ expression =
context.resolveLanguage("csimple").createExpression("${substringAfter('Hello
')}");
+ s = expression.evaluate(exchange, String.class);
+ assertEquals("World", s);
+
+ expression =
context.resolveLanguage("csimple").createExpression("${substringAfter(${body},'Hello')}");
+ s = expression.evaluate(exchange, String.class);
+ assertEquals(" World", s);
+
+ expression =
context.resolveLanguage("csimple").createExpression("${substringAfter('Unknown')}");
+ s = expression.evaluate(exchange, String.class);
+ assertNull(s);
+
+ exchange.getMessage().setHeader("place", "Hello");
+ expression =
context.resolveLanguage("csimple").createExpression("${substringAfter(${body},${header.place})}");
+ s = expression.evaluate(exchange, String.class);
+ assertEquals(" World", s);
+ }
+
@Test
public void testTrim() {
exchange.getMessage().setBody(" Hello World ");
diff --git
a/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
b/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
index 29debf063014..dc9b059cb0ae 100644
---
a/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
+++
b/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
@@ -70,31 +70,33 @@
"type:name.field": { "index": 44, "kind": "function", "displayName": "Java
Field Value", "group": "function", "label": "function", "required": false,
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "To refer to a type or
field by its classname. To refer to a field, you can append .FIELD_NAME. For
example, you can refer to the constant field from Exchange as:
`org.apache.camel.Exchange.FILE_NAME`", " [...]
"replace(from,to,exp)": { "index": 45, "kind": "function", "displayName":
"Replace String Values", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Replace all the string values in the message body\/expression. To make it
easier to replace single and double quotes, then you can use XML escaped values
`\\"` as double quote, `\\'` [...]
"substring(head,tail)": { "index": 46, "kind": "function", "displayName":
"Substring", "group": "function", "label": "function", "required": false,
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "Returns a substring of
the message body\/expression. If only one positive number, then the returned
string is clipped from the beginning. If only one negative number, then the
returned string is clipped fr [...]
- "random(min,max)": { "index": 47, "kind": "function", "displayName":
"Generate Random Number", "group": "function", "label": "function", "required":
false, "javaType": "int", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Returns a random number between min (included) and max (excluded).", "ognl":
false, "suffix": "}" },
- "skip(num)": { "index": 48, "kind": "function", "displayName": "Skip First
Items from the Message Body", "group": "function", "label": "function",
"required": false, "javaType": "java.util.Iterator", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The skip function iterates the message body and skips
the first number of items. This can be used with the Splitter EIP to split a
message body and skip the first N number of [...]
- "convertTo(exp,type)": { "index": 49, "kind": "function", "displayName":
"Convert To", "group": "function", "label": "function", "required": false,
"javaType": "", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "Converts the message body
(or expression) to the specified type.", "ognl": true, "suffix": "}" },
- "trim(exp)": { "index": 50, "kind": "function", "displayName": "Trim",
"group": "function", "label": "function", "required": false, "javaType":
"String", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The trim function trims
the message body (or expression) by removing all leading and trailing white
spaces.", "ognl": false, "suffix": "}" },
- "length(exp)": { "index": 51, "kind": "function", "displayName": "Length",
"group": "function", "label": "function", "required": false, "javaType": "int",
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The payload length (number of bytes) of the
message body (or expression).", "ognl": false, "suffix": "}" },
- "size(exp)": { "index": 52, "kind": "function", "displayName": "Size",
"group": "function", "label": "function", "required": false, "javaType": "int",
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The size of the message body (or expression).
If the payload is java.util.Collection or java.util.Map based then the size is
the number of elements; otherwise the payload size in bytes.", "ognl": false,
"suffix": "}" },
- "uppercase(exp)": { "index": 53, "kind": "function", "displayName":
"Uppercase", "group": "function", "label": "function", "required": false,
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "Uppercases the message
body (or expression)", "ognl": false, "suffix": "}" },
- "lowercase(exp)": { "index": 54, "kind": "function", "displayName":
"Lowercase", "group": "function", "label": "function", "required": false,
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "Lowercases the message
body (or expression)", "ognl": false, "suffix": "}" },
- "concat(exp,exp,separator)": { "index": 55, "kind": "function",
"displayName": "Concat", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Performs a string concat using two expressions (message body as default) with
optional separator", "ognl": false, "suffix": "}" },
- "collate(num)": { "index": 56, "kind": "function", "displayName": "Group
Message Body into Sub Lists", "group": "function", "label": "function",
"required": false, "javaType": "java.util.Iterator", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The collate function iterates the message body and
groups the data into sub lists of specified size. This can be used with the
Splitter EIP to split a message body and group\/ba [...]
- "join(separator,prefix,exp)": { "index": 57, "kind": "function",
"displayName": "Join", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
join function iterates the message body\/expression and joins the data into a
string. The separator is by default a comma. The prefix is optional. The join
uses the message body as source by default. [...]
- "messageHistory(boolean)": { "index": 58, "kind": "function",
"displayName": "Print Message History", "group": "function", "label":
"function", "required": false, "javaType": "String", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The message history of the current exchange (how it has
been routed). This is similar to the route stack-trace message history the
error handler logs in case of an unhandled exception. The b [...]
- "uuid(type)": { "index": 59, "kind": "function", "displayName": "Generate
UUID", "group": "function", "label": "function", "required": false, "javaType":
"String", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "Returns a UUID using the
Camel `UuidGenerator`. You can choose between `default`, `classic`, `short` and
`simple` as the type. If no type is given, the default is used. It is also
possible to use a custom `UuidG [...]
- "hash(exp,algorithm)": { "index": 60, "kind": "function", "displayName":
"Compute Hash Value", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Returns a hashed value (string in hex decimal) of the message body\/expression
using JDK MessageDigest. The algorithm can be SHA-256 (default) or SHA3-256.",
"ognl": false, "suffix": "}" },
- "empty(type)": { "index": 61, "kind": "function", "displayName": "Create
Empty Object", "group": "function", "label": "function", "required": false,
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "Creates a new empty
object (decided by type). Use `string` to create an empty String. Use `list` to
create an empty `java.util.ArrayList`. Use `map` to create an empty
`java.util.LinkedHashMap`.", "ognl": [...]
- "iif(predicate,trueExp,falseExp)": { "index": 62, "kind": "function",
"displayName": "If Then Else", "group": "function", "label": "function",
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Evaluates the predicate and returns the value of trueExp or falseExp. This
function is similar to the ternary operator in Java.", "ognl": false, "suffix":
"}" },
- "list(val...)": { "index": 63, "kind": "function", "displayName": "Create
List of values", "group": "function", "label": "function", "required": false,
"javaType": "java.util.ArrayList", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
list function creates an ArrayList with the given set of values.", "ognl":
false, "suffix": "}" },
- "map(key1,value1,...)": { "index": 64, "kind": "function", "displayName":
"Create Map of pairs", "group": "function", "label": "function", "required":
false, "javaType": "java.util.LinkedHashMap", "prefix": "${", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "The map function creates a LinkedHashMap with the given set of
pairs.", "ognl": false, "suffix": "}" },
- "attachments": { "index": 65, "kind": "function", "displayName":
"Attachments", "group": "function", "label": "function", "required": false,
"javaType": "java.util.Map", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "All
the attachments as a Map<String,DataHandler.", "ognl": false, "suffix": "}" },
- "attachments.size": { "index": 66, "kind": "function", "displayName":
"Attachments", "group": "function", "label": "function", "required": false,
"javaType": "int", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The number of attachments.
Is 0 if there are no attachments.", "ognl": false, "suffix": "}" },
- "attachmentContentAsText": { "index": 67, "kind": "function",
"displayName": "Attachment Content As Text", "group": "function", "label":
"function", "required": false, "javaType": "String", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment as text (ie String).",
"ognl": false, "suffix": "}" },
- "attachmentContent": { "index": 68, "kind": "function", "displayName":
"Attachment Content", "group": "function", "label": "function", "required":
false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
content of the attachment", "ognl": false, "suffix": "}" },
- "attachmentContentAs(type)": { "index": 69, "kind": "function",
"displayName": "Attachment Content As", "group": "function", "label":
"function", "required": false, "javaType": "Object", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment, converted to the given
type.", "ognl": false, "suffix": "}" },
- "attachmentHeader(key,name)": { "index": 70, "kind": "function",
"displayName": "Attachment Header", "group": "function", "label": "function",
"required": false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
attachment header with the given name.", "ognl": false, "suffix": "}" },
- "attachmentHeader(key,name,type)": { "index": 71, "kind": "function",
"displayName": "Attachment Header", "group": "function", "label": "function",
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
attachment header with the given name, converted to the given type.", "ognl":
false, "suffix": "}" },
- "attachment(key)": { "index": 72, "kind": "function", "displayName":
"Attachment", "group": "function", "label": "function", "required": false,
"javaType": "jakarta.activation.DataHandler", "prefix": "${", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "The DataHandler for the given attachment.", "ognl": true,
"suffix": "}" }
+ "substringBefore(exp,before)": { "index": 47, "kind": "function",
"displayName": "Substring Before", "group": "function", "label": "function",
"required": false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Returns a substring of the message body\/expression that comes before. Returns
null if nothing comes before.", "ognl": false, "suffix": "}" },
+ "substringAfter(exp,before)": { "index": 48, "kind": "function",
"displayName": "Substring After", "group": "function", "label": "function",
"required": false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Returns a substring of the message body\/expression that comes after. Returns
null if nothing comes after.", "ognl": false, "suffix": "}" },
+ "random(min,max)": { "index": 49, "kind": "function", "displayName":
"Generate Random Number", "group": "function", "label": "function", "required":
false, "javaType": "int", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Returns a random number between min (included) and max (excluded).", "ognl":
false, "suffix": "}" },
+ "skip(num)": { "index": 50, "kind": "function", "displayName": "Skip First
Items from the Message Body", "group": "function", "label": "function",
"required": false, "javaType": "java.util.Iterator", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The skip function iterates the message body and skips
the first number of items. This can be used with the Splitter EIP to split a
message body and skip the first N number of [...]
+ "convertTo(exp,type)": { "index": 51, "kind": "function", "displayName":
"Convert To", "group": "function", "label": "function", "required": false,
"javaType": "", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "Converts the message body
(or expression) to the specified type.", "ognl": true, "suffix": "}" },
+ "trim(exp)": { "index": 52, "kind": "function", "displayName": "Trim",
"group": "function", "label": "function", "required": false, "javaType":
"String", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The trim function trims
the message body (or expression) by removing all leading and trailing white
spaces.", "ognl": false, "suffix": "}" },
+ "length(exp)": { "index": 53, "kind": "function", "displayName": "Length",
"group": "function", "label": "function", "required": false, "javaType": "int",
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The payload length (number of bytes) of the
message body (or expression).", "ognl": false, "suffix": "}" },
+ "size(exp)": { "index": 54, "kind": "function", "displayName": "Size",
"group": "function", "label": "function", "required": false, "javaType": "int",
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The size of the message body (or expression).
If the payload is java.util.Collection or java.util.Map based then the size is
the number of elements; otherwise the payload size in bytes.", "ognl": false,
"suffix": "}" },
+ "uppercase(exp)": { "index": 55, "kind": "function", "displayName":
"Uppercase", "group": "function", "label": "function", "required": false,
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "Uppercases the message
body (or expression)", "ognl": false, "suffix": "}" },
+ "lowercase(exp)": { "index": 56, "kind": "function", "displayName":
"Lowercase", "group": "function", "label": "function", "required": false,
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "Lowercases the message
body (or expression)", "ognl": false, "suffix": "}" },
+ "concat(exp,exp,separator)": { "index": 57, "kind": "function",
"displayName": "Concat", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Performs a string concat using two expressions (message body as default) with
optional separator", "ognl": false, "suffix": "}" },
+ "collate(num)": { "index": 58, "kind": "function", "displayName": "Group
Message Body into Sub Lists", "group": "function", "label": "function",
"required": false, "javaType": "java.util.Iterator", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The collate function iterates the message body and
groups the data into sub lists of specified size. This can be used with the
Splitter EIP to split a message body and group\/ba [...]
+ "join(separator,prefix,exp)": { "index": 59, "kind": "function",
"displayName": "Join", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
join function iterates the message body\/expression and joins the data into a
string. The separator is by default a comma. The prefix is optional. The join
uses the message body as source by default. [...]
+ "messageHistory(boolean)": { "index": 60, "kind": "function",
"displayName": "Print Message History", "group": "function", "label":
"function", "required": false, "javaType": "String", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The message history of the current exchange (how it has
been routed). This is similar to the route stack-trace message history the
error handler logs in case of an unhandled exception. The b [...]
+ "uuid(type)": { "index": 61, "kind": "function", "displayName": "Generate
UUID", "group": "function", "label": "function", "required": false, "javaType":
"String", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "Returns a UUID using the
Camel `UuidGenerator`. You can choose between `default`, `classic`, `short` and
`simple` as the type. If no type is given, the default is used. It is also
possible to use a custom `UuidG [...]
+ "hash(exp,algorithm)": { "index": 62, "kind": "function", "displayName":
"Compute Hash Value", "group": "function", "label": "function", "required":
false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Returns a hashed value (string in hex decimal) of the message body\/expression
using JDK MessageDigest. The algorithm can be SHA-256 (default) or SHA3-256.",
"ognl": false, "suffix": "}" },
+ "empty(type)": { "index": 63, "kind": "function", "displayName": "Create
Empty Object", "group": "function", "label": "function", "required": false,
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote":
"", "autowired": false, "secret": false, "description": "Creates a new empty
object (decided by type). Use `string` to create an empty String. Use `list` to
create an empty `java.util.ArrayList`. Use `map` to create an empty
`java.util.LinkedHashMap`.", "ognl": [...]
+ "iif(predicate,trueExp,falseExp)": { "index": 64, "kind": "function",
"displayName": "If Then Else", "group": "function", "label": "function",
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description":
"Evaluates the predicate and returns the value of trueExp or falseExp. This
function is similar to the ternary operator in Java.", "ognl": false, "suffix":
"}" },
+ "list(val...)": { "index": 65, "kind": "function", "displayName": "Create
List of values", "group": "function", "label": "function", "required": false,
"javaType": "java.util.ArrayList", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
list function creates an ArrayList with the given set of values.", "ognl":
false, "suffix": "}" },
+ "map(key1,value1,...)": { "index": 66, "kind": "function", "displayName":
"Create Map of pairs", "group": "function", "label": "function", "required":
false, "javaType": "java.util.LinkedHashMap", "prefix": "${", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "The map function creates a LinkedHashMap with the given set of
pairs.", "ognl": false, "suffix": "}" },
+ "attachments": { "index": 67, "kind": "function", "displayName":
"Attachments", "group": "function", "label": "function", "required": false,
"javaType": "java.util.Map", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "All
the attachments as a Map<String,DataHandler.", "ognl": false, "suffix": "}" },
+ "attachments.size": { "index": 68, "kind": "function", "displayName":
"Attachments", "group": "function", "label": "function", "required": false,
"javaType": "int", "prefix": "${", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The number of attachments.
Is 0 if there are no attachments.", "ognl": false, "suffix": "}" },
+ "attachmentContentAsText": { "index": 69, "kind": "function",
"displayName": "Attachment Content As Text", "group": "function", "label":
"function", "required": false, "javaType": "String", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment as text (ie String).",
"ognl": false, "suffix": "}" },
+ "attachmentContent": { "index": 70, "kind": "function", "displayName":
"Attachment Content", "group": "function", "label": "function", "required":
false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
content of the attachment", "ognl": false, "suffix": "}" },
+ "attachmentContentAs(type)": { "index": 71, "kind": "function",
"displayName": "Attachment Content As", "group": "function", "label":
"function", "required": false, "javaType": "Object", "prefix": "${",
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The content of the attachment, converted to the given
type.", "ognl": false, "suffix": "}" },
+ "attachmentHeader(key,name)": { "index": 72, "kind": "function",
"displayName": "Attachment Header", "group": "function", "label": "function",
"required": false, "javaType": "String", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
attachment header with the given name.", "ognl": false, "suffix": "}" },
+ "attachmentHeader(key,name,type)": { "index": 73, "kind": "function",
"displayName": "Attachment Header", "group": "function", "label": "function",
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "description": "The
attachment header with the given name, converted to the given type.", "ognl":
false, "suffix": "}" },
+ "attachment(key)": { "index": 74, "kind": "function", "displayName":
"Attachment", "group": "function", "label": "function", "required": false,
"javaType": "jakarta.activation.DataHandler", "prefix": "${", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "The DataHandler for the given attachment.", "ognl": true,
"suffix": "}" }
}
}
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 899d166fff09..c883e34d2fb6 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
@@ -268,6 +268,9 @@ If the number is negative, then the returned string is
clipped from the ending.
If the number is positive, then the returned string is clipped from the
beginning.
If the number is negative, then the returned string is clipped from the ending.
+|substringBefore(exp,before) |String |Returns a substring of the message
body/expression that comes before. Returns null if nothing comes before.
+|substringAfter(exp,before) |String |Returns a substring of the message
body/expression that comes after. Returns null if nothing comes after.
+
|collate(group) |List |The collate function iterates the message body and
groups
the data into sub lists of specified size. This can be used with the
Splitter EIP to split a message body and group/batch
diff --git
a/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
b/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
index 64137118abd5..c393035eea3c 100644
---
a/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
+++
b/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
@@ -554,6 +554,24 @@ public final class CSimpleHelper {
return between(text, head, tail);
}
+ public static String substringBefore(Exchange exchange, Object value,
Object text) {
+ String body =
exchange.getContext().getTypeConverter().tryConvertTo(String.class, exchange,
value);
+ if (body == null) {
+ return null;
+ }
+ String before =
exchange.getContext().getTypeConverter().convertTo(String.class, exchange,
text);
+ return StringHelper.before(body, before);
+ }
+
+ public static String substringAfter(Exchange exchange, Object value,
Object text) {
+ String body =
exchange.getContext().getTypeConverter().tryConvertTo(String.class, exchange,
value);
+ if (body == null) {
+ return null;
+ }
+ String after =
exchange.getContext().getTypeConverter().convertTo(String.class, exchange,
text);
+ return StringHelper.after(body, after);
+ }
+
public static int random(Exchange exchange, Object min, Object max) {
int num1 =
exchange.getContext().getTypeConverter().tryConvertTo(int.class, exchange, min);
int num2 =
exchange.getContext().getTypeConverter().tryConvertTo(int.class, exchange, max);
diff --git
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleConstants.java
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleConstants.java
index 00cbccee1fff..57dd03120f8d 100644
---
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleConstants.java
+++
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleConstants.java
@@ -175,6 +175,12 @@ public final class SimpleConstants {
+ " Otherwise the returned string is clipped
between the head and tail positions.",
label = "function", javaType = "String")
public static final String SUBSTRING = "substring(head,tail)";
+ @Metadata(description = "Returns a substring of the message
body/expression that comes before. Returns null if nothing comes before.",
+ label = "function", javaType = "String")
+ public static final String SUBSTRING_BEFORE =
"substringBefore(exp,before)";
+ @Metadata(description = "Returns a substring of the message
body/expression that comes after. Returns null if nothing comes after.",
+ label = "function", javaType = "String")
+ public static final String SUBSTRING_AFTER = "substringAfter(exp,before)";
@Metadata(description = "Returns a random number between min (included)
and max (excluded).", label = "function",
javaType = "int", displayName = "Generate Random Number")
public static final String RANDOM = "random(min,max)";
diff --git
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
index b57a79616241..c3ba27e19e42 100644
---
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
+++
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
@@ -762,6 +762,72 @@ public final class SimpleExpressionBuilder {
};
}
+ /**
+ * Returns the substring from the given expression that comes before
+ */
+ public static Expression substringBeforeExpression(final String
expression, final String before) {
+ return new ExpressionAdapter() {
+ private Expression exp;
+ private Expression expBefore;
+
+ @Override
+ public void init(CamelContext context) {
+ exp =
context.resolveLanguage("simple").createExpression(expression);
+ exp.init(context);
+ expBefore = ExpressionBuilder.simpleExpression(before);
+ expBefore.init(context);
+ }
+
+ @Override
+ public Object evaluate(Exchange exchange) {
+ String body = exp.evaluate(exchange, String.class);
+ if (body == null) {
+ return null;
+ }
+ String bef = expBefore.evaluate(exchange, String.class);
+ return StringHelper.before(body, bef);
+ }
+
+ @Override
+ public String toString() {
+ return "substringBefore(" + expression + "," + before + ")";
+ }
+ };
+ }
+
+ /**
+ * Returns the substring from the given expression that comes after
+ */
+ public static Expression substringAfterExpression(final String expression,
final String after) {
+ return new ExpressionAdapter() {
+ private Expression exp;
+ private Expression expAfter;
+
+ @Override
+ public void init(CamelContext context) {
+ exp =
context.resolveLanguage("simple").createExpression(expression);
+ exp.init(context);
+ expAfter = ExpressionBuilder.simpleExpression(after);
+ expAfter.init(context);
+ }
+
+ @Override
+ public Object evaluate(Exchange exchange) {
+ String body = exp.evaluate(exchange, String.class);
+ if (body == null) {
+ return null;
+ }
+ String aft = expAfter.evaluate(exchange, String.class);
+ return StringHelper.after(body, aft);
+ }
+
+ @Override
+ public String toString() {
+ return "substringAfter(" + expression + "," + after + ")";
+ }
+ };
+ }
+
/**
* Hashes the value using the given algorithm
*/
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 a079522e8a15..db2c29fa6309 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
@@ -778,6 +778,58 @@ public class SimpleFunctionExpression extends
LiteralExpression {
}
return SimpleExpressionBuilder.substringExpression(exp, num1,
num2);
}
+ remainder = ifStartsWithReturnRemainder("substringBefore(", function);
+ if (remainder != null) {
+ String values = StringHelper.before(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringBefore(exp)} or
${substringBefore(exp,exp)} was: "
+ + function,
+ token.getIndex());
+ }
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringBefore(exp)} or
${substringBefore(exp,exp)} was: "
+ + function,
+ token.getIndex());
+ }
+ String exp1 = "${body}";
+ String before;
+ if (tokens.length == 2) {
+ exp1 = tokens[0];
+ before = tokens[1];
+ } else {
+ before = tokens[0];
+ }
+ return SimpleExpressionBuilder.substringBeforeExpression(exp1,
before);
+ }
+ remainder = ifStartsWithReturnRemainder("substringAfter(", function);
+ if (remainder != null) {
+ String values = StringHelper.before(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringAfter(exp)} or
${substringAfter(exp,exp)} was: "
+ + function,
+ token.getIndex());
+ }
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringAfter(exp)} or
${substringAfter(exp,exp)} was: "
+ + function,
+ token.getIndex());
+ }
+ String exp1 = "${body}";
+ String after;
+ if (tokens.length == 2) {
+ exp1 = tokens[0];
+ after = tokens[1];
+ } else {
+ after = tokens[0];
+ }
+ return SimpleExpressionBuilder.substringAfterExpression(exp1,
after);
+ }
// random function
remainder = ifStartsWithReturnRemainder("random(", function);
@@ -1931,7 +1983,7 @@ public class SimpleFunctionExpression extends
LiteralExpression {
// substring function
remainder = ifStartsWithReturnRemainder("substring(", function);
if (remainder != null) {
- String values = StringHelper.before(remainder, ")");
+ String values = StringHelper.beforeLast(remainder, ")");
if (values == null || ObjectHelper.isEmpty(values)) {
throw new SimpleParserException(
"Valid syntax: ${substring(num)},
${substring(num,num)} was: "
@@ -1952,6 +2004,78 @@ public class SimpleFunctionExpression extends
LiteralExpression {
num2 = num2.trim();
return "substring(exchange, " + num1 + ", " + num2 + ")";
}
+ remainder = ifStartsWithReturnRemainder("substringBefore(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringBefore(before)},
${substringBefore(exp,before)} was: "
+ + function,
+ token.getIndex());
+ }
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringBefore(before)},
${substringBefore(exp,before)} was: "
+ + function,
+ token.getIndex());
+ }
+ // single quotes should be double quotes
+ for (int i = 0; i < tokens.length; i++) {
+ String s = tokens[i];
+ if (StringHelper.isSingleQuoted(s)) {
+ s = StringHelper.removeLeadingAndEndingQuotes(s);
+ s = StringQuoteHelper.doubleQuote(s);
+ tokens[i] = s;
+ }
+ }
+ String body = "body";
+ String before;
+ if (tokens.length > 1) {
+ body = tokens[0];
+ before = tokens[1];
+ } else {
+ before = tokens[0];
+ }
+ return "Object value = " + body + ";\n Object before = " +
before
+ + ";\n return substringBefore(exchange, value,
before);";
+ }
+ remainder = ifStartsWithReturnRemainder("substringAfter(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringAfter(before)},
${substringAfter(exp,before)} was: "
+ + function,
+ token.getIndex());
+ }
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringAfter(before)},
${substringAfter(exp,before)} was: "
+ + function,
+ token.getIndex());
+ }
+ // single quotes should be double quotes
+ for (int i = 0; i < tokens.length; i++) {
+ String s = tokens[i];
+ if (StringHelper.isSingleQuoted(s)) {
+ s = StringHelper.removeLeadingAndEndingQuotes(s);
+ s = StringQuoteHelper.doubleQuote(s);
+ tokens[i] = s;
+ }
+ }
+ String body = "body";
+ String before;
+ if (tokens.length > 1) {
+ body = tokens[0];
+ before = tokens[1];
+ } else {
+ before = tokens[0];
+ }
+ return "Object value = " + body + ";\n Object after = " +
before
+ + ";\n return substringAfter(exchange, value,
after);";
+ }
// random function
remainder = ifStartsWithReturnRemainder("random(", function);
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 fda04a1917ac..2a1a488899d7 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
@@ -2552,6 +2552,58 @@ public class SimpleTest extends LanguageTestSupport {
assertEquals("Carlsberg", s);
}
+ @Test
+ public void testSubstringBefore() {
+ exchange.getMessage().setBody("Hello World");
+
+ Expression expression =
context.resolveLanguage("simple").createExpression("${substringBefore('World')}");
+ String s = expression.evaluate(exchange, String.class);
+ assertEquals("Hello ", s);
+
+ expression =
context.resolveLanguage("simple").createExpression("${substringBefore('
World')}");
+ s = expression.evaluate(exchange, String.class);
+ assertEquals("Hello", s);
+
+ expression =
context.resolveLanguage("simple").createExpression("${substringBefore(${body},'World')}");
+ s = expression.evaluate(exchange, String.class);
+ assertEquals("Hello ", s);
+
+ expression =
context.resolveLanguage("simple").createExpression("${substringBefore('Unknown')}");
+ s = expression.evaluate(exchange, String.class);
+ assertNull(s);
+
+ exchange.getMessage().setHeader("place", "World");
+ expression =
context.resolveLanguage("simple").createExpression("${substringBefore(${body},${header.place})}");
+ s = expression.evaluate(exchange, String.class);
+ assertEquals("Hello ", s);
+ }
+
+ @Test
+ public void testSubstringAfter() {
+ exchange.getMessage().setBody("Hello World");
+
+ Expression expression =
context.resolveLanguage("simple").createExpression("${substringAfter('Hello')}");
+ String s = expression.evaluate(exchange, String.class);
+ assertEquals(" World", s);
+
+ expression =
context.resolveLanguage("simple").createExpression("${substringAfter('Hello
')}");
+ s = expression.evaluate(exchange, String.class);
+ assertEquals("World", s);
+
+ expression =
context.resolveLanguage("simple").createExpression("${substringAfter(${body},'Hello')}");
+ s = expression.evaluate(exchange, String.class);
+ assertEquals(" World", s);
+
+ expression =
context.resolveLanguage("simple").createExpression("${substringAfter('Unknown')}");
+ s = expression.evaluate(exchange, String.class);
+ assertNull(s);
+
+ exchange.getMessage().setHeader("place", "Hello");
+ expression =
context.resolveLanguage("simple").createExpression("${substringAfter(${body},${header.place})}");
+ s = expression.evaluate(exchange, String.class);
+ assertEquals(" World", s);
+ }
+
@Test
public void testConcat() {
exchange.getMessage().setBody("Hello");