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 fb994907fd51 CAMEL-22894: simple - extract direct and misc function
factories
fb994907fd51 is described below
commit fb994907fd519ec151bba3505fc7eacafd06e186
Author: Adriano Machado <[email protected]>
AuthorDate: Tue May 26 01:21:13 2026 -0400
CAMEL-22894: simple - extract direct and misc function factories
Extract DirectFunctionFactory (exact-match keyword functions like id,
exchangeId, exception, null, body) and MiscFunctionFactory (utility
functions like isEmpty, isNumeric, not, convertTo, uuid, hash, iif, load)
from SimpleFunctionExpression, reducing it from ~1700 to ~1000 lines.
Includes 63 unit tests for both factories and fixes 15 documentation
errors in simple-language.adoc (wrong function names, missing parens,
copy-paste mistakes, JSon->JSON normalization).
Closes #23445
---
.../modules/languages/pages/simple-language.adoc | 119 ++--
.../language/simple/SimpleFunctionDispatcher.java | 4 +-
.../simple/ast/SimpleFunctionExpression.java | 739 +--------------------
.../simple/functions/DirectFunctionFactory.java | 119 ++++
.../simple/functions/MiscFunctionFactory.java | 550 +++++++++++++++
.../functions/DirectFunctionFactoryTest.java | 181 +++++
.../simple/functions/MiscFunctionFactoryTest.java | 266 ++++++++
docs/local-build.sh | 10 +-
8 files changed, 1215 insertions(+), 773 deletions(-)
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 5e9feaee135b..d9c36382d051 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
@@ -392,7 +392,7 @@ The `isEmpty` is primary for checking if a value is either
`null` or empty strin
The `isAlpha` / `isAlphaNumeric` and `isNumeric` is for checking if a value
only contains `A..Z` or `A.Z0..9`, or `0..9` characters.
Camel will use from the JDK `Character.isLetter` /
`Character.isLetterOrDigit`, or `Character.isDigit` methods internally.
-So `${isAlpha('Hello World'}` will actually return `false` because there is a
whitespace. However `${isAlpha('HelloWorld'}` returns `true`.
+So `${isAlpha('Hello World')}` will actually return `false` because there is a
whitespace. However `${isAlpha('HelloWorld')}` returns `true`.
TIP: You can use the `regex` operator to use regular expressions for more
advanced tests.
@@ -408,8 +408,8 @@ The date functions is used for parsing and formatting with
date and times.
|Function |Response Type |Description
|`date:millis` | `long` | Returns the current timestamp as millis in unix
epoch.
|`date:command` | `Date` | 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 (on [...]
-|`date:command:pattern` | `String` | Date formatting using
`java.text.SimpleDateFormat` patterns. See `data:command` function for
additional documentation on the commands.
-|`date-with-timezone:command:timezone:pattern` | `String` | Date formatting
using `java.text.SimpleDateFormat` timezones and patterns. See `data:command`
function for additional documentation on the commands.
+|`date:command:pattern` | `String` | Date formatting using
`java.text.SimpleDateFormat` patterns. See `date:command` function for
additional documentation on the commands.
+|`date-with-timezone:command:timezone:pattern` | `String` | Date formatting
using `java.text.SimpleDateFormat` timezones and patterns. See `date:command`
function for additional documentation on the commands.
|====
For example to get the current time use `${date:now}` which is returned as a
`java.util.Date` object.
@@ -449,13 +449,13 @@ The `abs` function returns the absolute value of a
numeric value. It converts th
A few examples `${abs(-5)}` returns `5`, and `${abs(5)}` also returns `5`.
The `average` function calculates the average (mean) of integral numbers (not
floating point).
-Assume message body is `[10, 20, 30]` (as `List<Integer>` or similar) then
`${avg()}` results in `20`
+Assume message body is `[10, 20, 30]` (as `List<Integer>` or similar) then
`${average()}` results in `20`
The `ceil` functions returns the value of number rounded up to the nearest
integer that is greater than or equal to number.
For example `${ceil(5.7)}` returns `6`, and `${ceil(5.1)}` also returns `6`.
The `floor` functions returns the value of number rounded down to the nearest
integer that is smaller or equal to number.
-For example `${ceil(5.7)}` returns `5`, and `${ceil(5.1)}` also returns `5`.
+For example `${floor(5.7)}` returns `5`, and `${floor(5.1)}` also returns `5`.
The `max` and `min` functions in are used to find the maximum or minimum value
among a set of numeric integral values.
For example message body contains a list `[10, 5, 30, 15]` then `${max()}`
returns `30` and `${min()}` returns `5`.
@@ -469,7 +469,7 @@ For example `${range(10)}` returns the numbers `0..9`. And
`${range(1,10)}` retu
The `sum` function adds up numeric values (not floating point) and returns the
result as a long.
Assume message body is `[10, 20, 30]` (as `List<Integer>` or similar) then
`${sum()}` results in `60`
You can also use the `sum` function to add or subtract numbers. For example if
you want to add 2 to a number, you can do
-`$sum($\{body},2)}`, and likewise to subtract you use negative number, such as
`$sum($\{body},-2)}`.
+`${sum($\{body},2)}`, and likewise to subtract you use negative number, such
as `${sum($\{body},-2)}`.
=== Other Functions
@@ -484,7 +484,7 @@ Other kind of functions.
|`load(file)` | `String` | Loads the content of the resource from classpath
(cannot load from file-system to avoid dangerous situations).
|`null` | `null` | Returns a `null` value.
|`sys.key` | `String` | *Deprecated* To lookup the JVM system property with
the given key.
-|`sysenv.key` | `String` | To lookup the JVM system property with the given
key.
+|`sysenv.key` | `String` | To lookup the OS environment variable with the
given key.
|`threadId` | `String` | Returns the id of the current thread.
|`threadName` | `String` | Returns the name of the current thread.
|`uuid(kind)` | `String` | Returns a UUID using the Camel `UuidGenerator`. You
can choose kind between `default`, `classic`, `short`, `simple` and `random` as
the kind. If no kind is given, then `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`.
@@ -500,7 +500,7 @@ The `hostname` function returns the OS hostname and does
not require using paren
The `null` function returns a `null` value such as `$\{null}`.
-To use JVM system properties you use the `${sysenv.key}` function, such as
`${sysenv.java.version}` or `${sysenv.java.io.tmpdir}`.
+To use OS environment variables you can also use the `${sysenv.key}` function
(an alias for `${env.key}`), such as `${sysenv.PATH}` or `${sysenv.HOME}`.
You can get the current thread id by the `$\{threadId}` function, and the name
via `$\{threadName}`.
@@ -570,7 +570,7 @@ To use semicolon as separator you would use `${join(;)}`.
The `prefix` argument
`${join(&,id=)}` would return `id=A&id=B&id=C`.
The `lowercase` and `uppercase` functions are as the name implies used for
lower and uppercasing.
-So `${lowercase('Hello World`)}` returns `hello world` and `${uppercase('Hello
World`)}` returns `HELLO WORLD`.
+So `${lowercase('Hello World')}` returns `hello world` and `${uppercase('Hello
World')}` returns `HELLO WORLD`.
You can use the `normalizeWhitespace` function to _clean up_ a value by
removing extra whitespaces. This is done by ensuring that
there are exactly only 1 whitespace between words. And as well trimming the
value for empty whitespace
@@ -579,7 +579,7 @@ in the beginning and end. Suppose the message body is a
String value with `" H
The `pad` function returns a copy of the string with extra padding, if
necessary, so that its total number of characters is at least the absolute
value of the width parameter.
If width is a positive number, then the string is padded to the right; if
negative, it is padded to the left.
The optional separator specifies the padding character(s) to use. If not
specified, it defaults to the space character.
-If the message body contains `foo` then `${pad(5)}` return `"foo "` and
`${pad(-5)}` returns `" foo"`, and `${pad(-5,'@')}` returns `@@foo`.
+If the message body contains `foo` then `${pad($\{body},5)}` returns `"foo "`
and `${pad($\{body},-5)}` returns `" foo"`, and `${pad($\{body},-5,'@')}`
returns `@@foo`.
The `replace` function is used for finding a given text in a string and
replacing it with another.
For example the message body contains `Hello a how are you`, then
`${replace(a,b)}` returns `Hello b how bre you`.
@@ -610,9 +610,9 @@ And using `${quote('Hi from me')}` then `"Hi from me"` is
returned.
The `safeQuote` function is quoting the value depending on the value type
(uses the same logic as `kindOfType` function). In essence values that are
null, boolean or numbers are not quoted,
-while everything else is. The `safeQuote` function is useful when working with
JSon data.
+while everything else is. The `safeQuote` function is useful when working with
JSON data.
-For example when doing JSon to JSon mapping you can extract values form the
source document,
+For example when doing JSON to JSON mapping you can extract values form the
source document,
to be included in the output, but the values may or may not need to be quoted.
Then you can use the `~>` chain operator
to call the `safeQuote` function as shown below:
@@ -625,34 +625,34 @@ to call the `safeQuote` function as shown below:
----
-=== XML & JSon Functions
+=== XML & JSON Functions
-Functions to work with XML and JSon payloads.
+Functions to work with XML and JSON payloads.
[width="100%",cols="10%,10%,80%",options="header",]
|====
|Function |Response Type |Description
-|`jq(exp)` | `Object` | 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.
-|`jq(input,exp)` | `Object` | Same as `jq(exp)` but to use the _input_
expression as the source of the JSon document.
-|`jsonpath(exp)` | `Object` | 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.
-|`jsonpath(input,exp)` | `Object` | Same as `jsonpath(exp)` but to use the
_input_ expression as the source of the JSon document.
-|`pretty(exp)` | `String` | Converts the expression to a `String`, and
attempts to pretty print (if JSon or XML) otherwise return the value as-is.
-|`prettyBody` | `String` | Converts the message body to a `String`, and
attempts to pretty print (if JSon or XML) otherwise return the value as-is.
-|`simpleJsonpath(exp)` | `Object` | When working with JSon data, then this
allows using built-in Simple JsonPath, for example, to extract data from the
message body (in JSon format).
-|`simpleJsonpath(input,exp)` | `Object` | Same as `simpleJsonpath(exp)` but to
use the _input_ expression as the source of the JSon document.
-|`toJson(exp)` | `String` | Converts the expression to a JSon `String`
representation. String values are returned as-is, null values return null, all
other types are serialized to JSon.
-|`toJsonBody` | `String` | Converts the message body to a JSon `String`
representation. String values are returned as-is, null values return null, all
other types are serialized to JSon.
-|`toPrettyJson(exp)` | `String` | Converts the expression to a JSon `String`
representation. String values are returned as-is, null values return null, all
other types are serialized to JSon in pretty mode.
-|`toPrettyJsonBody` | `String` | Converts the message body to a JSon `String`
representation. String values are returned as-is, null values return null, all
other types are serialized to JSon in pretty mode.
+|`jq(exp)` | `Object` | 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.
+|`jq(input,exp)` | `Object` | Same as `jq(exp)` but to use the _input_
expression as the source of the JSON document.
+|`jsonpath(exp)` | `Object` | 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.
+|`jsonpath(input,exp)` | `Object` | Same as `jsonpath(exp)` but to use the
_input_ expression as the source of the JSON document.
+|`pretty(exp)` | `String` | Converts the expression to a `String`, and
attempts to pretty print (if JSON or XML) otherwise return the value as-is.
+|`prettyBody` | `String` | Converts the message body to a `String`, and
attempts to pretty print (if JSON or XML) otherwise return the value as-is.
+|`simpleJsonpath(exp)` | `Object` | When working with JSON data, then this
allows using built-in Simple JsonPath, for example, to extract data from the
message body (in JSON format).
+|`simpleJsonpath(input,exp)` | `Object` | Same as `simpleJsonpath(exp)` but to
use the _input_ expression as the source of the JSON document.
+|`toJson(exp)` | `String` | Converts the expression to a JSON `String`
representation. String values are returned as-is, null values return null, all
other types are serialized to JSON.
+|`toJsonBody` | `String` | Converts the message body to a JSON `String`
representation. String values are returned as-is, null values return null, all
other types are serialized to JSON.
+|`toPrettyJson(exp)` | `String` | Converts the expression to a JSON `String`
representation. String values are returned as-is, null values return null, all
other types are serialized to JSON in pretty mode.
+|`toPrettyJsonBody` | `String` | Converts the message body to a JSON `String`
representation. String values are returned as-is, null values return null, all
other types are serialized to JSON in pretty mode.
|`xpath(exp)` | `Object` | 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.
-|`xpath(input,exp)` | `Object` | 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 you can choose `header:key`, `exchangeProperty:key` or `variable:key` to
use as input for the JSon payload instead of the message body.
+|`xpath(input,exp)` | `Object` | 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 you can choose `header:key`, `exchangeProperty:key` or `variable:key` to
use as input for the JSON payload instead of the message body.
|====
-The simple language has support for working with XML and JSon data by offering
functions that leverage the
-xref:languages:jsonpath-language.adoc[JSonPath],
xref:languages:jq-language.adoc[JQ], xref:languages:xpath-language.adoc[XPath]
languages.
+The simple language has support for working with XML and JSON data by offering
functions that leverage the
+xref:languages:jsonpath-language.adoc[JSONPath],
xref:languages:jq-language.adoc[JQ], xref:languages:xpath-language.adoc[XPath]
languages.
This also mean that you must include the required JARs on the classpath.
-The `jq` function (JSon Query) is used for using the JQ language to obtain
data from an existing JSon payload.
+The `jq` function (JSON Query) is used for using the JQ language to obtain
data from an existing JSON payload.
For example given this payload:
[source,json]
@@ -676,7 +676,7 @@ from("direct:map")
.to("log:data");
----
-The `jsonpath` function works similar to `jq` but uses JSonPath.
+The `jsonpath` function works similar to `jq` but uses JSONPath.
When using `${jsonpath($.id)}` will also return `123`.
And the data mapping can be done as follows with JSonPath instead of JQ:
@@ -693,10 +693,10 @@ from("direct:map")
.to("log:data");
----
-The `simpleJsonpath` function is using Camel's built in JSon library from
`camel-util-json` that is a basic JSon parser.
+The `simpleJsonpath` function is using Camel's built in JSON library from
`camel-util-json` that is a basic JSON parser.
The syntax for the path is similar to Camel's bean OGNL syntax to use a dot
notation to walk down a nested structure.
-Because the input JSon is not nested then the mapping example is just:
+Because the input JSON is not nested then the mapping example is just:
[source,java]
----
@@ -710,7 +710,7 @@ from("direct:map")
.to("log:data");
----
-However, if there are nested JSon such as:
+However, if there are nested JSON such as:
[source,json]
----
@@ -738,7 +738,7 @@ However, if there are nested JSon such as:
}
----
-Then you can retrieve data from the JSon payload as follows:
+Then you can retrieve data from the JSON payload as follows:
[source,text]
----
@@ -763,9 +763,9 @@ For example, we attempt to refer to a non-existing attribute
library.book[0]?.cheese
----
-The optional marker can also be used sooner in the path, such as
`foo?.bar.age` which will not fail if there are no nested _bar_ node in the
JSon payload.
+The optional marker can also be used sooner in the path, such as
`foo?.bar.age` which will not fail if there are no nested _bar_ node in the
JSON payload.
-The `toJson` function is to convert the payload to JSon as a `String` value.
However, if the payload is already a `String` then no conversion happens.
+The `toJson` function is to convert the payload to JSON as a `String` value.
However, if the payload is already a `String` then no conversion happens.
So suppose the payload is a `Map` object as follows:
[source,java]
@@ -775,9 +775,23 @@ map.put("name", "Jack");
map.put("id", 123);
----
-Then `toJson` will output: `{"name":"Jack","id":123}`.
+Then `toJson` will output:
-There are also _pretty_ alternatives so when calling `toPrettyJson` will
output: TODO:
+[source,json]
+----
+{"name":"Jack","id":123}
+----
+
+
+There are also _pretty_ alternatives so when calling `toPrettyJson` will
output:
+
+[source,json]
+----
+{
+ "name": "Jack",
+ "id": 123
+}
+----
The `xpath` function is for working with XML and using XPath expressions to
extract data from XML payloads.
@@ -805,15 +819,15 @@ And the data mapping can be done with XPath as follows:
from("direct:map")
.transform().simple("""
{
- "roll": ${jsonpath($.id)},
- "years": ${jsonpath($.age)},
- "fullname": "${jsonpath($.name)}"
+ "id": ${xpath(/order/@id)},
+ "item": "${xpath(/order/item)}",
+ "fullname": "${xpath(/order/first)} ${xpath(/order/last)}"
}""")
.to("log:data");
----
-The `pretty` function is used for pretty printing JSon or XML data as a String
value.
-For example given the following JSon payload (in a single line): `{"id": 123,
"age": 42, "name": "scott"}`
+The `pretty` function is used for pretty printing JSON or XML data as a String
value.
+For example given the following JSON payload (in a single line): `{"id": 123,
"age": 42, "name": "scott"}`
then `$\{pretty}` will output this nicely formatted:
[source,json]
@@ -948,7 +962,7 @@ The following special symbols can be used when escaped with
`\` as below:
|`\\n` | To use newline character.
|`\\t` | To use tab character.
|`\\r` | To use carriage return character.
-|`\\}` | To use the `}` character as text. This may be needed when building a
JSon structure with the simple language.
+|`\\}` | To use the `}` character as text. This may be needed when building a
JSON structure with the simple language.
|====
For example to use a new-line character in the split function `${split(\\n)}`.
@@ -1100,7 +1114,7 @@ And there can be as many chains:
[source,text]
----
-${leftValue} ~> ${midValue} ~> ${midValue} -> ${rightValue}
+${leftValue} ~> ${midValue} ~> ${midValue} ~> ${rightValue}
----
For example if the message body contains `Hello World` then the follow would
return `WORLD`:
@@ -1309,14 +1323,14 @@ For instance:
[source,java]
-----
-simple("${header.title} contains 'Camel' && ${header.type'} == 'gold'")
+simple("${header.title} contains 'Camel' && ${header.type} == 'gold'")
-----
And of course the `||` is also supported. The sample would be:
[source,java]
-----
-simple("${header.title} contains 'Camel' || ${header.type'} == 'gold'")
+simple("${header.title} contains 'Camel' || ${header.type} == 'gold'")
-----
== Init Blocks
@@ -1358,7 +1372,7 @@ Here are a couple of examples:
$init{
$cheese := 'Hello ${body}';
$minAge := 18;
- $foo := ${uppercase('Hello ${body}'};
+ $foo := ${uppercase('Hello ${body}')};
$bar := ${header.code > 999 ? 'Gold' : 'Silver'};
}init$
----
@@ -1382,7 +1396,7 @@ $init{
The local variables can then easily be used in the Simple language either
using the `${variable.foo}` syntax
or the shorthand syntax `$foo`.
-For example as below where we do a basic JSon mapping:
+For example as below where we do a basic JSON mapping:
[source,text]
----
@@ -1868,6 +1882,7 @@ Instead of the message body then a simple expression can
be nested as input, for
</setBody>
----
+[#_replacing_double_and_single_quotes]
== Replacing double and single quotes
You can use the `replace` function to more easily replace all single or double
quotes in the message body,
@@ -1964,7 +1979,7 @@ e.g., to refer to a file on the classpath you can do:
.setHeader("myHeader").simple("resource:classpath:mysimple.txt")
----
-== Pretty XML or JSon
+== Pretty XML or JSON
From *Camel 4.18* onwards then the Simple language can _pretty format_ the
output.
@@ -2113,7 +2128,7 @@ reg.addFunction(new FooSimpleFunction());
----
TIP: The custom function can then be made discoverable by Camel by dependency
injection.
-If you use standalone Camel you can add `@BindToRegistry("foo-function)` to
the class.
+If you use standalone Camel you can add `@BindToRegistry("foo-function")` to
the class.
For Spring Boot use `@Component` or `@Service` and Quarkus you can for example
use `@ApplicationScoped`.
diff --git
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionDispatcher.java
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionDispatcher.java
index 2c76cc113d4e..2080ac72c648 100644
---
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionDispatcher.java
+++
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionDispatcher.java
@@ -27,6 +27,7 @@ import
org.apache.camel.language.simple.functions.CollectionFunctionFactory;
import org.apache.camel.language.simple.functions.HeaderFunctionFactory;
import org.apache.camel.language.simple.functions.JoinFunctionFactory;
import org.apache.camel.language.simple.functions.MathFunctionFactory;
+import org.apache.camel.language.simple.functions.MiscFunctionFactory;
import org.apache.camel.language.simple.functions.RandomFunctionFactory;
import org.apache.camel.language.simple.functions.SkipFunctionFactory;
import org.apache.camel.language.simple.functions.StringFunctionFactory;
@@ -63,7 +64,8 @@ public final class SimpleFunctionDispatcher {
new JoinFunctionFactory(),
new MathFunctionFactory(),
new StringFunctionFactory(),
- new CollectionFunctionFactory());
+ new CollectionFunctionFactory(),
+ new MiscFunctionFactory());
private static final List<Entry> EXPRESSION_ENTRIES = List.of(
new Entry("camel-attachments",
SimpleFunctionDispatcher::isAttachmentFunction),
diff --git
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
index 0719dacccf9d..5708f1850500 100644
---
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
+++
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
@@ -27,6 +27,7 @@ import
org.apache.camel.language.simple.SimpleExpressionBuilder;
import org.apache.camel.language.simple.SimpleFunctionDispatcher;
import org.apache.camel.language.simple.SimpleFunctionHelper;
import org.apache.camel.language.simple.SimplePredicateParser;
+import org.apache.camel.language.simple.functions.DirectFunctionFactory;
import org.apache.camel.language.simple.types.SimpleParserException;
import org.apache.camel.language.simple.types.SimpleToken;
import org.apache.camel.spi.Language;
@@ -102,9 +103,11 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return exp;
}
+ private static final DirectFunctionFactory DIRECT_FACTORY = new
DirectFunctionFactory();
+
private Expression doCreateSimpleExpression(CamelContext camelContext,
String function, boolean strict) {
// return the function directly if we can create function without
analyzing the prefix
- Expression answer = createSimpleExpressionDirectly(camelContext,
function);
+ Expression answer = DIRECT_FACTORY.createFunction(camelContext,
function, token.getIndex());
if (answer != null) {
return answer;
}
@@ -375,15 +378,11 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return SimpleExpressionBuilder.cacheExpression(exp);
}
- // miscellaneous functions
+ // miscellaneous and other built-in functions
Expression builtIn =
SimpleFunctionDispatcher.tryCreateBuiltIn(camelContext, function,
token.getIndex());
if (builtIn != null) {
return builtIn;
}
- Expression misc = createSimpleExpressionMisc(function);
- if (misc != null) {
- return misc;
- }
// functions from external components (attachments, base64, html, ...)
Expression external =
SimpleFunctionDispatcher.tryCreateExternal(camelContext, function,
token.getIndex());
@@ -563,46 +562,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return null;
}
- private Expression createSimpleExpressionDirectly(CamelContext
camelContext, String expression) {
- if (ObjectHelper.equal(expression, "id")) {
- return ExpressionBuilder.messageIdExpression();
- } else if (ObjectHelper.equal(expression, "messageTimestamp")) {
- return ExpressionBuilder.messageTimestampExpression();
- } else if (ObjectHelper.equal(expression, "exchangeId")) {
- return ExpressionBuilder.exchangeIdExpression();
- } else if (ObjectHelper.equal(expression, "exchange")) {
- return ExpressionBuilder.exchangeExpression();
- } else if (ObjectHelper.equal(expression, "logExchange")) {
- return ExpressionBuilder.logExchange();
- } else if (ObjectHelper.equal(expression, "exception")) {
- return ExpressionBuilder.exchangeExceptionExpression();
- } else if (ObjectHelper.equal(expression, "exception.message")) {
- return ExpressionBuilder.exchangeExceptionMessageExpression();
- } else if (ObjectHelper.equal(expression, "exception.stacktrace")) {
- return ExpressionBuilder.exchangeExceptionStackTraceExpression();
- } else if (ObjectHelper.equal(expression, "threadId")) {
- return ExpressionBuilder.threadIdExpression();
- } else if (ObjectHelper.equal(expression, "threadName")) {
- return ExpressionBuilder.threadNameExpression();
- } else if (ObjectHelper.equal(expression, "hostname")) {
- return ExpressionBuilder.hostnameExpression();
- } else if (ObjectHelper.equal(expression, "camelId")) {
- return ExpressionBuilder.camelContextNameExpression();
- } else if (ObjectHelper.equal(expression, "routeId")) {
- return ExpressionBuilder.routeIdExpression();
- } else if (ObjectHelper.equal(expression, "fromRouteId")) {
- return ExpressionBuilder.fromRouteIdExpression();
- } else if (ObjectHelper.equal(expression, "routeGroup")) {
- return ExpressionBuilder.routeGroupExpression();
- } else if (ObjectHelper.equal(expression, "stepId")) {
- return ExpressionBuilder.stepIdExpression();
- } else if (ObjectHelper.equal(expression, "null")) {
- return SimpleExpressionBuilder.nullExpression();
- }
-
- return null;
- }
-
private Expression createSimpleFileExpression(String remainder, boolean
strict) {
if (ObjectHelper.equal(remainder, "name")) {
return SimpleExpressionBuilder.fileNameExpression();
@@ -639,251 +598,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return null;
}
- private Expression createSimpleExpressionMisc(String function) {
- String remainder;
-
- // isEmpty function
- remainder = ifStartsWithReturnRemainder("isEmpty(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.isEmptyExpression(exp);
- }
-
- // isAlpha function
- remainder = ifStartsWithReturnRemainder("isAlpha(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.isAlphaExpression(exp);
- }
- remainder = ifStartsWithReturnRemainder("isAlphaNumeric(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.isAlphaNumericExpression(exp);
- }
- // isNumeric function
- remainder = ifStartsWithReturnRemainder("isNumeric(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.isNumericExpression(exp);
- }
- // not function
- remainder = ifStartsWithReturnRemainder("not(", function);
- if (remainder != null) {
- String exp = "${body}";
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = value;
- }
- return SimpleExpressionBuilder.isNotPredicate(exp);
- }
-
- // whichKind function
- remainder = ifStartsWithReturnRemainder("kindOfType(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.kindOfTypeExpression(exp);
- }
-
- // throwException function
- remainder = ifStartsWithReturnRemainder("throwException(", function);
- if (remainder != null) {
- String msg;
- String type = null;
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${throwException(msg)} or
${throwException(type,msg)} was: " + function,
- token.getIndex());
- }
- if (values.contains(",")) {
- String[] tokens = StringQuoteHelper.splitSafeQuote(values,
',', true, true);
- if (tokens.length > 2) {
- throw new SimpleParserException(
- "Valid syntax: ${throwException(msg)} or
${throwException(type,msg)} was: " + function,
- token.getIndex());
- }
- msg = StringHelper.removeQuotes(tokens[0]);
- type = StringHelper.removeQuotes(tokens[1]);
- } else {
- msg = StringHelper.removeQuotes(values.trim());
- }
- return SimpleExpressionBuilder.throwExceptionExpression(msg, type);
- }
- // assert function
- remainder = ifStartsWithReturnRemainder("assert(", function);
- if (remainder != null) {
- String exp;
- String msg;
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${assert(exp,msg)} was: " + function,
- token.getIndex());
- }
- String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
true, true);
- if (tokens.length != 2) {
- throw new SimpleParserException(
- "Valid syntax: ${assert(exp,msg)} was: " + function,
- token.getIndex());
- }
- exp = tokens[0];
- msg = StringHelper.removeQuotes(tokens[1]);
- return SimpleExpressionBuilder.assertExpression(exp, msg);
- }
-
- // convertTo function
- remainder = ifStartsWithReturnRemainder("convertTo(", function);
- if (remainder != null) {
- String exp = "${body}";
- String type;
- // do not use beforeLast as this supports OGNL
- String values = StringHelper.before(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${convertTo(type)} or
${convertTo(exp,type)} was: " + function,
- token.getIndex());
- }
- if (values.contains(",")) {
- String[] tokens = StringQuoteHelper.splitSafeQuote(values,
',', true, true);
- if (tokens.length > 2) {
- throw new SimpleParserException(
- "Valid syntax: ${convertTo(type)} or
${convertTo(exp,type)} was: " + function,
- token.getIndex());
- }
- exp = StringHelper.removeQuotes(tokens[0]);
- type = StringHelper.removeQuotes(tokens[1]);
- } else {
- type = StringHelper.removeQuotes(values.trim());
- }
- remainder = StringHelper.after(remainder, ")");
- if (ObjectHelper.isNotEmpty(remainder)) {
- boolean invalid =
OgnlHelper.isInvalidValidOgnlExpression(remainder);
- if (invalid) {
- throw new SimpleParserException(
- "Valid syntax: ${convertTo(type).OGNL} or
${convertTo(exp,type).OGNL} was: " + function,
- token.getIndex());
- }
- return SimpleExpressionBuilder.convertToOgnlExpression(exp,
type, remainder);
- } else {
- return SimpleExpressionBuilder.convertToExpression(exp, type);
- }
- }
-
- // messageHistory function
- remainder = ifStartsWithReturnRemainder("messageHistory", function);
- if (remainder != null) {
- boolean detailed;
- String values = StringHelper.between(remainder, "(", ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- detailed = true;
- } else {
- detailed = Boolean.parseBoolean(values);
- }
- return SimpleExpressionBuilder.messageHistoryExpression(detailed);
- } else if (ObjectHelper.equal(function, "messageHistory")) {
- return SimpleExpressionBuilder.messageHistoryExpression(true);
- }
-
- // uuid function
- remainder = ifStartsWithReturnRemainder("uuid", function);
- if (remainder != null) {
- String values = StringHelper.between(remainder, "(", ")");
- return SimpleExpressionBuilder.uuidExpression(values);
- } else if (ObjectHelper.equal(function, "uuid")) {
- return SimpleExpressionBuilder.uuidExpression(null);
- }
-
- // hash function
- remainder = ifStartsWithReturnRemainder("hash(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${hash(value,algorithm)} or
${hash(value)} was: " + function, token.getIndex());
- }
- if (values.contains(",")) {
- String[] tokens = values.split(",", 2);
- if (tokens.length > 2) {
- throw new SimpleParserException(
- "Valid syntax: ${hash(value,algorithm)} or
${hash(value)} was: " + function, token.getIndex());
- }
- return
SimpleExpressionBuilder.hashExpression(tokens[0].trim(), tokens[1].trim());
- } else {
- return SimpleExpressionBuilder.hashExpression(values.trim(),
"SHA-256");
- }
- }
-
- // empty function
- remainder = ifStartsWithReturnRemainder("empty(", function);
- if (remainder != null) {
- String value = StringHelper.before(remainder, ")");
- if (ObjectHelper.isEmpty(value)) {
- throw new SimpleParserException(
- "Valid syntax: ${empty(<type>)} but was: " + function,
token.getIndex());
- }
- return SimpleExpressionBuilder.newEmptyExpression(value);
- }
- // newEmpty function
- remainder = ifStartsWithReturnRemainder("newEmpty(", function);
- if (remainder != null) {
- String value = StringHelper.before(remainder, ")");
- if (ObjectHelper.isEmpty(value)) {
- throw new SimpleParserException(
- "Valid syntax: ${newEmpty(<type>)} but was: " +
function, token.getIndex());
- }
- return SimpleExpressionBuilder.newEmptyExpression(value);
- }
- // iif function
- remainder = ifStartsWithReturnRemainder("iif(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax:
${iif(predicate,trueExpression,falseExpression)} was: " + function,
token.getIndex());
- }
- String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
true, true);
- if (tokens.length > 3) {
- throw new SimpleParserException(
- "Valid syntax:
${iif(predicate,trueExpression,falseExpression)} was: " + function,
token.getIndex());
- }
- return SimpleExpressionBuilder.iifExpression(tokens[0].trim(),
tokens[1].trim(), tokens[2].trim());
- }
-
- // load function
- remainder = ifStartsWithReturnRemainder("load(", function);
- if (remainder != null) {
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isEmpty(value)) {
- throw new SimpleParserException(
- "Valid syntax: ${load(name)} but was: " + function,
token.getIndex());
- }
- value = StringHelper.removeQuotes(value);
- return SimpleExpressionBuilder.loadExpression(value);
- }
-
- return null;
- }
-
@Deprecated(since = "4.21")
public static String ifStartsWithReturnRemainder(String prefix, String
text) {
return SimpleFunctionHelper.ifStartsWithReturnRemainder(prefix, text);
@@ -898,7 +612,7 @@ public class SimpleFunctionExpression extends
LiteralExpression {
String function = getText();
// return the function directly if we can create function without
analyzing the prefix
- String answer = createCodeDirectly(function);
+ String answer = DIRECT_FACTORY.createCode(camelContext, function,
token.getIndex());
if (answer != null) {
return answer;
}
@@ -1090,14 +804,27 @@ public class SimpleFunctionExpression extends
LiteralExpression {
}
}
- // miscellaneous functions
+ // miscellaneous and other built-in functions
String builtIn =
SimpleFunctionDispatcher.tryCreateCodeBuiltIn(camelContext, function,
token.getIndex());
if (builtIn != null) {
return builtIn;
}
- String misc = createCodeExpressionMisc(camelContext, function);
- if (misc != null) {
- return misc;
+
+ // not() code-gen requires skipFileFunctions from the parser context
and cannot be in MiscFunctionFactory
+ String notRemainder = ifStartsWithReturnRemainder("not(", function);
+ if (notRemainder != null) {
+ String exp = "body";
+ String values = StringHelper.beforeLast(notRemainder, ")");
+ if (ObjectHelper.isNotEmpty(values)) {
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length != 1) {
+ throw new SimpleParserException("Valid syntax: ${not(exp)}
was: " + function, token.getIndex());
+ }
+ SimplePredicateParser predicateParser
+ = new SimplePredicateParser(camelContext, tokens[0],
true, skipFileFunctions, null);
+ exp = predicateParser.parseCode();
+ }
+ return "Object o = " + exp + ";\n return isNot(exchange,
o);";
}
// code from external components (attachments, base64, ...)
@@ -1109,44 +836,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
throw new SimpleParserException("Unknown function: " + function,
token.getIndex());
}
- public String createCodeDirectly(String expression) throws
SimpleParserException {
- if (ObjectHelper.equal(expression, "id")) {
- return "message.getMessageId()";
- } else if (ObjectHelper.equal(expression, "messageTimestamp")) {
- return "message.getMessageTimestamp()";
- } else if (ObjectHelper.equal(expression, "exchangeId")) {
- return "exchange.getExchangeId()";
- } else if (ObjectHelper.equal(expression, "exchange")) {
- return "exchange";
- } else if (ObjectHelper.equal(expression, "logExchange")) {
- return "logExchange(exchange)";
- } else if (ObjectHelper.equal(expression, "exception")) {
- return "exception(exchange)";
- } else if (ObjectHelper.equal(expression, "exception.message")) {
- return "exceptionMessage(exchange)";
- } else if (ObjectHelper.equal(expression, "exception.stacktrace")) {
- return "exceptionStacktrace(exchange)";
- } else if (ObjectHelper.equal(expression, "threadId")) {
- return "threadId()";
- } else if (ObjectHelper.equal(expression, "threadName")) {
- return "threadName()";
- } else if (ObjectHelper.equal(expression, "hostname")) {
- return "hostName()";
- } else if (ObjectHelper.equal(expression, "camelId")) {
- return "context.getName()";
- } else if (ObjectHelper.equal(expression, "fromRouteId")) {
- return "fromRouteId(exchange)";
- } else if (ObjectHelper.equal(expression, "routeId")) {
- return "routeId(exchange)";
- } else if (ObjectHelper.equal(expression, "stepId")) {
- return "stepId(exchange)";
- } else if (ObjectHelper.equal(expression, "null")) {
- return "null";
- }
-
- return null;
- }
-
private String createCodeExchangeProperty(final String function) {
// exchangePropertyAsIndex
String remainder =
ifStartsWithReturnRemainder("exchangePropertyAsIndex(", function);
@@ -1301,388 +990,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
throw new SimpleParserException("Unknown file language syntax: " +
remainder, token.getIndex());
}
- private String createCodeExpressionMisc(CamelContext camelContext, String
function) {
- String remainder;
-
- // kindOfType function
- remainder = ifStartsWithReturnRemainder("kindOfType(", function);
- if (remainder != null) {
- String exp = null;
- String values = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(values)) {
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length != 1) {
- throw new SimpleParserException(
- "Valid syntax: ${kindOfType(exp)} was: " +
function, token.getIndex());
- }
- // single quotes should be double quotes
- String s = tokens[0];
- if (StringHelper.isSingleQuoted(s)) {
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- }
- exp = s;
- }
- if (ObjectHelper.isEmpty(exp)) {
- exp = "body";
- }
- return "Object o = " + exp + ";\n return
kindOfType(exchange, o);";
- }
-
- // isEmpty function
- remainder = ifStartsWithReturnRemainder("isEmpty(", function);
- if (remainder != null) {
- String exp = null;
- String values = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(values)) {
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length != 1) {
- throw new SimpleParserException(
- "Valid syntax: ${isEmpty(exp)} was: " + function,
token.getIndex());
- }
- // single quotes should be double quotes
- String s = tokens[0];
- if (StringHelper.isSingleQuoted(s)) {
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- }
- exp = s;
- }
- if (ObjectHelper.isEmpty(exp)) {
- exp = "body";
- }
- return "Object o = " + exp + ";\n return isEmpty(exchange,
o);";
- }
-
- // isNumeric function
- remainder = ifStartsWithReturnRemainder("isAlpha(", function);
- if (remainder != null) {
- String exp = null;
- String values = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(values)) {
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length != 1) {
- throw new SimpleParserException(
- "Valid syntax: ${isAlpha(exp)} was: " + function,
token.getIndex());
- }
- // single quotes should be double quotes
- String s = tokens[0];
- if (StringHelper.isSingleQuoted(s)) {
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- }
- exp = s;
- }
- if (ObjectHelper.isEmpty(exp)) {
- exp = "body";
- }
- return "Object o = " + exp + ";\n return isAlpha(exchange,
o);";
- }
- // isAlphaNumeric function
- remainder = ifStartsWithReturnRemainder("isAlphaNumeric(", function);
- if (remainder != null) {
- String exp = null;
- String values = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(values)) {
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length != 1) {
- throw new SimpleParserException(
- "Valid syntax: ${isAlphaNumeric(exp)} was: " +
function, token.getIndex());
- }
- // single quotes should be double quotes
- String s = tokens[0];
- if (StringHelper.isSingleQuoted(s)) {
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- }
- exp = s;
- }
- if (ObjectHelper.isEmpty(exp)) {
- exp = "body";
- }
- return "Object o = " + exp + ";\n return
isAlphaNumeric(exchange, o);";
- }
- // isNumeric function
- remainder = ifStartsWithReturnRemainder("isNumeric(", function);
- if (remainder != null) {
- String exp = null;
- String values = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(values)) {
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length != 1) {
- throw new SimpleParserException(
- "Valid syntax: ${isNumeric(exp)} was: " +
function, token.getIndex());
- }
- // single quotes should be double quotes
- String s = tokens[0];
- if (StringHelper.isSingleQuoted(s)) {
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- }
- exp = s;
- }
- if (ObjectHelper.isEmpty(exp)) {
- exp = "body";
- }
- return "Object o = " + exp + ";\n return
isNumeric(exchange, o);";
- }
- // not function
- remainder = ifStartsWithReturnRemainder("not(", function);
- if (remainder != null) {
- String exp = "body";
- String values = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(values)) {
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length != 1) {
- throw new SimpleParserException(
- "Valid syntax: ${not(exp)} was: " + function,
token.getIndex());
- }
-
- // Parse the condition as a predicate and generate code
- SimplePredicateParser predicateParser
- = new SimplePredicateParser(camelContext, tokens[0],
true, skipFileFunctions, null);
- exp = predicateParser.parseCode();
- }
- return "Object o = " + exp + ";\n return isNot(exchange,
o);";
- }
-
- // convertTo function
- remainder = ifStartsWithReturnRemainder("convertTo(", function);
- if (remainder != null) {
- String ognl = null;
- String exp = "body";
- String type;
- String values = StringHelper.before(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${convertTo(type)} or
${convertTo(exp,type)} was: " + function,
- token.getIndex());
- }
- if (values.contains(",")) {
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length > 2) {
- throw new SimpleParserException(
- "Valid syntax: ${convertTo(type)} or
${convertTo(exp,type)} was: " + function,
- token.getIndex());
- }
- String s = tokens[0].trim();
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- exp = s;
- type = tokens[1];
- } else {
- type = values.trim();
- }
- type = appendClass(type);
- type = type.replace('$', '.');
- if (ObjectHelper.isEmpty(exp)) {
- exp = "null";
- }
-
- remainder = StringHelper.after(remainder, ")");
- if (ObjectHelper.isNotEmpty(remainder)) {
- boolean invalid =
OgnlHelper.isInvalidValidOgnlExpression(remainder);
- if (invalid) {
- throw new SimpleParserException(
- "Valid syntax: ${convertTo(type).OGNL} or
${convertTo(exp,type).OGNL} was: " + function,
- token.getIndex());
- }
- ognl = ognlCodeMethods(remainder, type);
- }
-
- String code = "Object value = " + exp + ";\n return
convertTo(exchange, " + type + ", value)";
- if (ognl != null) {
- code += ognl;
- }
- code += ";";
- return code;
- }
- // throwException function
- remainder = ifStartsWithReturnRemainder("throwException(", function);
- if (remainder != null) {
- String msg;
- String type = "IllegalArgumentException";
- String values = StringHelper.before(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${throwException(msg)} or
${throwException(msg,type)} was: " + function,
- token.getIndex());
- }
- if (values.contains(",")) {
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length > 2) {
- throw new SimpleParserException(
- "Valid syntax: ${throwException(msg)} or
${throwException(msg,type)} was: " + function,
- token.getIndex());
- }
- msg = tokens[0];
- type = tokens[1];
- } else {
- msg = values.trim();
- }
- msg = StringHelper.removeLeadingAndEndingQuotes(msg);
- msg = StringQuoteHelper.doubleQuote(msg);
- type = appendClass(type);
- type = type.replace('$', '.');
- return "return throwException(exchange, " + msg + ", " + type +
");";
- }
- // assertExpression function
- remainder = ifStartsWithReturnRemainder("assertExpression(", function);
- if (remainder != null) {
- throw new UnsupportedOperationException("assertExpression is not
supported in csimple language");
- }
-
- // messageHistory function
- remainder = ifStartsWithReturnRemainder("messageHistory", function);
- if (remainder != null) {
- boolean detailed;
- String values = StringHelper.between(remainder, "(", ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- detailed = true;
- } else {
- detailed = Boolean.parseBoolean(values);
- }
- return "messageHistory(exchange, " + (detailed ? "true" : "false")
+ ")";
- } else if (ObjectHelper.equal(function, "messageHistory")) {
- return "messageHistory(exchange, true)";
- }
-
- // empty function
- remainder = ifStartsWithReturnRemainder("empty(", function);
- if (remainder != null) {
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isEmpty(value)) {
- throw new SimpleParserException(
- "Valid syntax: ${empty(<type>)} but was: " + function,
token.getIndex());
- }
- value = StringQuoteHelper.doubleQuote(value);
- return "newEmpty(exchange, " + value + ")";
- }
- // newEmpty
- remainder = ifStartsWithReturnRemainder("newEmpty(", function);
- if (remainder != null) {
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isEmpty(value)) {
- throw new SimpleParserException(
- "Valid syntax: ${newEmpty(<type>)} but was: " +
function, token.getIndex());
- }
- value = StringQuoteHelper.doubleQuote(value);
- return "newEmpty(exchange, " + value + ")";
- }
-
- // hash function
- remainder = ifStartsWithReturnRemainder("hash(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${hash(value,algorithm)} or
${hash(value)} was: " + function, token.getIndex());
- }
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length > 2) {
- throw new SimpleParserException(
- "Valid syntax: ${hash(value,algorithm)} or
${hash(value)} was: " + function, token.getIndex());
- }
- // single quotes should be double quotes
- for (int i = 0; i < tokens.length; i++) {
- String s = tokens[i];
- if (StringHelper.isSingleQuoted(s)) {
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- tokens[i] = s;
- }
- }
- String algo = "\"SHA-256\"";
- if (tokens.length == 2) {
- algo = tokens[1];
- if (!StringHelper.isQuoted(algo)) {
- algo = StringQuoteHelper.doubleQuote(algo);
- }
- }
- return "var val = " + tokens[0] + ";\n return
hash(exchange, val, " + algo + ");";
- }
-
- // uuid function
- remainder = ifStartsWithReturnRemainder("uuid", function);
- if (remainder == null && "uuid".equals(function)) {
- remainder = "(default)";
- }
- if (remainder != null) {
- String generator = StringHelper.between(remainder, "(", ")");
- if (generator == null) {
- generator = "default";
- }
- StringBuilder sb = new StringBuilder(128);
- if ("classic".equals(generator)) {
- sb.append(" UuidGenerator uuid = new
org.apache.camel.support.ClassicUuidGenerator();\n");
- sb.append("return uuid.generateUuid();");
- } else if ("short".equals(generator)) {
- sb.append(" UuidGenerator uuid = new
org.apache.camel.support.ShortUuidGenerator();\n");
- sb.append("return uuid.generateUuid();");
- } else if ("simple".equals(generator)) {
- sb.append(" UuidGenerator uuid = new
org.apache.camel.support.SimpleUuidGenerator();\n");
- sb.append("return uuid.generateUuid();");
- } else if ("default".equals(generator)) {
- sb.append(" UuidGenerator uuid = new
org.apache.camel.support.DefaultUuidGenerator();\n");
- sb.append("return uuid.generateUuid();");
- } else if ("random".equals(generator)) {
- sb.append(" UuidGenerator uuid = new
org.apache.camel.support.RandomUuidGenerator();\n");
- sb.append("return uuid.generateUuid();");
- } else {
- generator = StringQuoteHelper.doubleQuote(generator);
- sb.append("if (uuid == null) uuid =
customUuidGenerator(exchange, ").append(generator)
- .append("); return uuid.generateUuid();");
- }
- return sb.toString();
- }
-
- // iif function
- remainder = ifStartsWithReturnRemainder("iif(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax:
${iif(predicate,trueExpression,falseExpression)} was: " + function,
token.getIndex());
- }
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length != 3) {
- throw new SimpleParserException(
- "Valid syntax:
${iif(predicate,trueExpression,falseExpression)} was: " + function,
token.getIndex());
- }
- // single quotes should be double quotes
- for (int i = 0; i < 3; i++) {
- String s = tokens[i];
- if (StringHelper.isSingleQuoted(s)) {
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- tokens[i] = s;
- }
- }
-
- return "Object o = " + tokens[0]
- + ";\n boolean b = convertTo(exchange,
boolean.class, o);\n return b ? "
- + tokens[1] + " : " + tokens[2];
- }
-
- // load function
- remainder = ifStartsWithReturnRemainder("load(", function);
- if (remainder != null) {
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isEmpty(value)) {
- throw new SimpleParserException(
- "Valid syntax: ${load(name)} but was: " + function,
token.getIndex());
- }
- // single quotes should be double quotes
- if (StringHelper.isSingleQuoted(value)) {
- value = StringHelper.removeLeadingAndEndingQuotes(value);
- value = StringQuoteHelper.doubleQuote(value);
- }
- return "Object o = " + value + ";\n return load(exchange,
o);";
- }
-
- return null;
- }
-
@Deprecated(since = "4.21")
public static String ognlCodeMethods(String remainder, String type) {
return SimpleFunctionHelper.ognlCodeMethods(remainder, type);
diff --git
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/DirectFunctionFactory.java
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/DirectFunctionFactory.java
new file mode 100644
index 000000000000..54dd9290de12
--- /dev/null
+++
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/DirectFunctionFactory.java
@@ -0,0 +1,119 @@
+/*
+ * 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.functions;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.language.simple.SimpleExpressionBuilder;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.apache.camel.support.builder.ExpressionBuilder;
+import org.apache.camel.util.ObjectHelper;
+
+/**
+ * Built-in Simple keyword functions that are matched by exact name (no
prefix): {@code ${id}},
+ * {@code ${messageTimestamp}}, {@code ${exchangeId}}, {@code ${exchange}},
{@code ${logExchange}},
+ * {@code ${exception}}, {@code ${exception.message}}, {@code
${exception.stacktrace}}, {@code ${threadId}},
+ * {@code ${threadName}}, {@code ${hostname}}, {@code ${camelId}}, {@code
${routeId}}, {@code ${fromRouteId}},
+ * {@code ${routeGroup}}, {@code ${stepId}}, {@code ${null}}.
+ *
+ * <p>
+ * These functions must be dispatched <em>before</em> the inline prefix checks
in {@code SimpleFunctionExpression}
+ * (e.g., the {@code exception} OGNL check and the {@code exchange} OGNL
check), because names like {@code exchangeId}
+ * and {@code exception.message} share a prefix with those checks.
+ */
+public final class DirectFunctionFactory implements
SimpleLanguageFunctionFactory {
+
+ @Override
+ public Expression createFunction(CamelContext camelContext, String
function, int index) {
+ if (ObjectHelper.equal(function, "id")) {
+ return ExpressionBuilder.messageIdExpression();
+ } else if (ObjectHelper.equal(function, "messageTimestamp")) {
+ return ExpressionBuilder.messageTimestampExpression();
+ } else if (ObjectHelper.equal(function, "exchangeId")) {
+ return ExpressionBuilder.exchangeIdExpression();
+ } else if (ObjectHelper.equal(function, "exchange")) {
+ return ExpressionBuilder.exchangeExpression();
+ } else if (ObjectHelper.equal(function, "logExchange")) {
+ return ExpressionBuilder.logExchange();
+ } else if (ObjectHelper.equal(function, "exception")) {
+ return ExpressionBuilder.exchangeExceptionExpression();
+ } else if (ObjectHelper.equal(function, "exception.message")) {
+ return ExpressionBuilder.exchangeExceptionMessageExpression();
+ } else if (ObjectHelper.equal(function, "exception.stacktrace")) {
+ return ExpressionBuilder.exchangeExceptionStackTraceExpression();
+ } else if (ObjectHelper.equal(function, "threadId")) {
+ return ExpressionBuilder.threadIdExpression();
+ } else if (ObjectHelper.equal(function, "threadName")) {
+ return ExpressionBuilder.threadNameExpression();
+ } else if (ObjectHelper.equal(function, "hostname")) {
+ return ExpressionBuilder.hostnameExpression();
+ } else if (ObjectHelper.equal(function, "camelId")) {
+ return ExpressionBuilder.camelContextNameExpression();
+ } else if (ObjectHelper.equal(function, "routeId")) {
+ return ExpressionBuilder.routeIdExpression();
+ } else if (ObjectHelper.equal(function, "fromRouteId")) {
+ return ExpressionBuilder.fromRouteIdExpression();
+ } else if (ObjectHelper.equal(function, "routeGroup")) {
+ return ExpressionBuilder.routeGroupExpression();
+ } else if (ObjectHelper.equal(function, "stepId")) {
+ return ExpressionBuilder.stepIdExpression();
+ } else if (ObjectHelper.equal(function, "null")) {
+ return SimpleExpressionBuilder.nullExpression();
+ }
+
+ return null;
+ }
+
+ @Override
+ public String createCode(CamelContext camelContext, String function, int
index) {
+ if (ObjectHelper.equal(function, "id")) {
+ return "message.getMessageId()";
+ } else if (ObjectHelper.equal(function, "messageTimestamp")) {
+ return "message.getMessageTimestamp()";
+ } else if (ObjectHelper.equal(function, "exchangeId")) {
+ return "exchange.getExchangeId()";
+ } else if (ObjectHelper.equal(function, "exchange")) {
+ return "exchange";
+ } else if (ObjectHelper.equal(function, "logExchange")) {
+ return "logExchange(exchange)";
+ } else if (ObjectHelper.equal(function, "exception")) {
+ return "exception(exchange)";
+ } else if (ObjectHelper.equal(function, "exception.message")) {
+ return "exceptionMessage(exchange)";
+ } else if (ObjectHelper.equal(function, "exception.stacktrace")) {
+ return "exceptionStacktrace(exchange)";
+ } else if (ObjectHelper.equal(function, "threadId")) {
+ return "threadId()";
+ } else if (ObjectHelper.equal(function, "threadName")) {
+ return "threadName()";
+ } else if (ObjectHelper.equal(function, "hostname")) {
+ return "hostName()";
+ } else if (ObjectHelper.equal(function, "camelId")) {
+ return "context.getName()";
+ } else if (ObjectHelper.equal(function, "fromRouteId")) {
+ return "fromRouteId(exchange)";
+ } else if (ObjectHelper.equal(function, "routeId")) {
+ return "routeId(exchange)";
+ } else if (ObjectHelper.equal(function, "stepId")) {
+ return "stepId(exchange)";
+ } else if (ObjectHelper.equal(function, "null")) {
+ return "null";
+ }
+
+ return null;
+ }
+}
diff --git
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/MiscFunctionFactory.java
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/MiscFunctionFactory.java
new file mode 100644
index 000000000000..a173f147621e
--- /dev/null
+++
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/MiscFunctionFactory.java
@@ -0,0 +1,550 @@
+/*
+ * 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.functions;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.language.simple.SimpleExpressionBuilder;
+import org.apache.camel.language.simple.types.SimpleParserException;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.OgnlHelper;
+import org.apache.camel.util.StringHelper;
+import org.apache.camel.util.StringQuoteHelper;
+
+import static
org.apache.camel.language.simple.SimpleFunctionHelper.appendClass;
+import static
org.apache.camel.language.simple.SimpleFunctionHelper.codeSplitSafe;
+import static
org.apache.camel.language.simple.SimpleFunctionHelper.ifStartsWithReturnRemainder;
+import static
org.apache.camel.language.simple.SimpleFunctionHelper.ognlCodeMethods;
+
+/**
+ * Built-in Simple miscellaneous functions: {@code ${isEmpty}}, {@code
${isAlpha}}, {@code ${isAlphaNumeric}},
+ * {@code ${isNumeric}}, {@code ${not}}, {@code ${kindOfType}}, {@code
${throwException}}, {@code ${assert}},
+ * {@code ${convertTo}}, {@code ${messageHistory}}, {@code ${uuid}}, {@code
${hash}}, {@code ${empty}},
+ * {@code ${newEmpty}}, {@code ${iif}}, {@code ${load}}.
+ *
+ * <p>
+ * Note: the {@code ${not}} CSimple code-generation path requires access to
the {@code skipFileFunctions} flag from the
+ * enclosing parser context and is therefore kept in {@code
SimpleFunctionExpression} rather than here.
+ */
+public final class MiscFunctionFactory implements
SimpleLanguageFunctionFactory {
+
+ @Override
+ public Expression createFunction(CamelContext camelContext, String
function, int index) {
+ String remainder;
+
+ remainder = ifStartsWithReturnRemainder("isEmpty(", function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.isEmptyExpression(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("isAlpha(", function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.isAlphaExpression(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("isAlphaNumeric(", function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.isAlphaNumericExpression(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("isNumeric(", function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.isNumericExpression(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("not(", function);
+ if (remainder != null) {
+ String exp = "${body}";
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = value;
+ }
+ return SimpleExpressionBuilder.isNotPredicate(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("kindOfType(", function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.kindOfTypeExpression(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("throwException(", function);
+ if (remainder != null) {
+ String msg;
+ String type = null;
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${throwException(msg)} or
${throwException(type,msg)} was: " + function, index);
+ }
+ if (values.contains(",")) {
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values,
',', true, true);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${throwException(msg)} or
${throwException(type,msg)} was: " + function, index);
+ }
+ msg = StringHelper.removeQuotes(tokens[0]);
+ type = StringHelper.removeQuotes(tokens[1]);
+ } else {
+ msg = StringHelper.removeQuotes(values.trim());
+ }
+ return SimpleExpressionBuilder.throwExceptionExpression(msg, type);
+ }
+
+ remainder = ifStartsWithReturnRemainder("assert(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException("Valid syntax:
${assert(exp,msg)} was: " + function, index);
+ }
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
true, true);
+ if (tokens.length != 2) {
+ throw new SimpleParserException("Valid syntax:
${assert(exp,msg)} was: " + function, index);
+ }
+ return SimpleExpressionBuilder.assertExpression(tokens[0],
StringHelper.removeQuotes(tokens[1]));
+ }
+
+ remainder = ifStartsWithReturnRemainder("convertTo(", function);
+ if (remainder != null) {
+ String exp = "${body}";
+ String type;
+ String values = StringHelper.before(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${convertTo(type)} or
${convertTo(exp,type)} was: " + function, index);
+ }
+ if (values.contains(",")) {
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values,
',', true, true);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${convertTo(type)} or
${convertTo(exp,type)} was: " + function, index);
+ }
+ exp = StringHelper.removeQuotes(tokens[0]);
+ type = StringHelper.removeQuotes(tokens[1]);
+ } else {
+ type = StringHelper.removeQuotes(values.trim());
+ }
+ remainder = StringHelper.after(remainder, ")");
+ if (ObjectHelper.isNotEmpty(remainder)) {
+ boolean invalid =
OgnlHelper.isInvalidValidOgnlExpression(remainder);
+ if (invalid) {
+ throw new SimpleParserException(
+ "Valid syntax: ${convertTo(type).OGNL} or
${convertTo(exp,type).OGNL} was: " + function, index);
+ }
+ return SimpleExpressionBuilder.convertToOgnlExpression(exp,
type, remainder);
+ } else {
+ return SimpleExpressionBuilder.convertToExpression(exp, type);
+ }
+ }
+
+ remainder = ifStartsWithReturnRemainder("messageHistory", function);
+ if (remainder != null) {
+ boolean detailed;
+ String values = StringHelper.between(remainder, "(", ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ detailed = true;
+ } else {
+ detailed = Boolean.parseBoolean(values);
+ }
+ return SimpleExpressionBuilder.messageHistoryExpression(detailed);
+ } else if (ObjectHelper.equal(function, "messageHistory")) {
+ return SimpleExpressionBuilder.messageHistoryExpression(true);
+ }
+
+ remainder = ifStartsWithReturnRemainder("uuid", function);
+ if (remainder != null) {
+ String values = StringHelper.between(remainder, "(", ")");
+ return SimpleExpressionBuilder.uuidExpression(values);
+ } else if (ObjectHelper.equal(function, "uuid")) {
+ return SimpleExpressionBuilder.uuidExpression(null);
+ }
+
+ remainder = ifStartsWithReturnRemainder("hash(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${hash(value,algorithm)} or
${hash(value)} was: " + function, index);
+ }
+ if (values.contains(",")) {
+ String[] tokens = values.split(",", 2);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${hash(value,algorithm)} or
${hash(value)} was: " + function, index);
+ }
+ return
SimpleExpressionBuilder.hashExpression(tokens[0].trim(), tokens[1].trim());
+ } else {
+ return SimpleExpressionBuilder.hashExpression(values.trim(),
"SHA-256");
+ }
+ }
+
+ remainder = ifStartsWithReturnRemainder("empty(", function);
+ if (remainder != null) {
+ String value = StringHelper.before(remainder, ")");
+ if (ObjectHelper.isEmpty(value)) {
+ throw new SimpleParserException("Valid syntax:
${empty(<type>)} but was: " + function, index);
+ }
+ return SimpleExpressionBuilder.newEmptyExpression(value);
+ }
+
+ remainder = ifStartsWithReturnRemainder("newEmpty(", function);
+ if (remainder != null) {
+ String value = StringHelper.before(remainder, ")");
+ if (ObjectHelper.isEmpty(value)) {
+ throw new SimpleParserException("Valid syntax:
${newEmpty(<type>)} but was: " + function, index);
+ }
+ return SimpleExpressionBuilder.newEmptyExpression(value);
+ }
+
+ remainder = ifStartsWithReturnRemainder("iif(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax:
${iif(predicate,trueExpression,falseExpression)} was: " + function, index);
+ }
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
true, true);
+ if (tokens.length > 3) {
+ throw new SimpleParserException(
+ "Valid syntax:
${iif(predicate,trueExpression,falseExpression)} was: " + function, index);
+ }
+ return SimpleExpressionBuilder.iifExpression(tokens[0].trim(),
tokens[1].trim(), tokens[2].trim());
+ }
+
+ remainder = ifStartsWithReturnRemainder("load(", function);
+ if (remainder != null) {
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isEmpty(value)) {
+ throw new SimpleParserException("Valid syntax: ${load(name)}
but was: " + function, index);
+ }
+ return
SimpleExpressionBuilder.loadExpression(StringHelper.removeQuotes(value));
+ }
+
+ return null;
+ }
+
+ @Override
+ public String createCode(CamelContext camelContext, String function, int
index) {
+ String remainder;
+
+ remainder = ifStartsWithReturnRemainder("kindOfType(", function);
+ if (remainder != null) {
+ return codeUnaryObject("kindOfType", remainder, function, index);
+ }
+
+ remainder = ifStartsWithReturnRemainder("isEmpty(", function);
+ if (remainder != null) {
+ return codeUnaryObject("isEmpty", remainder, function, index);
+ }
+
+ remainder = ifStartsWithReturnRemainder("isAlpha(", function);
+ if (remainder != null) {
+ return codeUnaryObject("isAlpha", remainder, function, index);
+ }
+
+ remainder = ifStartsWithReturnRemainder("isAlphaNumeric(", function);
+ if (remainder != null) {
+ return codeUnaryObject("isAlphaNumeric", remainder, function,
index);
+ }
+
+ remainder = ifStartsWithReturnRemainder("isNumeric(", function);
+ if (remainder != null) {
+ return codeUnaryObject("isNumeric", remainder, function, index);
+ }
+
+ remainder = ifStartsWithReturnRemainder("convertTo(", function);
+ if (remainder != null) {
+ return codeConvertTo(remainder, function, index);
+ }
+
+ remainder = ifStartsWithReturnRemainder("throwException(", function);
+ if (remainder != null) {
+ return codeThrowException(remainder, function, index);
+ }
+
+ remainder = ifStartsWithReturnRemainder("assertExpression(", function);
+ if (remainder != null) {
+ throw new UnsupportedOperationException("assertExpression is not
supported in csimple language");
+ }
+
+ remainder = ifStartsWithReturnRemainder("messageHistory", function);
+ if (remainder != null) {
+ boolean detailed;
+ String values = StringHelper.between(remainder, "(", ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ detailed = true;
+ } else {
+ detailed = Boolean.parseBoolean(values);
+ }
+ return "messageHistory(exchange, " + (detailed ? "true" : "false")
+ ")";
+ } else if (ObjectHelper.equal(function, "messageHistory")) {
+ return "messageHistory(exchange, true)";
+ }
+
+ remainder = ifStartsWithReturnRemainder("empty(", function);
+ if (remainder != null) {
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isEmpty(value)) {
+ throw new SimpleParserException("Valid syntax:
${empty(<type>)} but was: " + function, index);
+ }
+ return "newEmpty(exchange, " +
StringQuoteHelper.doubleQuote(value) + ")";
+ }
+
+ remainder = ifStartsWithReturnRemainder("newEmpty(", function);
+ if (remainder != null) {
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isEmpty(value)) {
+ throw new SimpleParserException("Valid syntax:
${newEmpty(<type>)} but was: " + function, index);
+ }
+ return "newEmpty(exchange, " +
StringQuoteHelper.doubleQuote(value) + ")";
+ }
+
+ remainder = ifStartsWithReturnRemainder("hash(", function);
+ if (remainder != null) {
+ return codeHash(remainder, function, index);
+ }
+
+ remainder = ifStartsWithReturnRemainder("uuid", function);
+ if (remainder == null && "uuid".equals(function)) {
+ remainder = "(default)";
+ }
+ if (remainder != null) {
+ return codeUuid(remainder, function);
+ }
+
+ remainder = ifStartsWithReturnRemainder("iif(", function);
+ if (remainder != null) {
+ return codeIif(remainder, function, index);
+ }
+
+ remainder = ifStartsWithReturnRemainder("load(", function);
+ if (remainder != null) {
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isEmpty(value)) {
+ throw new SimpleParserException("Valid syntax: ${load(name)}
but was: " + function, index);
+ }
+ if (StringHelper.isSingleQuoted(value)) {
+ value = StringHelper.removeLeadingAndEndingQuotes(value);
+ value = StringQuoteHelper.doubleQuote(value);
+ }
+ return "Object o = " + value + ";\n return load(exchange,
o);";
+ }
+
+ return null;
+ }
+
+ private static String codeUnaryObject(String name, String remainder,
String function, int index) {
+ String exp = null;
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(values)) {
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length != 1) {
+ throw new SimpleParserException("Valid syntax: ${" + name +
"(exp)} was: " + function, index);
+ }
+ String s = tokens[0];
+ if (StringHelper.isSingleQuoted(s)) {
+ s = StringHelper.removeLeadingAndEndingQuotes(s);
+ s = StringQuoteHelper.doubleQuote(s);
+ }
+ exp = s;
+ }
+ if (ObjectHelper.isEmpty(exp)) {
+ exp = "body";
+ }
+ return "Object o = " + exp + ";\n return " + name + "(exchange,
o);";
+ }
+
+ private static String codeConvertTo(String remainder, String function, int
index) {
+ String ognl = null;
+ String exp = "body";
+ String type;
+ String values = StringHelper.before(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${convertTo(type)} or
${convertTo(exp,type)} was: " + function, index);
+ }
+ if (values.contains(",")) {
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${convertTo(type)} or
${convertTo(exp,type)} was: " + function, index);
+ }
+ String s = tokens[0].trim();
+ s = StringHelper.removeLeadingAndEndingQuotes(s);
+ s = StringQuoteHelper.doubleQuote(s);
+ exp = s;
+ type = tokens[1];
+ } else {
+ type = values.trim();
+ }
+ type = appendClass(type);
+ type = type.replace('$', '.');
+ if (ObjectHelper.isEmpty(exp)) {
+ exp = "null";
+ }
+
+ remainder = StringHelper.after(remainder, ")");
+ if (ObjectHelper.isNotEmpty(remainder)) {
+ boolean invalid =
OgnlHelper.isInvalidValidOgnlExpression(remainder);
+ if (invalid) {
+ throw new SimpleParserException(
+ "Valid syntax: ${convertTo(type).OGNL} or
${convertTo(exp,type).OGNL} was: " + function, index);
+ }
+ ognl = ognlCodeMethods(remainder, type);
+ }
+
+ String code = "Object value = " + exp + ";\n return
convertTo(exchange, " + type + ", value)";
+ if (ognl != null) {
+ code += ognl;
+ }
+ code += ";";
+ return code;
+ }
+
+ private static String codeThrowException(String remainder, String
function, int index) {
+ String msg;
+ String type = "IllegalArgumentException";
+ String values = StringHelper.before(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${throwException(msg)} or
${throwException(msg,type)} was: " + function, index);
+ }
+ if (values.contains(",")) {
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${throwException(msg)} or
${throwException(msg,type)} was: " + function, index);
+ }
+ msg = tokens[0];
+ type = tokens[1];
+ } else {
+ msg = values.trim();
+ }
+ msg = StringHelper.removeLeadingAndEndingQuotes(msg);
+ msg = StringQuoteHelper.doubleQuote(msg);
+ type = appendClass(type);
+ type = type.replace('$', '.');
+ return "return throwException(exchange, " + msg + ", " + type + ");";
+ }
+
+ private static String codeHash(String remainder, String function, int
index) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${hash(value,algorithm)} or ${hash(value)}
was: " + function, index);
+ }
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${hash(value,algorithm)} or ${hash(value)}
was: " + function, index);
+ }
+ for (int i = 0; i < tokens.length; i++) {
+ String s = tokens[i];
+ if (StringHelper.isSingleQuoted(s)) {
+ s = StringHelper.removeLeadingAndEndingQuotes(s);
+ s = StringQuoteHelper.doubleQuote(s);
+ tokens[i] = s;
+ }
+ }
+ String algo = "\"SHA-256\"";
+ if (tokens.length == 2) {
+ algo = tokens[1];
+ if (!StringHelper.isQuoted(algo)) {
+ algo = StringQuoteHelper.doubleQuote(algo);
+ }
+ }
+ return "var val = " + tokens[0] + ";\n return hash(exchange,
val, " + algo + ");";
+ }
+
+ private static String codeUuid(String remainder, String function) {
+ String generator = StringHelper.between(remainder, "(", ")");
+ if (generator == null) {
+ generator = "default";
+ }
+ StringBuilder sb = new StringBuilder(128);
+ if ("classic".equals(generator)) {
+ sb.append(" UuidGenerator uuid = new
org.apache.camel.support.ClassicUuidGenerator();\n");
+ sb.append("return uuid.generateUuid();");
+ } else if ("short".equals(generator)) {
+ sb.append(" UuidGenerator uuid = new
org.apache.camel.support.ShortUuidGenerator();\n");
+ sb.append("return uuid.generateUuid();");
+ } else if ("simple".equals(generator)) {
+ sb.append(" UuidGenerator uuid = new
org.apache.camel.support.SimpleUuidGenerator();\n");
+ sb.append("return uuid.generateUuid();");
+ } else if ("default".equals(generator)) {
+ sb.append(" UuidGenerator uuid = new
org.apache.camel.support.DefaultUuidGenerator();\n");
+ sb.append("return uuid.generateUuid();");
+ } else if ("random".equals(generator)) {
+ sb.append(" UuidGenerator uuid = new
org.apache.camel.support.RandomUuidGenerator();\n");
+ sb.append("return uuid.generateUuid();");
+ } else {
+ generator = StringQuoteHelper.doubleQuote(generator);
+ sb.append("if (uuid == null) uuid = customUuidGenerator(exchange,
").append(generator)
+ .append("); return uuid.generateUuid();");
+ }
+ return sb.toString();
+ }
+
+ private static String codeIif(String remainder, String function, int
index) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax:
${iif(predicate,trueExpression,falseExpression)} was: " + function, index);
+ }
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length != 3) {
+ throw new SimpleParserException(
+ "Valid syntax:
${iif(predicate,trueExpression,falseExpression)} was: " + function, index);
+ }
+ for (int i = 0; i < 3; i++) {
+ String s = tokens[i];
+ if (StringHelper.isSingleQuoted(s)) {
+ s = StringHelper.removeLeadingAndEndingQuotes(s);
+ s = StringQuoteHelper.doubleQuote(s);
+ tokens[i] = s;
+ }
+ }
+ return "Object o = " + tokens[0]
+ + ";\n boolean b = convertTo(exchange, boolean.class,
o);\n return b ? "
+ + tokens[1] + " : " + tokens[2];
+ }
+}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/DirectFunctionFactoryTest.java
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/DirectFunctionFactoryTest.java
new file mode 100644
index 000000000000..e508686261a1
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/DirectFunctionFactoryTest.java
@@ -0,0 +1,181 @@
+/*
+ * 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.functions;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+
+public class DirectFunctionFactoryTest extends
AbstractSimpleFunctionFactoryTestSupport {
+
+ @Override
+ protected SimpleLanguageFunctionFactory createFactory() {
+ return new DirectFunctionFactory();
+ }
+
+ // --- expression evaluation ---
+
+ @Test
+ public void testId() {
+ assertNotNull(evaluate("id", String.class));
+ }
+
+ @Test
+ public void testExchangeId() {
+ assertEquals(exchange.getExchangeId(), evaluate("exchangeId",
String.class));
+ }
+
+ @Test
+ public void testExchange() {
+ assertSame(exchange, evaluate("exchange", Exchange.class));
+ }
+
+ @Test
+ public void testExceptionNull() {
+ assertNull(evaluate("exception"));
+ }
+
+ @Test
+ public void testExceptionMessage() {
+ exchange.setException(new IllegalStateException("boom"));
+ assertEquals("boom", evaluate("exception.message", String.class));
+ }
+
+ @Test
+ public void testExceptionStacktrace() {
+ exchange.setException(new IllegalStateException("boom"));
+ String trace = evaluate("exception.stacktrace", String.class);
+ assertNotNull(trace);
+ }
+
+ @Test
+ public void testThreadId() {
+ assertNotNull(evaluate("threadId"));
+ }
+
+ @Test
+ public void testThreadName() {
+ assertNotNull(evaluate("threadName", String.class));
+ }
+
+ @Test
+ public void testHostname() {
+ assertNotNull(evaluate("hostname", String.class));
+ }
+
+ @Test
+ public void testCamelId() {
+ assertEquals(context.getName(), evaluate("camelId", String.class));
+ }
+
+ @Test
+ public void testNull() {
+ assertNull(evaluate("null"));
+ }
+
+ // --- code generation ---
+
+ @Test
+ public void testCreateCodeId() {
+ assertEquals("message.getMessageId()", createCode("id"));
+ }
+
+ @Test
+ public void testCreateCodeMessageTimestamp() {
+ assertEquals("message.getMessageTimestamp()",
createCode("messageTimestamp"));
+ }
+
+ @Test
+ public void testCreateCodeExchangeId() {
+ assertEquals("exchange.getExchangeId()", createCode("exchangeId"));
+ }
+
+ @Test
+ public void testCreateCodeExchange() {
+ assertEquals("exchange", createCode("exchange"));
+ }
+
+ @Test
+ public void testCreateCodeLogExchange() {
+ assertEquals("logExchange(exchange)", createCode("logExchange"));
+ }
+
+ @Test
+ public void testCreateCodeException() {
+ assertEquals("exception(exchange)", createCode("exception"));
+ }
+
+ @Test
+ public void testCreateCodeExceptionMessage() {
+ assertEquals("exceptionMessage(exchange)",
createCode("exception.message"));
+ }
+
+ @Test
+ public void testCreateCodeExceptionStacktrace() {
+ assertEquals("exceptionStacktrace(exchange)",
createCode("exception.stacktrace"));
+ }
+
+ @Test
+ public void testCreateCodeThreadId() {
+ assertEquals("threadId()", createCode("threadId"));
+ }
+
+ @Test
+ public void testCreateCodeThreadName() {
+ assertEquals("threadName()", createCode("threadName"));
+ }
+
+ @Test
+ public void testCreateCodeHostname() {
+ assertEquals("hostName()", createCode("hostname"));
+ }
+
+ @Test
+ public void testCreateCodeCamelId() {
+ assertEquals("context.getName()", createCode("camelId"));
+ }
+
+ @Test
+ public void testCreateCodeRouteId() {
+ assertEquals("routeId(exchange)", createCode("routeId"));
+ }
+
+ @Test
+ public void testCreateCodeFromRouteId() {
+ assertEquals("fromRouteId(exchange)", createCode("fromRouteId"));
+ }
+
+ @Test
+ public void testCreateCodeStepId() {
+ assertEquals("stepId(exchange)", createCode("stepId"));
+ }
+
+ @Test
+ public void testCreateCodeNull() {
+ assertEquals("null", createCode("null"));
+ }
+
+ @Test
+ public void testCreateCodeUnknown() {
+ assertNull(createFactory().createCode(context, "unknown", 0));
+ }
+}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/MiscFunctionFactoryTest.java
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/MiscFunctionFactoryTest.java
new file mode 100644
index 000000000000..a5be49e28d1b
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/MiscFunctionFactoryTest.java
@@ -0,0 +1,266 @@
+/*
+ * 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.functions;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class MiscFunctionFactoryTest extends
AbstractSimpleFunctionFactoryTestSupport {
+
+ @Override
+ protected SimpleLanguageFunctionFactory createFactory() {
+ return new MiscFunctionFactory();
+ }
+
+ // --- isEmpty ---
+
+ @Test
+ public void testIsEmptyTrue() {
+ exchange.getIn().setBody("");
+ assertTrue((Boolean) evaluate("isEmpty(${body})"));
+ }
+
+ @Test
+ public void testIsEmptyFalse() {
+ exchange.getIn().setBody("hello");
+ assertFalse((Boolean) evaluate("isEmpty(${body})"));
+ }
+
+ // --- isAlpha ---
+
+ @Test
+ public void testIsAlphaTrue() {
+ exchange.getIn().setBody("hello");
+ assertTrue((Boolean) evaluate("isAlpha(${body})"));
+ }
+
+ @Test
+ public void testIsAlphaFalse() {
+ exchange.getIn().setBody("hello123");
+ assertFalse((Boolean) evaluate("isAlpha(${body})"));
+ }
+
+ // --- isAlphaNumeric ---
+
+ @Test
+ public void testIsAlphaNumericTrue() {
+ exchange.getIn().setBody("hello123");
+ assertTrue((Boolean) evaluate("isAlphaNumeric(${body})"));
+ }
+
+ @Test
+ public void testIsAlphaNumericFalse() {
+ exchange.getIn().setBody("hello 123");
+ assertFalse((Boolean) evaluate("isAlphaNumeric(${body})"));
+ }
+
+ // --- isNumeric ---
+
+ @Test
+ public void testIsNumericTrue() {
+ exchange.getIn().setBody("123");
+ assertTrue((Boolean) evaluate("isNumeric(${body})"));
+ }
+
+ @Test
+ public void testIsNumericFalse() {
+ exchange.getIn().setBody("abc");
+ assertFalse((Boolean) evaluate("isNumeric(${body})"));
+ }
+
+ // --- not ---
+
+ @Test
+ public void testNotEmpty() {
+ exchange.getIn().setBody("");
+ assertTrue((Boolean) evaluate("not(${body})"));
+ }
+
+ @Test
+ public void testNotNonEmpty() {
+ exchange.getIn().setBody("hello");
+ assertFalse((Boolean) evaluate("not(${body})"));
+ }
+
+ // --- convertTo ---
+
+ @Test
+ public void testConvertToString() {
+ exchange.getIn().setBody(42);
+ assertEquals("42", evaluate("convertTo(java.lang.String)",
String.class));
+ }
+
+ @Test
+ public void testConvertToInteger() {
+ exchange.getIn().setBody("42");
+ assertEquals(42, evaluate("convertTo(java.lang.Integer)",
Integer.class));
+ }
+
+ // --- uuid ---
+
+ @Test
+ public void testUuid() {
+ assertNotNull(evaluate("uuid", String.class));
+ }
+
+ // --- hash ---
+
+ @Test
+ public void testHash() {
+ exchange.getIn().setBody("hello");
+ String result = evaluate("hash(${body})", String.class);
+ assertNotNull(result);
+ assertFalse(result.isEmpty());
+ }
+
+ // --- empty / newEmpty ---
+
+ @Test
+ public void testEmpty() {
+ Object result = evaluate("empty(List)");
+ assertInstanceOf(List.class, result);
+ assertTrue(((List<?>) result).isEmpty());
+ }
+
+ @Test
+ public void testNewEmpty() {
+ Object result = evaluate("newEmpty(Map)");
+ assertInstanceOf(Map.class, result);
+ assertTrue(((Map<?, ?>) result).isEmpty());
+ }
+
+ // --- iif ---
+
+ @Test
+ public void testIifTrue() {
+ exchange.getIn().setBody(true);
+ assertEquals("'yes'", evaluate("iif(${body},'yes','no')",
String.class));
+ }
+
+ @Test
+ public void testIifFalse() {
+ exchange.getIn().setBody(false);
+ assertEquals("'no'", evaluate("iif(${body},'yes','no')",
String.class));
+ }
+
+ // --- code generation ---
+
+ @Test
+ public void testCreateCodeIsEmpty() {
+ assertEquals("Object o = ${body};\n return isEmpty(exchange,
o);", createCode("isEmpty(${body})"));
+ }
+
+ @Test
+ public void testCreateCodeIsAlpha() {
+ assertEquals("Object o = ${body};\n return isAlpha(exchange,
o);", createCode("isAlpha(${body})"));
+ }
+
+ @Test
+ public void testCreateCodeIsAlphaNumeric() {
+ assertEquals("Object o = ${body};\n return
isAlphaNumeric(exchange, o);",
+ createCode("isAlphaNumeric(${body})"));
+ }
+
+ @Test
+ public void testCreateCodeIsNumeric() {
+ assertEquals("Object o = ${body};\n return isNumeric(exchange,
o);", createCode("isNumeric(${body})"));
+ }
+
+ @Test
+ public void testCreateCodeKindOfType() {
+ assertEquals("Object o = body;\n return kindOfType(exchange,
o);", createCode("kindOfType()"));
+ }
+
+ @Test
+ public void testCreateCodeConvertTo() {
+ assertEquals("Object value = body;\n return convertTo(exchange,
java.lang.String.class, value);",
+ createCode("convertTo(java.lang.String)"));
+ }
+
+ @Test
+ public void testCreateCodeConvertToShortName() {
+ assertEquals("Object value = body;\n return convertTo(exchange,
String.class, value);",
+ createCode("convertTo(String)"));
+ }
+
+ @Test
+ public void testCreateCodeThrowException() {
+ assertEquals("return throwException(exchange, \"bad input\",
IllegalArgumentException.class);",
+ createCode("throwException('bad input')"));
+ }
+
+ @Test
+ public void testCreateCodeMessageHistory() {
+ assertEquals("messageHistory(exchange, true)",
createCode("messageHistory"));
+ }
+
+ @Test
+ public void testCreateCodeMessageHistoryFalse() {
+ assertEquals("messageHistory(exchange, false)",
createCode("messageHistory(false)"));
+ }
+
+ @Test
+ public void testCreateCodeEmpty() {
+ assertEquals("newEmpty(exchange, \"List\")",
createCode("empty(List)"));
+ }
+
+ @Test
+ public void testCreateCodeNewEmpty() {
+ assertEquals("newEmpty(exchange, \"Map\")",
createCode("newEmpty(Map)"));
+ }
+
+ @Test
+ public void testCreateCodeHash() {
+ assertEquals("var val = ${body};\n return hash(exchange, val,
\"SHA-256\");",
+ createCode("hash(${body})"));
+ }
+
+ @Test
+ public void testCreateCodeHashWithAlgorithm() {
+ assertEquals("var val = ${body};\n return hash(exchange, val,
\"MD5\");",
+ createCode("hash(${body},MD5)"));
+ }
+
+ @Test
+ public void testCreateCodeUuid() {
+ String code = createCode("uuid");
+ assertNotNull(code);
+ assertTrue(code.contains("generateUuid"));
+ }
+
+ @Test
+ public void testCreateCodeIif() {
+ assertEquals(
+ "Object o = ${body};\n boolean b = convertTo(exchange,
boolean.class, o);\n return b ? \"yes\" : \"no\"",
+ createCode("iif(${body},'yes','no')"));
+ }
+
+ @Test
+ public void testCreateCodeUnknown() {
+ assertNull(createFactory().createCode(context, "unknown", 0));
+ }
+}
diff --git a/docs/local-build.sh b/docs/local-build.sh
index cd375d8b38f7..8f07d6069f6a 100755
--- a/docs/local-build.sh
+++ b/docs/local-build.sh
@@ -17,8 +17,10 @@
# limitations under the License.
#
-CW=./../../camel-website
-LOCAL=./../camel
+CW="./../../camel-website"
-cd $CW || (echo 'camel-website not in expected location $CW' && exit)
-./antora-local-build.sh $LOCAL $*
+parent_path="${PWD%/*}"
+LOCAL="./../${parent_path##*/}"
+
+cd $CW || (echo "camel-website not in expected location $CW" && exit)
+./antora-local-build.sh "$LOCAL" "$@"