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 f24bb4f884a CAMEL-20569: camel-catalog - Markup languages which 
functions they support for better doc and tooling. (#15177)
f24bb4f884a is described below

commit f24bb4f884a24d984a0d650e1befa96a5784ddc7
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Fri Aug 16 14:24:55 2024 +0200

    CAMEL-20569: camel-catalog - Markup languages which functions they support 
for better doc and tooling. (#15177)
    
    CAMEL-20569: camel-catalog - Markup languages which functions they support 
for better doc and tooling.
---
 .../org/apache/camel/catalog/languages/file.json   |  17 ++
 .../org/apache/camel/catalog/languages/simple.json |  57 ++++++
 .../org/apache/camel/spi/annotations/Language.java |  13 ++
 .../org/apache/camel/language/simple/file.json     |  17 ++
 .../org/apache/camel/language/simple/simple.json   |  57 ++++++
 .../modules/languages/pages/file-language.adoc     |   2 +-
 .../modules/languages/pages/simple-language.adoc   |   6 +-
 .../camel/language/simple/FileConstants.java       |  59 ++++++
 .../apache/camel/language/simple/FileLanguage.java |   2 +-
 .../camel/language/simple/SimpleConstants.java     | 215 +++++++++++++++++++++
 .../camel/language/simple/SimpleLanguage.java      |   2 +-
 .../camel/maven/dsl/yaml/support/Schema.java       |   2 +
 .../org/apache/camel/tooling/model/JsonMapper.java |  22 +++
 .../apache/camel/tooling/model/LanguageModel.java  |  70 +++++++
 .../org/apache/camel/tooling/util/Strings.java     |  16 ++
 .../packaging/AbstractGenerateConfigurerMojo.java  |  10 +
 .../camel/maven/packaging/PackageLanguageMojo.java |  99 +++++++++-
 .../camel/maven/packaging/generics/ClassUtil.java  |   4 +-
 .../org/apache/camel/spi/annotations/Language.java |  13 ++
 19 files changed, 673 insertions(+), 10 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/file.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/file.json
index 83d94c000d3..16ae6217ad2 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/file.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/file.json
@@ -20,5 +20,22 @@
     "expression": { "index": 1, "kind": "value", "displayName": "Expression", 
"group": "common", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "The expression value in your chosen language syntax" },
     "resultType": { "index": 2, "kind": "attribute", "displayName": "Result 
Type", "group": "common", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "Sets the class of the result type (type from output)" },
     "trim": { "index": 3, "kind": "attribute", "displayName": "Trim", "group": 
"advanced", "label": "advanced", "required": false, "type": "boolean", 
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": true, "description": "Whether to trim the 
value to remove leading and trailing whitespaces and line breaks" }
+  },
+  "functions": {
+    "file:name": { "index": 0, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The file name (relative 
from starting directory)", "ognl": false, "suffix": "}" },
+    "file:name.noext": { "index": 1, "kind": "function", "displayName": 
"File", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The file name 
(relative from starting directory) without extension", "ognl": false, "suffix": 
"}" },
+    "file:name.noext.single": { "index": 2, "kind": "function", "displayName": 
"File", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The file name 
(relative from starting directory) without extension. If the file name has 
multiple dots, then this expression strips and only returns the last part.", 
"ognl": false, "suffix": "}" },
+    "file:name.ext": { "index": 3, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The file extension", 
"ognl": false, "suffix": "}" },
+    "file:name.ext.single": { "index": 4, "kind": "function", "displayName": 
"File", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The file extension. If 
the file extension has multiple dots, then this expression strips and only 
returns the last part.", "ognl": false, "suffix": "}" },
+    "file:onlyname": { "index": 5, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "\u2020he file name 
(without any leading paths)", "ognl": false, "suffix": "}" },
+    "file:onlyname.noext": { "index": 6, "kind": "function", "displayName": 
"File", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "\u2020he file name 
(without any leading paths) without extension", "ognl": false, "suffix": "}" },
+    "file:onlyname.noext.single": { "index": 7, "kind": "function", 
"displayName": "File", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"\u2020he file name (without any leading paths) without extension. If the file 
name has multiple dots, then this expression strips and only returns the last 
part.", "ognl": false, "suffix": "}" },
+    "file:parent": { "index": 8, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The file parent directory 
(null if no parent directory)", "ognl": false, "suffix": "}" },
+    "file:path": { "index": 9, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The file path", "ognl": 
false, "suffix": "}" },
+    "file:absolute": { "index": 10, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"boolean", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Whether the file is 
regarded as absolute or relative", "ognl": false, "suffix": "}" },
+    "file:absolute.path": { "index": 11, "kind": "function", "displayName": 
"File", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The absolute file 
path", "ognl": false, "suffix": "}" },
+    "file:length": { "index": 12, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The size of the file", 
"ognl": false, "suffix": "}" },
+    "file:size": { "index": 13, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The size of the file", 
"ognl": false, "suffix": "}" },
+    "file:modified": { "index": 14, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The file modification 
date", "ognl": false, "suffix": "}" }
   }
 }
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 223741d6576..2fa67ebaf9d 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
@@ -20,5 +20,62 @@
     "expression": { "index": 1, "kind": "value", "displayName": "Expression", 
"group": "common", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "The expression value in your chosen language syntax" },
     "resultType": { "index": 2, "kind": "attribute", "displayName": "Result 
Type", "group": "common", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "Sets the class of the result type (type from output)" },
     "trim": { "index": 3, "kind": "attribute", "displayName": "Trim", "group": 
"advanced", "label": "advanced", "required": false, "type": "boolean", 
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": true, "description": "Whether to trim the 
value to remove leading and trailing whitespaces and line breaks" }
+  },
+  "functions": {
+    "body": { "index": 0, "kind": "function", "displayName": "Body", "group": 
"function", "label": "function", "required": false, "javaType": "Object", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The message body", "ognl": true, "suffix": "}" 
},
+    "prettyBody": { "index": 1, "kind": "function", "displayName": "Pretty 
Body", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Converts the body to a 
String, and attempts to pretty print if JSon or XML; otherwise the body is 
returned as the String value.", "ognl": false, "suffix": "}" },
+    "bodyOneLine": { "index": 2, "kind": "function", "displayName": "Body One 
Line", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Converts the body to a 
String and removes all line-breaks, so the string is in one line.", "ognl": 
false, "suffix": "}" },
+    "originalBody": { "index": 3, "kind": "function", "displayName": "Original 
Body", "group": "function", "label": "function", "required": false, "javaType": 
"Object", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The original incoming body 
(only available if allowUseOriginalMessage=true).", "ognl": false, "suffix": 
"}" },
+    "id": { "index": 4, "kind": "function", "displayName": "Id", "group": 
"function", "label": "function", "required": false, "javaType": "String", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The message id", "ognl": false, "suffix": "}" 
},
+    "messageTimestamp": { "index": 5, "kind": "function", "displayName": 
"Message Timestamp", "group": "function", "label": "function", "required": 
false, "javaType": "long", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
message timestamp (millis since epoc) that this message originates from. Some 
systems like JMS, Kafka, AWS have a timestamp on the event\/message that Camel 
received. This method returns the timestamp [...]
+    "exchangeId": { "index": 6, "kind": "function", "displayName": "Exchange 
Id", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The exchange id", "ognl": 
false, "suffix": "}" },
+    "exchange": { "index": 7, "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": "}" },
+    "exception": { "index": 8, "kind": "function", "displayName": "Exception", 
"group": "function", "label": "function", "required": false, "javaType": 
"java.lang.Exception", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The exception object 
on the exchange (also from caught exceptions), is null if no exception 
present.", "ognl": true, "suffix": "}" },
+    "exception.message": { "index": 9, "kind": "function", "displayName": 
"Exception Message", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
exception message (also from caught exceptions), is null if no exception 
present.", "ognl": false, "suffix": "}" },
+    "exception.stackTrace": { "index": 10, "kind": "function", "displayName": 
"Exception Stacktrace", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
exception stacktrace (also from caught exceptions), is null if no exception 
present.", "ognl": false, "suffix": "}" },
+    "threadId": { "index": 11, "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": 12, "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": "}" },
+    "hostName": { "index": 13, "kind": "function", "displayName": "Host Name", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the local hostname 
(may be empty if not possible to resolve).", "ognl": false, "suffix": "}" },
+    "camelId": { "index": 14, "kind": "function", "displayName": "Camel Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The name of the 
CamelContext", "ognl": false, "suffix": "}" },
+    "routeId": { "index": 15, "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": "}" },
+    "fromRouteId": { "index": 16, "kind": "function", "displayName": "From 
Route Id", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The original route id 
where this exchange was created.", "ognl": false, "suffix": "}" },
+    "routeGroup": { "index": 17, "kind": "function", "displayName": "Route 
Group", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Returns 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": "}" },
+    "stepId": { "index": 18, "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": "}" },
+    "null": { "index": 19, "kind": "function", "displayName": "Null", "group": 
"function", "label": "function", "required": false, "javaType": "Object", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "Represents a null value", "ognl": false, 
"suffix": "}" },
+    "messageAs(type)": { "index": 20, "kind": "function", "displayName": 
"Message As", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Converts the message 
to the given type (classname).", "ognl": true, "suffix": "}" },
+    "bodyAs(type)": { "index": 21, "kind": "function", "displayName": "Body 
As", "group": "function", "label": "function", "required": false, "javaType": 
"Object", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Converts the message body 
to the given type (classname).", "ognl": true, "suffix": "}" },
+    "mandatoryBodyAs(type)": { "index": 22, "kind": "function", "displayName": 
"Mandatory Body As", "group": "function", "label": "function", "required": 
false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Converts the message body to the given type (classname). If the body is null 
then the function will fail with an exception", "ognl": true, "suffix": "}" },
+    "headerAs(key,type)": { "index": 23, "kind": "function", "displayName": 
"Header As", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Converts the message 
header to the given type (classname).", "ognl": false, "suffix": "}" },
+    "headers": { "index": 24, "kind": "function", "displayName": "Headers", 
"group": "function", "label": "function", "required": false, "javaType": 
"java.util.Map", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns all the message 
headers in a Map", "ognl": false, "suffix": "}" },
+    "header.name": { "index": 25, "kind": "function", "displayName": "Header", 
"group": "function", "label": "function", "required": false, "javaType": 
"Object", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The message header with 
the given name", "ognl": true, "suffix": "}" },
+    "variableAs(key,type)": { "index": 26, "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": 27, "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": "}" },
+    "variable.name": { "index": 28, "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": "}" },
+    "exchangeProperty.name": { "index": 29, "kind": "function", "displayName": 
"Exchange Property", "group": "function", "label": "function", "required": 
false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
exchange property with the given name", "ognl": true, "suffix": "}" },
+    "camelContext": { "index": 30, "kind": "function", "displayName": "Camel 
Context", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The Camel Context", 
"ognl": true, "suffix": "}" },
+    "jq(input,exp)": { "index": 31, "kind": "function", "displayName": "JQ", 
"group": "function", "label": "function", "required": false, "javaType": 
"Object", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "When working with JSon 
data, then this allows using the JQ language, for example, to extract data from 
the message body (in JSon format). This requires having camel-jq JAR on the 
classpath. For input (optional), you can [...]
+    "jsonpath(input,exp)": { "index": 32, "kind": "function", "displayName": 
"JSonPath", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "When working with JSon 
data, then this allows using the JSonPath language, for example, to extract 
data from the message body (in JSon format). This requires having 
camel-jsonpath JAR on the classpath. For i [...]
+    "xpath(input,exp)": { "index": 33, "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 [...]
+    "sys.name": { "index": 34, "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": "}" },
+    "env.name": { "index": 35, "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": "}" },
+    "pretty(exp)": { "index": 36, "kind": "function", "displayName": "Pretty 
Print", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Converts the 
expression to a String, and attempts to pretty print if JSon or XML, otherwise 
the expression is returned as the String value.", "ognl": false, "suffix": "}" 
},
+    "date(command)": { "index": 37, "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": 38, "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 [...]
+    "bean(name.method)": { "index": 39, "kind": "function", "displayName": 
"Call Java Bean", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Calls a Java bean. The 
name of the bean can also refer to a class name using type prefix as follows 
`bean:type:com.foo.MyClass`. If no method name is given then Camel will 
automatic attempt to find the b [...]
+    "propertiesExist:key": { "index": 40, "kind": "function", "displayName": 
"Property Placeholder Exists", "group": "function", "label": "function", 
"required": false, "javaType": "boolean", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Checks whether a property placeholder with the given key exists or not. The 
result can be negated by prefixing the key with !", "ognl": false, "suffix": 
"}" },
+    "properties:key:default": { "index": 41, "kind": "function", 
"displayName": "Property Placeholder", "group": "function", "label": 
"function", "required": false, "javaType": "String", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Lookup a property placeholder with the given key. If the 
key does not exist nor has a value, then an optional default value can be 
specified.", "ognl": false, "suffix": "}" },
+    "ref:name": { "index": 42, "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": "}" },
+    "type:name.field": { "index": 43, "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": 44, "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;`  [...]
+    "substring(head,tail)": { "index": 45, "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": 46, "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": 47, "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  [...]
+    "collate(num)": { "index": 48, "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": 49, "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": 50, "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": 51, "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": 52, "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": 53, "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.HashMap`.", "ognl": false [...]
+    "iif(predicate,trueExp,falseExp)": { "index": 54, "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": 
"}" }
   }
 }
diff --git 
a/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/Language.java
 
b/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/Language.java
index 1a986577836..a619f4e481e 100644
--- 
a/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/Language.java
+++ 
b/core/camel-api/src/generated/java/org/apache/camel/spi/annotations/Language.java
@@ -30,4 +30,17 @@ public @interface Language {
 
     String value();
 
+    /**
+     * The class that contains all the name of functions that are supported by 
the language. The name of the functions
+     * are defined as {@code String} constants in the functions class.
+     * <p/>
+     * The class to provide can be any class but by convention, we would 
expect a class whose name is of type
+     * <i>xxxConstants</i> where <i>xxx</i> is the name of the corresponding 
language like for example
+     * <i>SimpleConstants</i> for the language <i>camel-simple</i>.
+     * <p/>
+     * The metadata of a given functions are retrieved directly from the 
annotation {@code @Metadata} added to the
+     * {@code String} constant representing its name and defined in the 
functions class.
+     */
+    Class<?> functionsClass() default void.class;
+
 }
diff --git 
a/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/file.json
 
b/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/file.json
index 83d94c000d3..16ae6217ad2 100644
--- 
a/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/file.json
+++ 
b/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/file.json
@@ -20,5 +20,22 @@
     "expression": { "index": 1, "kind": "value", "displayName": "Expression", 
"group": "common", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "The expression value in your chosen language syntax" },
     "resultType": { "index": 2, "kind": "attribute", "displayName": "Result 
Type", "group": "common", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "Sets the class of the result type (type from output)" },
     "trim": { "index": 3, "kind": "attribute", "displayName": "Trim", "group": 
"advanced", "label": "advanced", "required": false, "type": "boolean", 
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": true, "description": "Whether to trim the 
value to remove leading and trailing whitespaces and line breaks" }
+  },
+  "functions": {
+    "file:name": { "index": 0, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The file name (relative 
from starting directory)", "ognl": false, "suffix": "}" },
+    "file:name.noext": { "index": 1, "kind": "function", "displayName": 
"File", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The file name 
(relative from starting directory) without extension", "ognl": false, "suffix": 
"}" },
+    "file:name.noext.single": { "index": 2, "kind": "function", "displayName": 
"File", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The file name 
(relative from starting directory) without extension. If the file name has 
multiple dots, then this expression strips and only returns the last part.", 
"ognl": false, "suffix": "}" },
+    "file:name.ext": { "index": 3, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The file extension", 
"ognl": false, "suffix": "}" },
+    "file:name.ext.single": { "index": 4, "kind": "function", "displayName": 
"File", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The file extension. If 
the file extension has multiple dots, then this expression strips and only 
returns the last part.", "ognl": false, "suffix": "}" },
+    "file:onlyname": { "index": 5, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "\u2020he file name 
(without any leading paths)", "ognl": false, "suffix": "}" },
+    "file:onlyname.noext": { "index": 6, "kind": "function", "displayName": 
"File", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "\u2020he file name 
(without any leading paths) without extension", "ognl": false, "suffix": "}" },
+    "file:onlyname.noext.single": { "index": 7, "kind": "function", 
"displayName": "File", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"\u2020he file name (without any leading paths) without extension. If the file 
name has multiple dots, then this expression strips and only returns the last 
part.", "ognl": false, "suffix": "}" },
+    "file:parent": { "index": 8, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The file parent directory 
(null if no parent directory)", "ognl": false, "suffix": "}" },
+    "file:path": { "index": 9, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The file path", "ognl": 
false, "suffix": "}" },
+    "file:absolute": { "index": 10, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"boolean", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Whether the file is 
regarded as absolute or relative", "ognl": false, "suffix": "}" },
+    "file:absolute.path": { "index": 11, "kind": "function", "displayName": 
"File", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The absolute file 
path", "ognl": false, "suffix": "}" },
+    "file:length": { "index": 12, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The size of the file", 
"ognl": false, "suffix": "}" },
+    "file:size": { "index": 13, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The size of the file", 
"ognl": false, "suffix": "}" },
+    "file:modified": { "index": 14, "kind": "function", "displayName": "File", 
"group": "function", "label": "function", "required": false, "javaType": 
"long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The file modification 
date", "ognl": false, "suffix": "}" }
   }
 }
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 223741d6576..2fa67ebaf9d 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
@@ -20,5 +20,62 @@
     "expression": { "index": 1, "kind": "value", "displayName": "Expression", 
"group": "common", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "The expression value in your chosen language syntax" },
     "resultType": { "index": 2, "kind": "attribute", "displayName": "Result 
Type", "group": "common", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "Sets the class of the result type (type from output)" },
     "trim": { "index": 3, "kind": "attribute", "displayName": "Trim", "group": 
"advanced", "label": "advanced", "required": false, "type": "boolean", 
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": true, "description": "Whether to trim the 
value to remove leading and trailing whitespaces and line breaks" }
+  },
+  "functions": {
+    "body": { "index": 0, "kind": "function", "displayName": "Body", "group": 
"function", "label": "function", "required": false, "javaType": "Object", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The message body", "ognl": true, "suffix": "}" 
},
+    "prettyBody": { "index": 1, "kind": "function", "displayName": "Pretty 
Body", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Converts the body to a 
String, and attempts to pretty print if JSon or XML; otherwise the body is 
returned as the String value.", "ognl": false, "suffix": "}" },
+    "bodyOneLine": { "index": 2, "kind": "function", "displayName": "Body One 
Line", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Converts the body to a 
String and removes all line-breaks, so the string is in one line.", "ognl": 
false, "suffix": "}" },
+    "originalBody": { "index": 3, "kind": "function", "displayName": "Original 
Body", "group": "function", "label": "function", "required": false, "javaType": 
"Object", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The original incoming body 
(only available if allowUseOriginalMessage=true).", "ognl": false, "suffix": 
"}" },
+    "id": { "index": 4, "kind": "function", "displayName": "Id", "group": 
"function", "label": "function", "required": false, "javaType": "String", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The message id", "ognl": false, "suffix": "}" 
},
+    "messageTimestamp": { "index": 5, "kind": "function", "displayName": 
"Message Timestamp", "group": "function", "label": "function", "required": 
false, "javaType": "long", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
message timestamp (millis since epoc) that this message originates from. Some 
systems like JMS, Kafka, AWS have a timestamp on the event\/message that Camel 
received. This method returns the timestamp [...]
+    "exchangeId": { "index": 6, "kind": "function", "displayName": "Exchange 
Id", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The exchange id", "ognl": 
false, "suffix": "}" },
+    "exchange": { "index": 7, "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": "}" },
+    "exception": { "index": 8, "kind": "function", "displayName": "Exception", 
"group": "function", "label": "function", "required": false, "javaType": 
"java.lang.Exception", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The exception object 
on the exchange (also from caught exceptions), is null if no exception 
present.", "ognl": true, "suffix": "}" },
+    "exception.message": { "index": 9, "kind": "function", "displayName": 
"Exception Message", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
exception message (also from caught exceptions), is null if no exception 
present.", "ognl": false, "suffix": "}" },
+    "exception.stackTrace": { "index": 10, "kind": "function", "displayName": 
"Exception Stacktrace", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
exception stacktrace (also from caught exceptions), is null if no exception 
present.", "ognl": false, "suffix": "}" },
+    "threadId": { "index": 11, "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": 12, "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": "}" },
+    "hostName": { "index": 13, "kind": "function", "displayName": "Host Name", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the local hostname 
(may be empty if not possible to resolve).", "ognl": false, "suffix": "}" },
+    "camelId": { "index": 14, "kind": "function", "displayName": "Camel Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The name of the 
CamelContext", "ognl": false, "suffix": "}" },
+    "routeId": { "index": 15, "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": "}" },
+    "fromRouteId": { "index": 16, "kind": "function", "displayName": "From 
Route Id", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The original route id 
where this exchange was created.", "ognl": false, "suffix": "}" },
+    "routeGroup": { "index": 17, "kind": "function", "displayName": "Route 
Group", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Returns 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": "}" },
+    "stepId": { "index": 18, "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": "}" },
+    "null": { "index": 19, "kind": "function", "displayName": "Null", "group": 
"function", "label": "function", "required": false, "javaType": "Object", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "Represents a null value", "ognl": false, 
"suffix": "}" },
+    "messageAs(type)": { "index": 20, "kind": "function", "displayName": 
"Message As", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Converts the message 
to the given type (classname).", "ognl": true, "suffix": "}" },
+    "bodyAs(type)": { "index": 21, "kind": "function", "displayName": "Body 
As", "group": "function", "label": "function", "required": false, "javaType": 
"Object", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Converts the message body 
to the given type (classname).", "ognl": true, "suffix": "}" },
+    "mandatoryBodyAs(type)": { "index": 22, "kind": "function", "displayName": 
"Mandatory Body As", "group": "function", "label": "function", "required": 
false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Converts the message body to the given type (classname). If the body is null 
then the function will fail with an exception", "ognl": true, "suffix": "}" },
+    "headerAs(key,type)": { "index": 23, "kind": "function", "displayName": 
"Header As", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Converts the message 
header to the given type (classname).", "ognl": false, "suffix": "}" },
+    "headers": { "index": 24, "kind": "function", "displayName": "Headers", 
"group": "function", "label": "function", "required": false, "javaType": 
"java.util.Map", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns all the message 
headers in a Map", "ognl": false, "suffix": "}" },
+    "header.name": { "index": 25, "kind": "function", "displayName": "Header", 
"group": "function", "label": "function", "required": false, "javaType": 
"Object", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The message header with 
the given name", "ognl": true, "suffix": "}" },
+    "variableAs(key,type)": { "index": 26, "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": 27, "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": "}" },
+    "variable.name": { "index": 28, "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": "}" },
+    "exchangeProperty.name": { "index": 29, "kind": "function", "displayName": 
"Exchange Property", "group": "function", "label": "function", "required": 
false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
exchange property with the given name", "ognl": true, "suffix": "}" },
+    "camelContext": { "index": 30, "kind": "function", "displayName": "Camel 
Context", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The Camel Context", 
"ognl": true, "suffix": "}" },
+    "jq(input,exp)": { "index": 31, "kind": "function", "displayName": "JQ", 
"group": "function", "label": "function", "required": false, "javaType": 
"Object", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "When working with JSon 
data, then this allows using the JQ language, for example, to extract data from 
the message body (in JSon format). This requires having camel-jq JAR on the 
classpath. For input (optional), you can [...]
+    "jsonpath(input,exp)": { "index": 32, "kind": "function", "displayName": 
"JSonPath", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "When working with JSon 
data, then this allows using the JSonPath language, for example, to extract 
data from the message body (in JSon format). This requires having 
camel-jsonpath JAR on the classpath. For i [...]
+    "xpath(input,exp)": { "index": 33, "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 [...]
+    "sys.name": { "index": 34, "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": "}" },
+    "env.name": { "index": 35, "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": "}" },
+    "pretty(exp)": { "index": 36, "kind": "function", "displayName": "Pretty 
Print", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Converts the 
expression to a String, and attempts to pretty print if JSon or XML, otherwise 
the expression is returned as the String value.", "ognl": false, "suffix": "}" 
},
+    "date(command)": { "index": 37, "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": 38, "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 [...]
+    "bean(name.method)": { "index": 39, "kind": "function", "displayName": 
"Call Java Bean", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Calls a Java bean. The 
name of the bean can also refer to a class name using type prefix as follows 
`bean:type:com.foo.MyClass`. If no method name is given then Camel will 
automatic attempt to find the b [...]
+    "propertiesExist:key": { "index": 40, "kind": "function", "displayName": 
"Property Placeholder Exists", "group": "function", "label": "function", 
"required": false, "javaType": "boolean", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Checks whether a property placeholder with the given key exists or not. The 
result can be negated by prefixing the key with !", "ognl": false, "suffix": 
"}" },
+    "properties:key:default": { "index": 41, "kind": "function", 
"displayName": "Property Placeholder", "group": "function", "label": 
"function", "required": false, "javaType": "String", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Lookup a property placeholder with the given key. If the 
key does not exist nor has a value, then an optional default value can be 
specified.", "ognl": false, "suffix": "}" },
+    "ref:name": { "index": 42, "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": "}" },
+    "type:name.field": { "index": 43, "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": 44, "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;`  [...]
+    "substring(head,tail)": { "index": 45, "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": 46, "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": 47, "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  [...]
+    "collate(num)": { "index": 48, "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": 49, "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": 50, "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": 51, "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": 52, "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": 53, "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.HashMap`.", "ognl": false [...]
+    "iif(predicate,trueExp,falseExp)": { "index": 54, "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": 
"}" }
   }
 }
diff --git 
a/core/camel-core-languages/src/main/docs/modules/languages/pages/file-language.adoc
 
b/core/camel-core-languages/src/main/docs/modules/languages/pages/file-language.adoc
index bab3431944f..e8ae85b3f78 100644
--- 
a/core/camel-core-languages/src/main/docs/modules/languages/pages/file-language.adoc
+++ 
b/core/camel-core-languages/src/main/docs/modules/languages/pages/file-language.adoc
@@ -60,7 +60,7 @@ directory, see note below)
 
 |file:name.noext.single |String |yes |no |yes |no |refers to the file name 
with no extension (is
 relative to the starting directory, see note below). If the file
-extension has multiple dots, then this expression strips only the last
+name has multiple dots, then this expression strips only the last
 part, and keeps the others.
 
 |file:onlyname |String |yes |no |yes |no |refers to the file name only with no 
leading paths.
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 ac47f5fafee..3182c19c9a5 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
@@ -75,7 +75,7 @@ OGNL expression.
 
 |id |String |the message id
 
-|messageTimestamp |String |the message timestamp (millis since epoc) that this 
message originates from.
+|messageTimestamp |long |the message timestamp (millis since epoc) that this 
message originates from.
 Some systems like JMS, Kafka, AWS have a timestamp on the event/message that 
Camel received. This method returns
 the timestamp if a timestamp exists.
 The message timestamp and exchange created are different. An exchange always 
has a created timestamp which is the
@@ -197,7 +197,7 @@ to a bean class (such as calling a static method), then you 
can prefix with the
 not exist nor has a value, then an optional default value can be
 specified.
 
-|propertiesExist:key |String |Checks whether a property placeholder with the 
given key exists or not.
+|propertiesExist:key |boolean |Checks whether a property placeholder with the 
given key exists or not.
 The result can be negated by prefixing the key with `!`.
 
 |fromRouteId |String |Returns the original route id where this exchange was 
created.
@@ -254,7 +254,7 @@ 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.
 
-|substring(num1,num2,exp) |String |replace all the string values in the given 
expression.
+|substring(num1,num2,exp) |String |returns a substring of the given expression.
 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.
 
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/FileConstants.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/FileConstants.java
new file mode 100644
index 00000000000..d093c39e34b
--- /dev/null
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/FileConstants.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.simple;
+
+import org.apache.camel.spi.Metadata;
+
+@Metadata(label = "function", annotations = { "prefix=${", "suffix=}" })
+public final class FileConstants {
+
+    @Metadata(description = "The file name (relative from starting 
directory)", javaType = "String", label = "function")
+    public static final String FILE_NAME = "file:name";
+    @Metadata(description = "The file name (relative from starting directory) 
without extension", javaType = "String",
+              label = "function")
+    public static final String FILE_NO_EXT = "file:name.noext";
+    @Metadata(description = "The file name (relative from starting directory) 
without extension. If the file name has multiple dots, then this expression 
strips and only returns the last part.",
+              javaType = "String", label = "function")
+    public static final String FILE_NO_EXT_SINGLE = "file:name.noext.single";
+    @Metadata(description = "The file extension", javaType = "String", label = 
"function")
+    public static final String FILE_EXT = "file:name.ext";
+    @Metadata(description = "The file extension. If the file extension has 
multiple dots, then this expression strips and only returns the last part.",
+              javaType = "String", label = "function")
+    public static final String FILE_EXT_SINGLE = "file:name.ext.single";
+    @Metadata(description = "†he file name (without any leading paths)", 
javaType = "String", label = "function")
+    public static final String FILE_ONLY_NAME = "file:onlyname";
+    @Metadata(description = "†he file name (without any leading paths) without 
extension", javaType = "String",
+              label = "function")
+    public static final String FILE_ONLY_NAME_NO_EXT = "file:onlyname.noext";
+    @Metadata(description = "†he file name (without any leading paths) without 
extension. If the file name has multiple dots, then this expression strips and 
only returns the last part.",
+              javaType = "String", label = "function")
+    public static final String FILE_ONLY_NAME_NO_EXT_SINGLE = 
"file:onlyname.noext.single";
+    @Metadata(description = "The file parent directory (null if no parent 
directory)", javaType = "String", label = "function")
+    public static final String FILE_PARENT = "file:parent";
+    @Metadata(description = "The file path", javaType = "String", label = 
"function")
+    public static final String FILE_PATH = "file:path";
+    @Metadata(description = "Whether the file is regarded as absolute or 
relative", javaType = "boolean", label = "function")
+    public static final String FILE_ABSOLUTE = "file:absolute";
+    @Metadata(description = "The absolute file path", javaType = "String", 
label = "function")
+    public static final String FILE_ABSOLUTE_PATH = "file:absolute.path";
+    @Metadata(description = "The size of the file", javaType = "long", label = 
"function")
+    public static final String FILE_LENGTH = "file:length";
+    @Metadata(description = "The size of the file", javaType = "long", label = 
"function")
+    public static final String FILE_SIZE = "file:size";
+    @Metadata(description = "The file modification date", javaType = "long", 
label = "function")
+    public static final String FILE_MODIFIED = "file:modified";
+}
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/FileLanguage.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/FileLanguage.java
index 83b535c9f82..f579745e989 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/FileLanguage.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/FileLanguage.java
@@ -21,7 +21,7 @@ import org.apache.camel.spi.annotations.Language;
 /**
  * The Camel file language.
  */
-@Language("file")
+@Language(value = "file", functionsClass = FileConstants.class)
 public class FileLanguage extends SimpleLanguage {
 
     public FileLanguage() {
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
new file mode 100644
index 00000000000..a4be0023117
--- /dev/null
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleConstants.java
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.simple;
+
+import org.apache.camel.spi.Metadata;
+
+@Metadata(label = "function", annotations = { "prefix=${", "suffix=}" })
+public final class SimpleConstants {
+
+    @Metadata(description = "The message body", javaType = "Object", label = 
"function,ognl")
+    public static final String BODY = "body";
+    @Metadata(description = "Converts the body to a String, and attempts to 
pretty print if JSon or XML; otherwise the body is returned as the String 
value.",
+              javaType = "String", label = "function")
+    public static final String PRETTY_BODY = "prettyBody";
+    @Metadata(description = "Converts the body to a String and removes all 
line-breaks, so the string is in one line.",
+              javaType = "String", label = "function")
+    public static final String BODY_ONE_LINE = "bodyOneLine";
+    @Metadata(description = "The original incoming body (only available if 
allowUseOriginalMessage=true).", javaType = "Object",
+              label = "function")
+    public static final String ORIGINAL_BODY = "originalBody";
+    @Metadata(description = "The message id", javaType = "String", label = 
"function")
+    public static final String ID = "id";
+    @Metadata(description = "The message timestamp (millis since epoc) that 
this message originates from."
+                            + " Some systems like JMS, Kafka, AWS have a 
timestamp on the event/message that Camel received. This method returns the 
timestamp if a timestamp exists."
+                            + " The message timestamp and exchange created are 
different. An exchange always has a created timestamp which is the"
+                            + " local timestamp when Camel created the 
exchange. The message timestamp is only available in some Camel components"
+                            + " when the consumer is able to extract the 
timestamp from the source event."
+                            + " If the message has no timestamp, then 0 is 
returned.",
+              javaType = "long", label = "function")
+    public static final String MESSAGE_TIMESTAMP = "messageTimestamp";
+    @Metadata(description = "The exchange id", javaType = "String", label = 
"function")
+    public static final String EXCHANGE_ID = "exchangeId";
+    @Metadata(description = "The current exchange", javaType = 
"org.apache.camel.Exchange", label = "function,ognl")
+    public static final String EXCHANGE = "exchange";
+    @Metadata(description = "The exception object on the exchange (also from 
caught exceptions), is null if no exception present.",
+              javaType = "java.lang.Exception", label = "function,ognl")
+    public static final String EXCEPTION = "exception";
+    @Metadata(description = "The exception message (also from caught 
exceptions), is null if no exception present.",
+              javaType = "String", label = "function", displayName = 
"Exception Message")
+    public static final String EXCEPTION_MESSAGE = "exception.message";
+    @Metadata(description = "The exception stacktrace (also from caught 
exceptions), is null if no exception present.",
+              javaType = "String", label = "function", displayName = 
"Exception Stacktrace")
+    public static final String EXCEPTION_STACKTRACE = "exception.stackTrace";
+    @Metadata(description = "Returns the id of the current thread. Can be used 
for logging.", javaType = "long",
+              label = "function")
+    public static final String THREAD_ID = "threadId";
+    @Metadata(description = "Returns the name of the current thread. Can be 
used for logging.", javaType = "String",
+              label = "function")
+    public static final String THREAD_NAME = "threadName";
+    @Metadata(description = "Returns the local hostname (may be empty if not 
possible to resolve).", javaType = "String",
+              label = "function")
+    public static final String HOST_NAME = "hostName";
+    @Metadata(description = "The name of the CamelContext", javaType = 
"String", label = "function")
+    public static final String CAMEL_ID = "camelId";
+    @Metadata(description = "The route id of the current route the Exchange is 
being routed", javaType = "String",
+              label = "function")
+    public static final String ROUTE_ID = "routeId";
+    @Metadata(description = "The original route id where this exchange was 
created.", javaType = "String", label = "function")
+    public static final String FROM_ROUTE_ID = "fromRouteId";
+    @Metadata(description = "Returns 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";
+    @Metadata(description = "Returns the id of the current step the Exchange 
is being routed.", javaType = "String",
+              label = "function")
+    public static final String STEP_ID = "stepId";
+    @Metadata(description = "Represents a null value", label = "function", 
javaType = "Object")
+    public static final String NULL = "null";
+    @Metadata(description = "Converts the message to the given type 
(classname).", label = "function,ognl", javaType = "Object")
+    public static final String MESSAGE_AS = "messageAs(type)";
+    @Metadata(description = "Converts the message body to the given type 
(classname).", label = "function,ognl",
+              javaType = "Object")
+    public static final String BODY_AS = "bodyAs(type)";
+    @Metadata(description = "Converts the message body to the given type 
(classname). If the body is null then the function will fail with an exception",
+              label = "function,ognl", javaType = "Object")
+    public static final String MANDATORY_BODY_AS = "mandatoryBodyAs(type)";
+    @Metadata(description = "Converts the message header to the given type 
(classname).", label = "function",
+              javaType = "Object")
+    public static final String HEADER_AS = "headerAs(key,type)";
+    @Metadata(description = "Returns all the message headers in a Map", label 
= "function", javaType = "java.util.Map")
+    public static final String HEADERS = "headers";
+    @Metadata(description = "The message header with the given name", label = 
"function,ognl", javaType = "Object")
+    public static final String HEADER = "header.name";
+    @Metadata(description = "Converts the variable to the given type 
(classname).", label = "function", javaType = "Object")
+    public static final String VARIABLE_AS = "variableAs(key,type)";
+    @Metadata(description = "Returns all the variables from the current 
Exchange in a Map", label = "function",
+              javaType = "java.util.Map")
+    public static final String VARIABLES = "variables";
+    @Metadata(description = "The variable with the given name", label = 
"function,ognl", javaType = "Object")
+    public static final String VARIABLE = "variable.name";
+    @Metadata(description = "The exchange property with the given name", label 
= "function,ognl", javaType = "Object")
+    public static final String EXCHANGE_PROPERTY = "exchangeProperty.name";
+    @Metadata(description = "The Camel Context", label = "function,ognl", 
javaType = "Object")
+    public static final String CAMEL_CONTEXT = "camelContext";
+    @Metadata(description = "When working with JSon data, then this allows 
using the JQ language, for example, to extract data from the message body (in 
JSon format). This requires having camel-jq JAR on the classpath."
+                            + " For input (optional), you can choose 
`header:key`, `exchangeProperty:key` or `variable:key` to use as input for the 
JSon payload instead of the message body.",
+              label = "function", javaType = "Object", displayName = "JQ")
+    public static final String JQ = "jq(input,exp)";
+    @Metadata(description = "When working with JSon data, then this allows 
using the JSonPath language, for example, to extract data from the message body 
(in JSon format). This requires having camel-jsonpath JAR on the classpath."
+                            + " For input (optional), you can choose 
`header:key`, `exchangeProperty:key` or `variable:key` to use as input for the 
JSon payload instead of the message body.",
+              label = "function", javaType = "Object", displayName = 
"JSonPath")
+    public static final String JSONPATH = "jsonpath(input,exp)";
+    @Metadata(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), you can choose 
`header:key`, `exchangeProperty:key` or `variable:key` to use as input for the 
XML payload instead of the message body.",
+              label = "function", javaType = "Object", displayName = "XPath")
+    public static final String XPATH = "xpath(input,exp)";
+    @Metadata(description = "The JVM system property with the given name", 
label = "function", javaType = "Object",
+              displayName = "JVM System Property")
+    public static final String SYS = "sys.name";
+    @Metadata(description = "The OS environment variable with the given name", 
label = "function", javaType = "Object",
+              displayName = "OS Environment Variable")
+    public static final String ENV = "env.name";
+    @Metadata(description = "Converts the expression to a String, and attempts 
to pretty print if JSon or XML, otherwise the expression is returned as the 
String value.",
+              label = "function", javaType = "String", displayName = "Pretty 
Print")
+    public static final String PRETTY = "pretty(exp)";
+    @Metadata(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 object in 
the header with the key xxx."
+                            + " `variable.xxx` to use the Long/Date in the 
variable with the key xxx."
+                            + " `exchangeProperty.xxx` to use the Long/Date 
object in the exchange property with the key xxx."
+                            + " `file` for the last modified timestamp of the 
file (available with a File consumer)."
+                            + " Command accepts offsets such as: `now-24h` or 
`header.xxx+1h` or even `now+1h30m-100`.",
+              label = "function", javaType = "java.util.Date", displayName = 
"Parse Date")
+    public static final String DATE = "date(command)";
+    @Metadata(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 timestamp when the 
current exchange was created,"
+                            + " `header.xxx` to use the Long/Date object in 
the header with the key xxx."
+                            + " `variable.xxx` to use the Long/Date in the 
variable with the key xxx."
+                            + " `exchangeProperty.xxx` to use the Long/Date 
object in the exchange property with the key xxx."
+                            + " `file` for the last modified timestamp of the 
file (available with a File consumer)."
+                            + " Command accepts offsets such as: `now-24h` or 
`header.xxx+1h` or even `now+1h30m-100`.",
+              label = "function", javaType = "String", displayName = "Date 
Formatter")
+    public static final String DATE_WITH_TIMEZONE = 
"date-with-timezone(command:timezone:pattern)";
+    @Metadata(description = "Calls a Java bean."
+                            + " The name of the bean can also refer to a class 
name using type prefix as follows `bean:type:com.foo.MyClass`."
+                            + " If no method name is given then Camel will 
automatic attempt to find the best method to use.",
+              label = "function", javaType = "Object", displayName = "Call 
Java Bean")
+    public static final String BEAN = "bean(name.method)";
+    @Metadata(description = "Checks whether a property placeholder with the 
given key exists or not. The result can be negated by prefixing the key with !",
+              label = "function", javaType = "boolean", displayName = 
"Property Placeholder Exists")
+    public static final String PROPERTIES_EXIST = "propertiesExist:key";
+    @Metadata(description = "Lookup a property placeholder with the given key. 
If the key does not exist nor has a value, then an optional default value can 
be specified.",
+              label = "function", javaType = "String", displayName = "Property 
Placeholder")
+    public static final String PROPERTIES = "properties:key:default";
+    @Metadata(description = "To look up a bean from the Registry with the 
given name.", label = "function", javaType = "Object",
+              displayName = "Bean By Id")
+    public static final String REF = "ref:name";
+    @Metadata(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`",
+              label = "function", javaType = "Object", displayName = "Java 
Field Value")
+    public static final String TYPE = "type:name.field";
+    @Metadata(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;` as single quote, and `\\&empty;` as empty value.",
+              label = "function", javaType = "String", displayName = "Replace 
String Values")
+    public static final String REPLACE = "replace(from,to,exp)";
+    @Metadata(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 from the beginning."
+                            + " 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 random number between min (included) 
and max (excluded).", label = "function",
+              javaType = "int", displayName = "Generate Random Number")
+    public static final String RANDOM = "random(min,max)";
+    @Metadata(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 items.",
+              label = "function", javaType = "java.util.Iterator", displayName 
= "Skip First Items from the Message Body")
+    public static final String SKIP = "skip(num)";
+    @Metadata(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/batch"
+                            + " the split sub message into a group of N sub 
lists.",
+              label = "function", javaType = "java.util.Iterator", displayName 
= "Group Message Body into Sub Lists")
+    public static final String COLLATE = "collate(num)";
+    @Metadata(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. It is possible to refer to another"
+                            + " source (simple language) such as a header via 
the exp parameter. For example `join('&','id=','$\\{header.ids}')`.",
+              label = "function", javaType = "String")
+    public static final String JOIN = "join(separator,prefix,exp)";
+    @Metadata(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 boolean can be used to turn off detailed 
information to be less verbose, and avoid printing sensitive data from the 
message.",
+              label = "function", javaType = "String", displayName = "Print 
Message History")
+    public static final String MESSAGE_HISTORY = "messageHistory(boolean)";
+    @Metadata(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 `UuidGenerator`"
+                            + " and bind the bean to the 
xref:manual::registry.adoc[Registry] with an id. For example 
`${uuid(myGenerator)}`"
+                            + " where the ID is _myGenerator_.",
+              label = "function", javaType = "String", displayName = "Generate 
UUID")
+    public static final String UUID = "uuid(type)";
+    @Metadata(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.",
+              label = "function", javaType = "String", displayName = "Compute 
Hash Value")
+    public static final String HASH = "hash(exp,algorithm)";
+    @Metadata(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.HashMap`.",
+              label = "function", javaType = "Object", displayName = "Create 
Empty Object")
+    public static final String EMPTY = "empty(type)";
+    @Metadata(description = "Evaluates the predicate and returns the value of 
trueExp or falseExp. This function is similar to the ternary operator in Java.",
+              label = "function", javaType = "Object", displayName = "If Then 
Else")
+    public static final String IIF = "iif(predicate,trueExp,falseExp)";
+}
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleLanguage.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleLanguage.java
index 723c34b3e2d..85c4b07d7bf 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleLanguage.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleLanguage.java
@@ -37,7 +37,7 @@ import org.slf4j.LoggerFactory;
 /**
  * The Camel simple language.
  */
-@Language("simple")
+@Language(value = "simple", functionsClass = SimpleConstants.class)
 public class SimpleLanguage extends LanguageSupport implements StaticService {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(SimpleLanguage.class);
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/support/Schema.java
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/support/Schema.java
index fab0841b324..864c83c73b7 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/support/Schema.java
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/support/Schema.java
@@ -31,6 +31,8 @@ public class Schema {
     public ObjectNode properties;
     @JsonIgnore
     public ObjectNode exchangeProperties;
+    @JsonProperty
+    public ObjectNode functions;
 
     public Schema() {
     }
diff --git 
a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/JsonMapper.java
 
b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/JsonMapper.java
index 9cfd4e4ed36..249e1951cbc 100644
--- 
a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/JsonMapper.java
+++ 
b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/JsonMapper.java
@@ -413,6 +413,10 @@ public final class JsonMapper {
         JsonObject wrapper = new JsonObject();
         wrapper.put("language", obj);
         wrapper.put("properties", asJsonObject(model.getOptions()));
+        final List<LanguageModel.LanguageFunctionModel> functions = 
model.getFunctions();
+        if (!functions.isEmpty()) {
+            wrapper.put("functions", asJsonObjectFunctions(functions));
+        }
         return wrapper;
     }
 
@@ -599,6 +603,24 @@ public final class JsonMapper {
         return json;
     }
 
+    public static JsonObject 
asJsonObjectFunctions(List<LanguageModel.LanguageFunctionModel> options) {
+        JsonObject json = new JsonObject();
+        for (int i = 0; i < options.size(); i++) {
+            var o = options.get(i);
+            o.setIndex(i);
+            JsonObject jo = asJsonObject(o);
+            jo.put("ognl", o.isOgnl());
+            if (o.getPrefix() != null) {
+                jo.put("prefix", o.getPrefix());
+            }
+            if (o.getSuffix() != null) {
+                jo.put("suffix", o.getSuffix());
+            }
+            json.put(o.getName(), jo);
+        }
+        return json;
+    }
+
     public static JsonObject apiModelAsJsonObject(Collection<ApiModel> model, 
boolean options) {
         JsonObject root = new JsonObject();
         model.forEach(a -> {
diff --git 
a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/LanguageModel.java
 
b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/LanguageModel.java
index f4bb4ddb395..36fd690f6f0 100644
--- 
a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/LanguageModel.java
+++ 
b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/LanguageModel.java
@@ -16,10 +16,14 @@
  */
 package org.apache.camel.tooling.model;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class LanguageModel extends 
ArtifactModel<LanguageModel.LanguageOptionModel> {
 
     protected String modelName;
     protected String modelJavaType;
+    protected final List<LanguageFunctionModel> functions = new ArrayList<>();
 
     public static class LanguageOptionModel extends BaseOptionModel {
 
@@ -48,4 +52,70 @@ public class LanguageModel extends 
ArtifactModel<LanguageModel.LanguageOptionMod
     public void setModelJavaType(String modelJavaType) {
         this.modelJavaType = modelJavaType;
     }
+
+    public List<LanguageFunctionModel> getFunctions() {
+        return functions;
+    }
+
+    public void addFunction(LanguageFunctionModel function) {
+        functions.add(function);
+    }
+
+    public static class LanguageFunctionModel extends BaseOptionModel {
+
+        /**
+         * The name of the constant that defines the function.
+         */
+        private String constantName;
+
+        /**
+         * Whether this function allows to do OGNL method calls.
+         */
+        boolean ognl;
+
+        /**
+         * Optional prefix for the function
+         */
+        private String prefix;
+
+        /**
+         * Optional suffix for the function
+         */
+        private String suffix;
+
+        public String getConstantName() {
+            return constantName;
+        }
+
+        public void setConstantName(String constantName) {
+            this.constantName = constantName;
+        }
+
+        public boolean isOgnl() {
+            return ognl;
+        }
+
+        public void setOgnl(boolean ognl) {
+            this.ognl = ognl;
+        }
+
+        @Override
+        public String getPrefix() {
+            return prefix;
+        }
+
+        @Override
+        public void setPrefix(String prefix) {
+            this.prefix = prefix;
+        }
+
+        public String getSuffix() {
+            return suffix;
+        }
+
+        public void setSuffix(String suffix) {
+            this.suffix = suffix;
+        }
+    }
+
 }
diff --git 
a/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/Strings.java
 
b/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/Strings.java
index f6670e6be27..25dbb75006f 100644
--- 
a/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/Strings.java
+++ 
b/tooling/camel-tooling-util/src/main/java/org/apache/camel/tooling/util/Strings.java
@@ -69,6 +69,22 @@ public final class Strings {
         return text.substring(index + after.length());
     }
 
+    /**
+     * Returns the string after the given token
+     *
+     * @param  text         the text
+     * @param  after        the token
+     * @param  defaultValue the default value
+     * @return              the text after the token, or default value if text 
does not contain the token
+     */
+    public static String after(String text, String after, String defaultValue) 
{
+        int index = text.indexOf(after);
+        if (index < 0) {
+            return defaultValue;
+        }
+        return text.substring(index + after.length());
+    }
+
     /**
      * Returns the canonical class name by removing any generic type 
information.
      */
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/AbstractGenerateConfigurerMojo.java
 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/AbstractGenerateConfigurerMojo.java
index 504f774d1b2..f76a3e6fc3c 100644
--- 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/AbstractGenerateConfigurerMojo.java
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/AbstractGenerateConfigurerMojo.java
@@ -518,4 +518,14 @@ public abstract class AbstractGenerateConfigurerMojo 
extends AbstractGeneratorMo
         return false;
     }
 
+    private static String asString(AnnotationInstance ai, String name) {
+        if (ai != null) {
+            AnnotationValue av = ai.value(name);
+            if (av != null) {
+                return av.asString();
+            }
+        }
+        return null;
+    }
+
 }
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageLanguageMojo.java
 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageLanguageMojo.java
index 3a7d4eb9d37..81b8adf5b0c 100644
--- 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageLanguageMojo.java
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageLanguageMojo.java
@@ -18,6 +18,7 @@ package org.apache.camel.maven.packaging;
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.Field;
 import java.nio.file.Path;
 import java.util.Collections;
 import java.util.HashMap;
@@ -26,7 +27,9 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import org.apache.camel.maven.packaging.generics.ClassUtil;
+import org.apache.camel.maven.packaging.generics.PackagePluginUtils;
 import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.annotations.Language;
 import org.apache.camel.tooling.model.EipModel;
 import org.apache.camel.tooling.model.EipModel.EipOptionModel;
 import org.apache.camel.tooling.model.JsonMapper;
@@ -34,6 +37,7 @@ import org.apache.camel.tooling.model.LanguageModel;
 import org.apache.camel.tooling.model.LanguageModel.LanguageOptionModel;
 import org.apache.camel.tooling.model.SupportLevel;
 import org.apache.camel.tooling.util.PackageHelper;
+import org.apache.camel.tooling.util.Strings;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugin.logging.Log;
@@ -42,6 +46,10 @@ import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
 import org.codehaus.plexus.build.BuildContext;
+import org.jboss.jandex.DotName;
+import org.jboss.jandex.IndexView;
+
+import static java.lang.reflect.Modifier.isStatic;
 
 /**
  * Analyses the Camel plugins in a project and generates extra descriptor 
information for easier auto-discovery in
@@ -50,6 +58,9 @@ import org.codehaus.plexus.build.BuildContext;
 @Mojo(name = "generate-languages-list", threadSafe = true)
 public class PackageLanguageMojo extends AbstractGeneratorMojo {
 
+    private static final DotName LANGUAGE = 
DotName.createSimple(Language.class.getName());
+    private IndexView indexView;
+
     /**
      * The output directory for generated languages file
      */
@@ -162,7 +173,7 @@ public class PackageLanguageMojo extends 
AbstractGeneratorMojo {
                         SchemaHelper.addModelMetadata(languageModel, project);
                         SchemaHelper.addModelMetadata(languageModel, 
javaType.getAnnotation(Metadata.class));
 
-                        // build json schema for the data format
+                        // build json schema for the language
                         String schema = 
JsonMapper.createParameterJsonSchema(languageModel);
                         if (log.isDebugEnabled()) {
                             log.debug("JSON schema\n" + schema);
@@ -203,7 +214,7 @@ public class PackageLanguageMojo extends 
AbstractGeneratorMojo {
         return count;
     }
 
-    protected static LanguageModel extractLanguageModel(MavenProject project, 
String json, String name, Class<?> javaType) {
+    protected LanguageModel extractLanguageModel(MavenProject project, String 
json, String name, Class<?> javaType) {
         EipModel def = JsonMapper.generateEipModel(json);
         LanguageModel model = new LanguageModel();
         model.setName(name);
@@ -258,9 +269,86 @@ public class PackageLanguageMojo extends 
AbstractGeneratorMojo {
             option.setDescription(opt.getDescription());
             model.addOption(option);
         }
+
+        // read class and find functionClass and add each field as a function 
in the model
+        Class<?> classElement = loadClass(javaType.getName());
+        final Language lan = classElement.getAnnotation(Language.class);
+        if (lan.functionsClass() != void.class) {
+            classElement = loadClass(lan.functionsClass().getName());
+            if (classElement != null) {
+                for (Field field : classElement.getFields()) {
+                    final boolean isEnum = classElement.isEnum();
+                    if ((isEnum || isStatic(field.getModifiers()) && 
field.getType() == String.class)
+                            && field.isAnnotationPresent(Metadata.class)) {
+                        try {
+                            addFunction(model, field);
+                        } catch (Exception e) {
+                            getLog().warn(e);
+                        }
+                    }
+                }
+            }
+        }
+
         return model;
     }
 
+    private void addFunction(LanguageModel model, Field field) throws 
Exception {
+        final Class<?> declaringClass = field.getDeclaringClass();
+        final Metadata cm = declaringClass.getAnnotation(Metadata.class);
+        String prefix = null;
+        String suffix = null;
+        if (cm != null && cm.annotations() != null) {
+            for (String s : cm.annotations()) {
+                prefix = Strings.after(s, "prefix=", prefix);
+                suffix = Strings.after(s, "suffix=", suffix);
+            }
+        }
+        final Metadata metadata = field.getAnnotation(Metadata.class);
+        LanguageModel.LanguageFunctionModel fun = new 
LanguageModel.LanguageFunctionModel();
+        fun.setConstantName(String.format("%s#%s", declaringClass.getName(), 
field.getName()));
+        fun.setName((String) field.get(null));
+        fun.setPrefix(prefix);
+        fun.setSuffix(suffix);
+        fun.setDescription(metadata.description().trim());
+        fun.setKind("function");
+        String displayName = metadata.displayName();
+        // compute a display name if we don't have anything
+        if (Strings.isNullOrEmpty(displayName)) {
+            displayName = fun.getName();
+            int pos = displayName.indexOf('(');
+            if (pos == -1) {
+                pos = displayName.indexOf(':');
+            }
+            if (pos == -1) {
+                pos = displayName.indexOf('.');
+            }
+            if (pos != -1) {
+                displayName = displayName.substring(0, pos);
+            }
+            displayName = displayName.replace('-', ' ');
+            displayName = Strings.asTitle(displayName);
+        }
+        fun.setDisplayName(displayName);
+        fun.setJavaType(metadata.javaType());
+        fun.setRequired(metadata.required());
+        fun.setDefaultValue(metadata.defaultValue());
+        fun.setDeprecated(field.isAnnotationPresent(Deprecated.class));
+        fun.setDeprecationNote(metadata.deprecationNote());
+        fun.setSecret(metadata.secret());
+        String label = metadata.label();
+        boolean ognl = false;
+        if (label.contains(",ognl")) {
+            ognl = true;
+            label = label.replace(",ognl", "");
+        }
+        String group = EndpointHelper.labelAsGroupName(label, false, false);
+        fun.setGroup(group);
+        fun.setLabel(label);
+        fun.setOgnl(ognl);
+        model.addFunction(fun);
+    }
+
     private static String readClassFromCamelResource(File file, StringBuilder 
buffer, BuildContext buildContext)
             throws MojoExecutionException {
         // skip directories as there may be a sub .resolver directory such as 
in
@@ -326,4 +414,11 @@ public class PackageLanguageMojo extends 
AbstractGeneratorMojo {
         return "META-INF/" + pckName.replace('.', '/');
     }
 
+    private IndexView getIndex() {
+        if (indexView == null) {
+            indexView = PackagePluginUtils.readJandexIndexQuietly(project);
+        }
+        return indexView;
+    }
+
 }
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/generics/ClassUtil.java
 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/generics/ClassUtil.java
index f15d3c1c401..6616cbcbbdd 100644
--- 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/generics/ClassUtil.java
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/generics/ClassUtil.java
@@ -81,8 +81,7 @@ public final class ClassUtil {
      * type otherwise it return the casted {@link Class} of the type argument.
      * </p>
      *
-     * @param  type class or parametrized type
-     * @return
+     * @param type class or parametrized type
      */
     public static Class<?> getClass(Type type) {
         return getClazz(type);
@@ -209,4 +208,5 @@ public final class ClassUtil {
                 .map(annotation -> annotation.annotationType().getName())
                 .anyMatch(fqAnnotationName::equals);
     }
+
 }
diff --git 
a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/Language.java
 
b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/Language.java
index 1a986577836..a619f4e481e 100644
--- 
a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/Language.java
+++ 
b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/Language.java
@@ -30,4 +30,17 @@ public @interface Language {
 
     String value();
 
+    /**
+     * The class that contains all the name of functions that are supported by 
the language. The name of the functions
+     * are defined as {@code String} constants in the functions class.
+     * <p/>
+     * The class to provide can be any class but by convention, we would 
expect a class whose name is of type
+     * <i>xxxConstants</i> where <i>xxx</i> is the name of the corresponding 
language like for example
+     * <i>SimpleConstants</i> for the language <i>camel-simple</i>.
+     * <p/>
+     * The metadata of a given functions are retrieved directly from the 
annotation {@code @Metadata} added to the
+     * {@code String} constant representing its name and defined in the 
functions class.
+     */
+    Class<?> functionsClass() default void.class;
+
 }

Reply via email to