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 59290377a26e camel-core - Add reverse/shuffle functions to simple 
language
59290377a26e is described below

commit 59290377a26ee361d567d835e4a7ed385c4fc068
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Jan 23 13:04:58 2026 +0100

    camel-core - Add reverse/shuffle functions to simple language
---
 .../org/apache/camel/catalog/languages/simple.json | 52 +++++++-------
 .../language/csimple/joor/OriginalSimpleTest.java  | 46 +++++++++++++
 .../org/apache/camel/language/simple/simple.json   | 52 +++++++-------
 .../modules/languages/pages/simple-language.adoc   |  2 +
 .../camel/language/csimple/CSimpleHelper.java      | 27 ++++++++
 .../camel/language/simple/SimpleConstants.java     | 10 ++-
 .../language/simple/SimpleExpressionBuilder.java   | 79 ++++++++++++++++++++++
 .../simple/ast/SimpleFunctionExpression.java       | 70 ++++++++++++++++++-
 .../apache/camel/language/simple/SimpleTest.java   | 46 +++++++++++++
 9 files changed, 331 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 bfcc00a501dc..5075bb5c2007 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
@@ -50,7 +50,7 @@
     "convertTo(exp,type)": { "index": 23, "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": "}" },
     "date(command)": { "index": 24, "kind": "function", "displayName": "Parse 
Date", "group": "function", "label": "function", "required": false, "javaType": 
"java.util.Date", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Evaluates to a 
java.util.Date object. Supported commands are: `now` for current timestamp, 
`exchangeCreated` for the timestamp when the current exchange was created, 
`header.xxx` to use the Long\/Date ob [...]
     "date-with-timezone(command:timezone:pattern)": { "index": 25, "kind": 
"function", "displayName": "Date Formatter", "group": "function", "label": 
"function", "required": false, "javaType": "String", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Formats the date to a String using the given date 
pattern, and with support for timezone. Supported commands are: `now` for 
current timestamp, `exchangeCreated` for the timesta [...]
-    "distinct(val...)": { "index": 26, "kind": "function", "displayName": 
"Distinct Values", "group": "function", "label": "function", "required": false, 
"javaType": "long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a set of all the 
values with duplicates removed", "ognl": false, "suffix": "}" },
+    "distinct(val...)": { "index": 26, "kind": "function", "displayName": 
"Distinct Values", "group": "function", "label": "function", "required": false, 
"javaType": "Set", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a set of all the 
values with duplicates removed", "ognl": false, "suffix": "}" },
     "empty(type)": { "index": 27, "kind": "function", "displayName": "Create 
Empty Object", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": true, "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`. Use `set`  [...]
     "env.name": { "index": 28, "kind": "function", "displayName": "OS 
Environment Variable", "group": "function", "label": "function", "required": 
false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
OS environment variable with the given name", "ognl": false, "suffix": "}" },
     "exchange": { "index": 29, "kind": "function", "displayName": "Exchange", 
"group": "function", "label": "function", "required": false, "javaType": 
"org.apache.camel.Exchange", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
current exchange", "ognl": true, "suffix": "}" },
@@ -97,29 +97,31 @@
     "random(min,max)": { "index": 70, "kind": "function", "displayName": 
"Random", "group": "function", "label": "function", "required": false, 
"javaType": "int", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a random number 
between min and max (exclusive)", "ognl": false, "suffix": "}" },
     "ref:name": { "index": 71, "kind": "function", "displayName": "Bean By 
Id", "group": "function", "label": "function", "required": false, "javaType": 
"Object", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "To look up a bean from the 
Registry with the given name.", "ognl": false, "suffix": "}" },
     "replace(from,to,exp)": { "index": 72, "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 
`\\&quot;` as double quote, `\\&apos;`  [...]
-    "routeGroup": { "index": 73, "kind": "function", "displayName": "Route 
Group", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The route group of the 
current route the Exchange is being routed. Not all routes have a group 
assigned, so this may be null.", "ognl": false, "suffix": "}" },
-    "routeId": { "index": 74, "kind": "function", "displayName": "Route Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The route id of the 
current route the Exchange is being routed", "ognl": false, "suffix": "}" },
-    "setHeader(name,type,exp)": { "index": 75, "kind": "function", 
"displayName": "Set Header", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a message header with the given expression (optional converting to the 
given type)", "ognl": false, "suffix": "}" },
-    "setVariable(name,type,exp)": { "index": 76, "kind": "function", 
"displayName": "Set Variable", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a variable with the given expression (optional converting to the given 
type)", "ognl": false, "suffix": "}" },
-    "size(exp)": { "index": 77, "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": "}" },
-    "skip(num)": { "index": 78, "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  [...]
-    "split(exp,separator)": { "index": 79, "kind": "function", "displayName": 
"Split String Values", "group": "function", "label": "function", "required": 
false, "javaType": "String[]", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Splits the message body\/expression as a String value using the separator into 
a String array", "ognl": false, "suffix": "}" },
-    "stepId": { "index": 80, "kind": "function", "displayName": "Step Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the id of the 
current step the Exchange is being routed.", "ognl": false, "suffix": "}" },
-    "substring(head,tail)": { "index": 81, "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 [...]
-    "substringAfter(exp,before)": { "index": 82, "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": "}" },
-    "substringBefore(exp,before)": { "index": 83, "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": "}" },
-    "substringBetween(exp,after,before)": { "index": 84, "kind": "function", 
"displayName": "Substring Between", "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 are between after and 
before. Returns null if nothing comes between.", "ognl": false, "suffix": "}" },
-    "sum(val...)": { "index": 85, "kind": "function", "displayName": 
"Calculate Sum Number", "group": "function", "label": "function", "required": 
false, "javaType": "long", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sums together all the values as integral numbers. This function can also be 
used to subtract by using negative numbers.", "ognl": false, "suffix": "}" },
-    "sys.name": { "index": 86, "kind": "function", "displayName": "JVM System 
Property", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The JVM system 
property with the given name", "ognl": false, "suffix": "}" },
-    "threadId": { "index": 87, "kind": "function", "displayName": "Thread Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the id of the 
current thread. Can be used for logging.", "ognl": false, "suffix": "}" },
-    "threadName": { "index": 88, "kind": "function", "displayName": "Thread 
Name", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the name of the 
current thread. Can be used for logging.", "ognl": false, "suffix": "}" },
-    "trim(exp)": { "index": 89, "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": "}" },
-    "type:name.field": { "index": 90, "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`", " [...]
-    "uppercase(exp)": { "index": 91, "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": "}" },
-    "uuid(type)": { "index": 92, "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 [...]
-    "variable.name": { "index": 93, "kind": "function", "displayName": 
"Variable", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The variable with the 
given name", "ognl": true, "suffix": "}" },
-    "variableAs(key,type)": { "index": 94, "kind": "function", "displayName": 
"Variable As", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Converts the variable 
to the given type (classname).", "ognl": false, "suffix": "}" },
-    "variables": { "index": 95, "kind": "function", "displayName": 
"Variables", "group": "function", "label": "function", "required": false, 
"javaType": "java.util.Map", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Returns all the variables from the current Exchange in a Map", "ognl": false, 
"suffix": "}" },
-    "xpath(input,exp)": { "index": 96, "kind": "function", "displayName": 
"XPath", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "When working with XML 
data, then this allows using 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 (optional [...]
+    "reverse(val...)": { "index": 73, "kind": "function", "displayName": 
"Reverse Values", "group": "function", "label": "function", "required": false, 
"javaType": "List", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a list of all the 
values, but in reverse order", "ognl": false, "suffix": "}" },
+    "routeGroup": { "index": 74, "kind": "function", "displayName": "Route 
Group", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The route group of the 
current route the Exchange is being routed. Not all routes have a group 
assigned, so this may be null.", "ognl": false, "suffix": "}" },
+    "routeId": { "index": 75, "kind": "function", "displayName": "Route Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The route id of the 
current route the Exchange is being routed", "ognl": false, "suffix": "}" },
+    "setHeader(name,type,exp)": { "index": 76, "kind": "function", 
"displayName": "Set Header", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a message header with the given expression (optional converting to the 
given type)", "ognl": false, "suffix": "}" },
+    "setVariable(name,type,exp)": { "index": 77, "kind": "function", 
"displayName": "Set Variable", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a variable with the given expression (optional converting to the given 
type)", "ognl": false, "suffix": "}" },
+    "shuffle(val...)": { "index": 78, "kind": "function", "displayName": 
"Shuffle Values", "group": "function", "label": "function", "required": false, 
"javaType": "List", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a list of all the 
values shuffled in random order", "ognl": false, "suffix": "}" },
+    "size(exp)": { "index": 79, "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": "}" },
+    "skip(num)": { "index": 80, "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  [...]
+    "split(exp,separator)": { "index": 81, "kind": "function", "displayName": 
"Split String Values", "group": "function", "label": "function", "required": 
false, "javaType": "String[]", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Splits the message body\/expression as a String value using the separator into 
a String array", "ognl": false, "suffix": "}" },
+    "stepId": { "index": 82, "kind": "function", "displayName": "Step Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the id of the 
current step the Exchange is being routed.", "ognl": false, "suffix": "}" },
+    "substring(head,tail)": { "index": 83, "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 [...]
+    "substringAfter(exp,before)": { "index": 84, "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": "}" },
+    "substringBefore(exp,before)": { "index": 85, "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": "}" },
+    "substringBetween(exp,after,before)": { "index": 86, "kind": "function", 
"displayName": "Substring Between", "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 are between after and 
before. Returns null if nothing comes between.", "ognl": false, "suffix": "}" },
+    "sum(val...)": { "index": 87, "kind": "function", "displayName": 
"Calculate Sum Number", "group": "function", "label": "function", "required": 
false, "javaType": "long", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sums together all the values as integral numbers. This function can also be 
used to subtract by using negative numbers.", "ognl": false, "suffix": "}" },
+    "sys.name": { "index": 88, "kind": "function", "displayName": "JVM System 
Property", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The JVM system 
property with the given name", "ognl": false, "suffix": "}" },
+    "threadId": { "index": 89, "kind": "function", "displayName": "Thread Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the id of the 
current thread. Can be used for logging.", "ognl": false, "suffix": "}" },
+    "threadName": { "index": 90, "kind": "function", "displayName": "Thread 
Name", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the name of the 
current thread. Can be used for logging.", "ognl": false, "suffix": "}" },
+    "trim(exp)": { "index": 91, "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": "}" },
+    "type:name.field": { "index": 92, "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`", " [...]
+    "uppercase(exp)": { "index": 93, "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": "}" },
+    "uuid(type)": { "index": 94, "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 [...]
+    "variable.name": { "index": 95, "kind": "function", "displayName": 
"Variable", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The variable with the 
given name", "ognl": true, "suffix": "}" },
+    "variableAs(key,type)": { "index": 96, "kind": "function", "displayName": 
"Variable As", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Converts the variable 
to the given type (classname).", "ognl": false, "suffix": "}" },
+    "variables": { "index": 97, "kind": "function", "displayName": 
"Variables", "group": "function", "label": "function", "required": false, 
"javaType": "java.util.Map", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Returns all the variables from the current Exchange in a Map", "ognl": false, 
"suffix": "}" },
+    "xpath(input,exp)": { "index": 98, "kind": "function", "displayName": 
"XPath", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "When working with XML 
data, then this allows using 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 (optional [...]
   }
 }
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 a223b8f9d1a8..f283276079f2 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
@@ -63,6 +63,7 @@ import static 
org.apache.camel.test.junit5.TestSupport.assertIsInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
@@ -3221,6 +3222,51 @@ public class OriginalSimpleTest extends 
LanguageTestSupport {
         assertEquals("[]", s);
     }
 
+    @Test
+    public void testReverse() {
+        exchange.getMessage().setBody("1,2,3,4,5");
+
+        Expression expression = 
context.resolveLanguage("csimple").createExpression("${reverse()}");
+        List list = expression.evaluate(exchange, List.class);
+        assertEquals(5, list.size());
+        String s = expression.evaluate(exchange, String.class);
+        assertEquals("[5, 4, 3, 2, 1]", s);
+
+        expression = 
context.resolveLanguage("csimple").createExpression("${reverse('Z','X','Z','A','B','A','C','D','B','E')}");
+        s = expression.evaluate(exchange, String.class);
+        assertEquals("[E, B, D, C, A, B, A, Z, X, Z]", s);
+
+        expression = context.resolveLanguage("csimple")
+                
.createExpression("${reverse('Z','4',${body},'A','B','A','C','D','B','E')}");
+        s = expression.evaluate(exchange, String.class);
+        assertEquals("[E, B, D, C, A, B, A, 5, 4, 3, 2, 1, 4, Z]", s);
+
+        exchange.getMessage().setBody(null);
+        expression = 
context.resolveLanguage("csimple").createExpression("${reverse()}");
+        s = expression.evaluate(exchange, String.class);
+        assertEquals("[]", s);
+    }
+
+    @Test
+    public void testShuffle() {
+        String input = "1,2,3,4,5,6,7,8,9,0";
+        exchange.getMessage().setBody(input);
+
+        Expression expression = 
context.resolveLanguage("csimple").createExpression("${shuffle()}");
+        List list = expression.evaluate(exchange, List.class);
+        assertEquals(10, list.size());
+        String s = expression.evaluate(exchange, String.class);
+        String s2 = expression.evaluate(exchange, String.class);
+        assertNotEquals(input, s);
+        assertNotEquals(input, s2);
+        assertNotEquals(s, s2); // should be random when calling again
+
+        exchange.getMessage().setBody(null);
+        expression = 
context.resolveLanguage("csimple").createExpression("${shuffle()}");
+        s = expression.evaluate(exchange, String.class);
+        assertEquals("[]", s);
+    }
+
     @Test
     public void testNot() {
         exchange.getMessage().setBody("");
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 bfcc00a501dc..5075bb5c2007 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
@@ -50,7 +50,7 @@
     "convertTo(exp,type)": { "index": 23, "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": "}" },
     "date(command)": { "index": 24, "kind": "function", "displayName": "Parse 
Date", "group": "function", "label": "function", "required": false, "javaType": 
"java.util.Date", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Evaluates to a 
java.util.Date object. Supported commands are: `now` for current timestamp, 
`exchangeCreated` for the timestamp when the current exchange was created, 
`header.xxx` to use the Long\/Date ob [...]
     "date-with-timezone(command:timezone:pattern)": { "index": 25, "kind": 
"function", "displayName": "Date Formatter", "group": "function", "label": 
"function", "required": false, "javaType": "String", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Formats the date to a String using the given date 
pattern, and with support for timezone. Supported commands are: `now` for 
current timestamp, `exchangeCreated` for the timesta [...]
-    "distinct(val...)": { "index": 26, "kind": "function", "displayName": 
"Distinct Values", "group": "function", "label": "function", "required": false, 
"javaType": "long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a set of all the 
values with duplicates removed", "ognl": false, "suffix": "}" },
+    "distinct(val...)": { "index": 26, "kind": "function", "displayName": 
"Distinct Values", "group": "function", "label": "function", "required": false, 
"javaType": "Set", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a set of all the 
values with duplicates removed", "ognl": false, "suffix": "}" },
     "empty(type)": { "index": 27, "kind": "function", "displayName": "Create 
Empty Object", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": true, "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`. Use `set`  [...]
     "env.name": { "index": 28, "kind": "function", "displayName": "OS 
Environment Variable", "group": "function", "label": "function", "required": 
false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
OS environment variable with the given name", "ognl": false, "suffix": "}" },
     "exchange": { "index": 29, "kind": "function", "displayName": "Exchange", 
"group": "function", "label": "function", "required": false, "javaType": 
"org.apache.camel.Exchange", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
current exchange", "ognl": true, "suffix": "}" },
@@ -97,29 +97,31 @@
     "random(min,max)": { "index": 70, "kind": "function", "displayName": 
"Random", "group": "function", "label": "function", "required": false, 
"javaType": "int", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a random number 
between min and max (exclusive)", "ognl": false, "suffix": "}" },
     "ref:name": { "index": 71, "kind": "function", "displayName": "Bean By 
Id", "group": "function", "label": "function", "required": false, "javaType": 
"Object", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "To look up a bean from the 
Registry with the given name.", "ognl": false, "suffix": "}" },
     "replace(from,to,exp)": { "index": 72, "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 
`\\&quot;` as double quote, `\\&apos;`  [...]
-    "routeGroup": { "index": 73, "kind": "function", "displayName": "Route 
Group", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The route group of the 
current route the Exchange is being routed. Not all routes have a group 
assigned, so this may be null.", "ognl": false, "suffix": "}" },
-    "routeId": { "index": 74, "kind": "function", "displayName": "Route Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The route id of the 
current route the Exchange is being routed", "ognl": false, "suffix": "}" },
-    "setHeader(name,type,exp)": { "index": 75, "kind": "function", 
"displayName": "Set Header", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a message header with the given expression (optional converting to the 
given type)", "ognl": false, "suffix": "}" },
-    "setVariable(name,type,exp)": { "index": 76, "kind": "function", 
"displayName": "Set Variable", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a variable with the given expression (optional converting to the given 
type)", "ognl": false, "suffix": "}" },
-    "size(exp)": { "index": 77, "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": "}" },
-    "skip(num)": { "index": 78, "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  [...]
-    "split(exp,separator)": { "index": 79, "kind": "function", "displayName": 
"Split String Values", "group": "function", "label": "function", "required": 
false, "javaType": "String[]", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Splits the message body\/expression as a String value using the separator into 
a String array", "ognl": false, "suffix": "}" },
-    "stepId": { "index": 80, "kind": "function", "displayName": "Step Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the id of the 
current step the Exchange is being routed.", "ognl": false, "suffix": "}" },
-    "substring(head,tail)": { "index": 81, "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 [...]
-    "substringAfter(exp,before)": { "index": 82, "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": "}" },
-    "substringBefore(exp,before)": { "index": 83, "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": "}" },
-    "substringBetween(exp,after,before)": { "index": 84, "kind": "function", 
"displayName": "Substring Between", "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 are between after and 
before. Returns null if nothing comes between.", "ognl": false, "suffix": "}" },
-    "sum(val...)": { "index": 85, "kind": "function", "displayName": 
"Calculate Sum Number", "group": "function", "label": "function", "required": 
false, "javaType": "long", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sums together all the values as integral numbers. This function can also be 
used to subtract by using negative numbers.", "ognl": false, "suffix": "}" },
-    "sys.name": { "index": 86, "kind": "function", "displayName": "JVM System 
Property", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The JVM system 
property with the given name", "ognl": false, "suffix": "}" },
-    "threadId": { "index": 87, "kind": "function", "displayName": "Thread Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the id of the 
current thread. Can be used for logging.", "ognl": false, "suffix": "}" },
-    "threadName": { "index": 88, "kind": "function", "displayName": "Thread 
Name", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the name of the 
current thread. Can be used for logging.", "ognl": false, "suffix": "}" },
-    "trim(exp)": { "index": 89, "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": "}" },
-    "type:name.field": { "index": 90, "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`", " [...]
-    "uppercase(exp)": { "index": 91, "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": "}" },
-    "uuid(type)": { "index": 92, "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 [...]
-    "variable.name": { "index": 93, "kind": "function", "displayName": 
"Variable", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The variable with the 
given name", "ognl": true, "suffix": "}" },
-    "variableAs(key,type)": { "index": 94, "kind": "function", "displayName": 
"Variable As", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Converts the variable 
to the given type (classname).", "ognl": false, "suffix": "}" },
-    "variables": { "index": 95, "kind": "function", "displayName": 
"Variables", "group": "function", "label": "function", "required": false, 
"javaType": "java.util.Map", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Returns all the variables from the current Exchange in a Map", "ognl": false, 
"suffix": "}" },
-    "xpath(input,exp)": { "index": 96, "kind": "function", "displayName": 
"XPath", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "When working with XML 
data, then this allows using 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 (optional [...]
+    "reverse(val...)": { "index": 73, "kind": "function", "displayName": 
"Reverse Values", "group": "function", "label": "function", "required": false, 
"javaType": "List", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a list of all the 
values, but in reverse order", "ognl": false, "suffix": "}" },
+    "routeGroup": { "index": 74, "kind": "function", "displayName": "Route 
Group", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The route group of the 
current route the Exchange is being routed. Not all routes have a group 
assigned, so this may be null.", "ognl": false, "suffix": "}" },
+    "routeId": { "index": 75, "kind": "function", "displayName": "Route Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The route id of the 
current route the Exchange is being routed", "ognl": false, "suffix": "}" },
+    "setHeader(name,type,exp)": { "index": 76, "kind": "function", 
"displayName": "Set Header", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a message header with the given expression (optional converting to the 
given type)", "ognl": false, "suffix": "}" },
+    "setVariable(name,type,exp)": { "index": 77, "kind": "function", 
"displayName": "Set Variable", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a variable with the given expression (optional converting to the given 
type)", "ognl": false, "suffix": "}" },
+    "shuffle(val...)": { "index": 78, "kind": "function", "displayName": 
"Shuffle Values", "group": "function", "label": "function", "required": false, 
"javaType": "List", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a list of all the 
values shuffled in random order", "ognl": false, "suffix": "}" },
+    "size(exp)": { "index": 79, "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": "}" },
+    "skip(num)": { "index": 80, "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  [...]
+    "split(exp,separator)": { "index": 81, "kind": "function", "displayName": 
"Split String Values", "group": "function", "label": "function", "required": 
false, "javaType": "String[]", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Splits the message body\/expression as a String value using the separator into 
a String array", "ognl": false, "suffix": "}" },
+    "stepId": { "index": 82, "kind": "function", "displayName": "Step Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the id of the 
current step the Exchange is being routed.", "ognl": false, "suffix": "}" },
+    "substring(head,tail)": { "index": 83, "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 [...]
+    "substringAfter(exp,before)": { "index": 84, "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": "}" },
+    "substringBefore(exp,before)": { "index": 85, "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": "}" },
+    "substringBetween(exp,after,before)": { "index": 86, "kind": "function", 
"displayName": "Substring Between", "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 are between after and 
before. Returns null if nothing comes between.", "ognl": false, "suffix": "}" },
+    "sum(val...)": { "index": 87, "kind": "function", "displayName": 
"Calculate Sum Number", "group": "function", "label": "function", "required": 
false, "javaType": "long", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sums together all the values as integral numbers. This function can also be 
used to subtract by using negative numbers.", "ognl": false, "suffix": "}" },
+    "sys.name": { "index": 88, "kind": "function", "displayName": "JVM System 
Property", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The JVM system 
property with the given name", "ognl": false, "suffix": "}" },
+    "threadId": { "index": 89, "kind": "function", "displayName": "Thread Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the id of the 
current thread. Can be used for logging.", "ognl": false, "suffix": "}" },
+    "threadName": { "index": 90, "kind": "function", "displayName": "Thread 
Name", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the name of the 
current thread. Can be used for logging.", "ognl": false, "suffix": "}" },
+    "trim(exp)": { "index": 91, "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": "}" },
+    "type:name.field": { "index": 92, "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`", " [...]
+    "uppercase(exp)": { "index": 93, "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": "}" },
+    "uuid(type)": { "index": 94, "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 [...]
+    "variable.name": { "index": 95, "kind": "function", "displayName": 
"Variable", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The variable with the 
given name", "ognl": true, "suffix": "}" },
+    "variableAs(key,type)": { "index": 96, "kind": "function", "displayName": 
"Variable As", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Converts the variable 
to the given type (classname).", "ognl": false, "suffix": "}" },
+    "variables": { "index": 97, "kind": "function", "displayName": 
"Variables", "group": "function", "label": "function", "required": false, 
"javaType": "java.util.Map", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Returns all the variables from the current Exchange in a Map", "ognl": false, 
"suffix": "}" },
+    "xpath(input,exp)": { "index": 98, "kind": "function", "displayName": 
"XPath", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "When working with XML 
data, then this allows using 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 (optional [...]
   }
 }
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 1b5e2c025cee..1e0fbc145f8c 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
@@ -197,6 +197,8 @@ NOTE: Some functions take 1 or more arguments enclosed in 
parentheses, and argum
 |`list(val1,val2,...)` | `List` | The list function creates an 
`java.util.ArrayList` with the given set of values.
 |`map(key1,value1,...)` | `Map` | The map function creates a 
`java.util.LinkedHashMap` with the given set of pairs.
 |`createEmpty(kind)` | `<T>` | Creates a new empty object of the given kind. 
The `string` kind creates an empty `String` object. The `list` creates an empty 
`ArrayList`, and `map` creates an empty `LinkedHashMap` object. Use `set` to 
create an empty `java.util.LinkedHashSet`.
+|`reverse(val1,val2,...)` | `List` | Returns a list of all the values, but in 
reverse order.
+|`shuffle(val1,val2,...)` | `List` | Returns a list of all the values shuffled 
in random order.
 |`skip(number)` | `Iterator` | 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 items.
 |`split(separator)` | `String[]` | Splits the message body as a `String` value 
using the separator into a `String` array. The separator is comma by default.
 |`split(exp,separator)` | `String[]` | Splits the expression as a `String` 
value using the separator into a `String` array. The separator is comma by 
default.
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 249addbb81a6..3304b6d7b4a2 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
@@ -21,6 +21,7 @@ import java.lang.reflect.Array;
 import java.security.MessageDigest;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
@@ -616,6 +617,32 @@ public final class CSimpleHelper {
         return answer;
     }
 
+    public static List<Object> reverse(Exchange exchange, Object... args) {
+        List<Object> answer = new ArrayList<>();
+        for (Object o : args) {
+            // this may be an object that we can iterate
+            Iterable<?> it = 
org.apache.camel.support.ObjectHelper.createIterable(o);
+            for (Object i : it) {
+                answer.add(i);
+            }
+        }
+        Collections.reverse(answer);
+        return answer;
+    }
+
+    public static List<Object> shuffle(Exchange exchange, Object... args) {
+        List<Object> answer = new ArrayList<>();
+        for (Object o : args) {
+            // this may be an object that we can iterate
+            Iterable<?> it = 
org.apache.camel.support.ObjectHelper.createIterable(o);
+            for (Object i : it) {
+                answer.add(i);
+            }
+        }
+        Collections.shuffle(answer);
+        return answer;
+    }
+
     public static Map<String, Object> map(Exchange exchange, Object... args) {
         Map<String, Object> answer = new LinkedHashMap<>();
         for (int i = 0, j = 0; args != null && i < args.length - 1; j++) {
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 1a83622ae949..f0c1804f2957 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
@@ -116,7 +116,7 @@ public final class SimpleConstants {
     public static final String DATE_WITH_TIMEZONE = 
"date-with-timezone(command:timezone:pattern)";
 
     @Metadata(description = "Returns a set of all the values with duplicates 
removed",
-              label = "function", javaType = "long", displayName = "Distinct 
Values")
+              label = "function", javaType = "Set", displayName = "Distinct 
Values")
     public static final String DISTINCT = "distinct(val...)";
 
     @Deprecated
@@ -294,6 +294,10 @@ public final class SimpleConstants {
               label = "function", javaType = "String", displayName = "Replace 
String Values")
     public static final String REPLACE = "replace(from,to,exp)";
 
+    @Metadata(description = "Returns a list of all the values, but in reverse 
order",
+              label = "function", javaType = "List", displayName = "Reverse 
Values")
+    public static final String REVERSE = "reverse(val...)";
+
     @Metadata(description = "The route group of the current route the Exchange 
is being routed. Not all routes have a group assigned, so this may be null.",
               javaType = "String", label = "function")
     public static final String ROUTE_GROUP = "routeGroup";
@@ -310,6 +314,10 @@ public final class SimpleConstants {
               label = "function", javaType = "Object")
     public static final String SET_VARIABLE = "setVariable(name,type,exp)";
 
+    @Metadata(description = "Returns a list of all the values shuffled in 
random order",
+              label = "function", javaType = "List", displayName = "Shuffle 
Values")
+    public static final String SHUFFLE = "shuffle(val...)";
+
     @Metadata(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.",
               label = "function", javaType = "int", displayName = "Size")
     public static final String SIZE = "size(exp)";
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 1d8c397ab3d8..92110ee4fedb 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
@@ -24,6 +24,7 @@ import java.security.MessageDigest;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
@@ -1107,6 +1108,84 @@ public final class SimpleExpressionBuilder {
         };
     }
 
+    /**
+     * An expression that returns the elements in reverse order
+     */
+    public static Expression reverseExpression(String[] values) {
+        return new ExpressionAdapter() {
+
+            private final Expression[] exps = new Expression[values != null ? 
values.length : 0];
+
+            @Override
+            public void init(CamelContext context) {
+                for (int i = 0; values != null && i < values.length; i++) {
+                    Expression exp = 
context.resolveLanguage("simple").createExpression(values[i]);
+                    exp.init(context);
+                    exps[i] = exp;
+                }
+            }
+
+            @Override
+            public Object evaluate(Exchange exchange) {
+                List<Object> answer = new ArrayList<>();
+                for (Expression exp : exps) {
+                    Object o = exp.evaluate(exchange, Object.class);
+                    // this may be an object that we can iterate
+                    Iterable<?> it = 
org.apache.camel.support.ObjectHelper.createIterable(o);
+                    for (Object i : it) {
+                        answer.add(i);
+                    }
+                }
+                Collections.reverse(answer);
+                return answer;
+            }
+
+            @Override
+            public String toString() {
+                return "reverse(" + Arrays.toString(values) + ")";
+            }
+        };
+    }
+
+    /**
+     * An expression that returns the elements in random order
+     */
+    public static Expression shuffleExpression(String[] values) {
+        return new ExpressionAdapter() {
+
+            private final Expression[] exps = new Expression[values != null ? 
values.length : 0];
+
+            @Override
+            public void init(CamelContext context) {
+                for (int i = 0; values != null && i < values.length; i++) {
+                    Expression exp = 
context.resolveLanguage("simple").createExpression(values[i]);
+                    exp.init(context);
+                    exps[i] = exp;
+                }
+            }
+
+            @Override
+            public Object evaluate(Exchange exchange) {
+                List<Object> answer = new ArrayList<>();
+                for (Expression exp : exps) {
+                    Object o = exp.evaluate(exchange, Object.class);
+                    // this may be an object that we can iterate
+                    Iterable<?> it = 
org.apache.camel.support.ObjectHelper.createIterable(o);
+                    for (Object i : it) {
+                        answer.add(i);
+                    }
+                }
+                Collections.shuffle(answer);
+                return answer;
+            }
+
+            @Override
+            public String toString() {
+                return "reverse(" + Arrays.toString(values) + ")";
+            }
+        };
+    }
+
     /**
      * An expression that converts the expressions to number and sum the values
      */
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 d28a8b4b173c..026ce5a8e158 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
@@ -968,7 +968,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
         remainder = ifStartsWithReturnRemainder("distinct(", function);
         if (remainder != null) {
             String values = StringHelper.beforeLast(remainder, ")");
-            String[] tokens = null;
+            String[] tokens;
             if (ObjectHelper.isNotEmpty(values)) {
                 tokens = StringQuoteHelper.splitSafeQuote(values, ',', true, 
false);
             } else {
@@ -976,6 +976,30 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             }
             return SimpleExpressionBuilder.distinctExpression(tokens);
         }
+        // reverse function
+        remainder = ifStartsWithReturnRemainder("reverse(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            String[] tokens;
+            if (ObjectHelper.isNotEmpty(values)) {
+                tokens = StringQuoteHelper.splitSafeQuote(values, ',', true, 
false);
+            } else {
+                tokens = new String[] { "${body}" };
+            }
+            return SimpleExpressionBuilder.reverseExpression(tokens);
+        }
+        // shuffle function
+        remainder = ifStartsWithReturnRemainder("shuffle(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            String[] tokens;
+            if (ObjectHelper.isNotEmpty(values)) {
+                tokens = StringQuoteHelper.splitSafeQuote(values, ',', true, 
false);
+            } else {
+                tokens = new String[] { "${body}" };
+            }
+            return SimpleExpressionBuilder.shuffleExpression(tokens);
+        }
         // skip function
         remainder = ifStartsWithReturnRemainder("skip(", function);
         if (remainder != null) {
@@ -2643,7 +2667,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             return "replace(exchange, " + from + ", " + to + ")";
         }
 
-        // distinct
+        // distinct function
         remainder = ifStartsWithReturnRemainder("distinct(", function);
         if (remainder != null) {
             String values = StringHelper.beforeLast(remainder, ")");
@@ -2664,6 +2688,48 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             String p = sj.length() > 0 ? sj.toString() : "body";
             return "distinct(exchange, " + p + ")";
         }
+        // reverse function
+        remainder = ifStartsWithReturnRemainder("reverse(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            String[] tokens = null;
+            if (ObjectHelper.isNotEmpty(values)) {
+                tokens = codeSplitSafe(values, ',', true, true);
+            }
+            StringJoiner sj = new StringJoiner(", ");
+            for (int i = 0; tokens != null && i < tokens.length; i++) {
+                String s = tokens[i];
+                // single quotes should be double quotes
+                if (StringHelper.isSingleQuoted(s)) {
+                    s = StringHelper.removeLeadingAndEndingQuotes(s);
+                    s = StringQuoteHelper.doubleQuote(s);
+                }
+                sj.add(s);
+            }
+            String p = sj.length() > 0 ? sj.toString() : "body";
+            return "reverse(exchange, " + p + ")";
+        }
+        // shuffle function
+        remainder = ifStartsWithReturnRemainder("shuffle(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            String[] tokens = null;
+            if (ObjectHelper.isNotEmpty(values)) {
+                tokens = codeSplitSafe(values, ',', true, true);
+            }
+            StringJoiner sj = new StringJoiner(", ");
+            for (int i = 0; tokens != null && i < tokens.length; i++) {
+                String s = tokens[i];
+                // single quotes should be double quotes
+                if (StringHelper.isSingleQuoted(s)) {
+                    s = StringHelper.removeLeadingAndEndingQuotes(s);
+                    s = StringQuoteHelper.doubleQuote(s);
+                }
+                sj.add(s);
+            }
+            String p = sj.length() > 0 ? sj.toString() : "body";
+            return "shuffle(exchange, " + p + ")";
+        }
 
         // skip function
         remainder = ifStartsWithReturnRemainder("skip(", 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 1e3981e971b6..4b0d209944f3 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
@@ -64,6 +64,7 @@ import org.junit.jupiter.api.parallel.Resources;
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
@@ -3517,6 +3518,51 @@ public class SimpleTest extends LanguageTestSupport {
         assertEquals("[]", s);
     }
 
+    @Test
+    public void testReverse() {
+        exchange.getMessage().setBody("1,2,3,4,5");
+
+        Expression expression = 
context.resolveLanguage("simple").createExpression("${reverse()}");
+        List list = expression.evaluate(exchange, List.class);
+        assertEquals(5, list.size());
+        String s = expression.evaluate(exchange, String.class);
+        assertEquals("[5, 4, 3, 2, 1]", s);
+
+        expression = 
context.resolveLanguage("simple").createExpression("${reverse('Z','X','Z','A','B','A','C','D','B','E')}");
+        s = expression.evaluate(exchange, String.class);
+        assertEquals("[E, B, D, C, A, B, A, Z, X, Z]", s);
+
+        expression = context.resolveLanguage("simple")
+                
.createExpression("${reverse('Z','4',${body},'A','B','A','C','D','B','E')}");
+        s = expression.evaluate(exchange, String.class);
+        assertEquals("[E, B, D, C, A, B, A, 5, 4, 3, 2, 1, 4, Z]", s);
+
+        exchange.getMessage().setBody(null);
+        expression = 
context.resolveLanguage("simple").createExpression("${reverse()}");
+        s = expression.evaluate(exchange, String.class);
+        assertEquals("[]", s);
+    }
+
+    @Test
+    public void testShuffle() {
+        String input = "1,2,3,4,5,6,7,8,9,0";
+        exchange.getMessage().setBody(input);
+
+        Expression expression = 
context.resolveLanguage("simple").createExpression("${shuffle()}");
+        List list = expression.evaluate(exchange, List.class);
+        assertEquals(10, list.size());
+        String s = expression.evaluate(exchange, String.class);
+        String s2 = expression.evaluate(exchange, String.class);
+        assertNotEquals(input, s);
+        assertNotEquals(input, s2);
+        assertNotEquals(s, s2); // should be random when calling again
+
+        exchange.getMessage().setBody(null);
+        expression = 
context.resolveLanguage("simple").createExpression("${shuffle()}");
+        s = expression.evaluate(exchange, String.class);
+        assertEquals("[]", s);
+    }
+
     @Test
     public void testNot() {
         exchange.getMessage().setBody("");

Reply via email to