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 2972b41e58f9 CAMEL-22894: extract math and string Simple functions
into dedicated factories (#23388)
2972b41e58f9 is described below
commit 2972b41e58f949dfae8e2a9f87bf0c8c6f7c42d8
Author: Adriano Machado <[email protected]>
AuthorDate: Thu May 21 02:01:07 2026 -0400
CAMEL-22894: extract math and string Simple functions into dedicated
factories (#23388)
Extract abs/floor/ceil/sum/max/min/average into MathFunctionFactory and
replace/substring/substringBefore/substringAfter/substringBetween/contains/
trim/val/capitalize/pad/concat/quote/safeQuote/unquote/uppercase/lowercase/
length/size/normalizeWhitespace into StringFunctionFactory.
Consolidates the full codeSplitSafe implementation into SimpleFunctionHelper
(deprecating the delegation stub on SimpleFunctionExpression). Reduces
SimpleFunctionExpression from ~3600 to ~2300 lines.
Also fix a few typos present on the Simple language documentation.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
---
.../modules/languages/pages/simple-language.adoc | 18 +-
.../language/simple/SimpleFunctionDispatcher.java | 6 +-
.../language/simple/SimpleFunctionHelper.java | 111 +-
.../simple/ast/SimpleFunctionExpression.java | 1405 +-------------------
.../simple/functions/MathFunctionFactory.java | 164 +++
.../simple/functions/StringFunctionFactory.java | 687 ++++++++++
.../simple/functions/MathFunctionFactoryTest.java | 123 ++
.../functions/StringFunctionFactoryTest.java | 319 +++++
8 files changed, 1425 insertions(+), 1408 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 cd1a6a4dff83..5e9feaee135b 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
@@ -362,13 +362,13 @@ The condition functions is small functions that mostly
evaluates to a `boolean`
|====
|Function |Response Type |Description
|`assert(exp,msg)` | `null` | Evaluates the expression and throws an exception
with the message if the condition is false. This function is not supported when
using csimple.
-|`contains(text`) | `boolean` | Returns true if the message body contains part
of the text (ignore case)
-|`contains(exp,text`) | `boolean` | Returns true if the expression contains
part of the text (ignore case)
-|`iif(predicate,trueExp,falseExp`) | `Object` | The inlined if function
evaluates the predicate expression and returns the value of _trueExp_ if the
predicate is `true`, otherwise the value of `falseExp` is returned. This
function is similar to the ternary operator in Java.
+|`contains(text)` | `boolean` | Returns true if the message body contains part
of the text (ignore case)
+|`contains(exp,text)` | `boolean` | Returns true if the expression contains
part of the text (ignore case)
+|`iif(predicate,trueExp,falseExp)` | `Object` | The inlined if function
evaluates the predicate expression and returns the value of _trueExp_ if the
predicate is `true`, otherwise the value of `falseExp` is returned. This
function is similar to the ternary operator in Java.
|`isEmpty` | `boolean` | Whether the message body is `null` or empty (list/map
types are tested if they have 0 elements).
|`isEmpty(exp)` | `boolean` | Whether the expression is `null` or empty
(list/map types are tested if they have 0 elements).
-|`isAlpha()` | `boolean` | Whether the message body is numeric value (A..Z).
For more advanced checks use the `regex` operator.
-|`isAlpha(exp)` | `boolean` | Whether the expression is numeric value (A..Z).
For more advanced checks use the `regex` operator.
+|`isAlpha()` | `boolean` | Whether the message body is alphabetic value
(A..Z). For more advanced checks use the `regex` operator.
+|`isAlpha(exp)` | `boolean` | Whether the expression is alphabetic value
(A..Z). For more advanced checks use the `regex` operator.
|`isAlphaNumeric()` | `boolean` | Whether the message body is alphanumeric
value (A..Z0-9). For more advanced checks use the `regex` operator.
|`isAlphaNumeric(exp)` | `boolean` | Whether the expression is alphanumeric
value (A..Z0-9). For more advanced checks use the `regex` operator.
|`isNumeric()` | `boolean` | Whether the message body is numeric value (0..9).
For more advanced checks use the `regex` operator.
@@ -537,14 +537,14 @@ The string functions is various functions to work with
values that are String an
|`safeQuote()` | `String` | Returns the message body safely quoted if needed
|`safeQuote(exp)` | `String` | Returns the expression safely quoted if needed
|`substring(num1)` | `String` | Returns a substring of the message body. If
the number is positive, then the returned string is clipped from the beginning.
If the number is negative, then the returned string is clipped from the ending.
-|`substring(num1,num2)` | `String` | Returns a substring of the message body.
If the number is positive, then the returned string is clipped from the
beginning. If the number is negative, then the returned string is clipped from
the ending.
-|`substring(num1,num2,exp)` | `String` | Returns a substring of the given
expression. If the number is positive, then the returned string is clipped from
the beginning. If the number is negative, then the returned string is clipped
from the ending.
+|`substring(num1,num2)` | `String` | Returns a substring of the message body.
`num1` clips from the beginning, `num2` clips from the ending. Negative values
clip from the opposite end.
+|`substring(num1,num2,exp)` | `String` | Returns a substring of the given
expression. `num1` clips from the beginning, `num2` clips from the ending.
Negative values clip from the opposite end.
|`substringAfter(after)` | `String` | Returns a substring of the message body
that comes after. Returns `null` if nothing comes after.
|`substringAfter(exp,after)` | `String` | Returns a substring of the
expression that comes after. Returns `null` if nothing comes after.
|`substringBefore(before)` | `String` | Returns a substring of the message
body that comes before. Returns `null` if nothing comes before.
|`substringBefore(exp,before)` | `String` | Returns a substring of the
expression that comes before. Returns `null` if nothing comes before.
-|`substringBetween(after,before` | `String` | Returns a substring of the
message body that are between before and after. Returns `null` if nothing comes
between.
-|`substringBetween(exp,after,before` | `String` | Returns a substring of the
expression that are between before and after. Returns `null` if nothing comes
between.
+|`substringBetween(after,before)` | `String` | Returns a substring of the
message body that are between before and after. Returns `null` if nothing comes
between.
+|`substringBetween(exp,after,before)` | `String` | Returns a substring of the
expression that are between before and after. Returns `null` if nothing comes
between.
|`trim()` | `String` | The trim function trims the message body by removing
all leading and trailing white spaces.
|`trim(exp)` | `String` | The trim function trims the expression by removing
all leading and trailing white spaces.
|`unquote()` | `String` | Returns the message body with any leading/ending
quotes removed
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 0f41262c81dc..cca342857ee1 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
@@ -25,8 +25,10 @@ import
org.apache.camel.language.simple.functions.BodyFunctionFactory;
import org.apache.camel.language.simple.functions.CollateFunctionFactory;
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.RandomFunctionFactory;
import org.apache.camel.language.simple.functions.SkipFunctionFactory;
+import org.apache.camel.language.simple.functions.StringFunctionFactory;
import org.apache.camel.language.simple.functions.VariableFunctionFactory;
import org.apache.camel.spi.SimpleLanguageFunctionFactory;
import org.apache.camel.support.ResolverHelper;
@@ -57,7 +59,9 @@ public final class SimpleFunctionDispatcher {
new RandomFunctionFactory(),
new SkipFunctionFactory(),
new CollateFunctionFactory(),
- new JoinFunctionFactory());
+ new JoinFunctionFactory(),
+ new MathFunctionFactory(),
+ new StringFunctionFactory());
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/SimpleFunctionHelper.java
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionHelper.java
index 6e11f57f7c7a..ce70af1b4010 100644
---
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionHelper.java
+++
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionHelper.java
@@ -179,6 +179,7 @@ public final class SimpleFunctionHelper {
input = input.trim();
}
}
+ // no separator in data, so return single string with input as is
return new String[] { input };
}
@@ -196,6 +197,7 @@ public final class SimpleFunctionHelper {
boolean isQuoting = singleQuoted || doubleQuoted;
boolean last = i == input.length() - 1;
+ // do not split inside code blocks
if (input.indexOf(BaseSimpleParser.CODE_START, i) == i) {
codeLevel++;
sb.append(BaseSimpleParser.CODE_START);
@@ -213,65 +215,92 @@ public final class SimpleFunctionHelper {
}
if (!doubleQuoted && ch == '\'') {
- if (!singleQuoted) {
- singleQuoted = true;
+ if (singleQuoted && prev == ch && sb.isEmpty()) {
+ // its an empty quote so add empty text
if (keepQuotes) {
- sb.append(ch);
+ answer.add("''");
+ } else {
+ answer.add("");
}
- continue;
- } else if (prev != '\\') {
- singleQuoted = false;
- if (keepQuotes) {
- sb.append(ch);
+ }
+ // special logic needed if this quote is the end
+ if (last) {
+ if (singleQuoted && !sb.isEmpty()) {
+ String text = sb.toString();
+ // do not trim a quoted string
+ if (keepQuotes) {
+ answer.add(text + "'"); // append ending quote
+ } else {
+ answer.add(text);
+ }
+ sb.setLength(0);
}
- continue;
+ break; // break out as we are finished
+ }
+ singleQuoted = !singleQuoted;
+ if (keepQuotes) {
+ sb.append(ch);
}
+ continue;
} else if (!singleQuoted && ch == '"') {
- if (!doubleQuoted) {
- doubleQuoted = true;
+ if (doubleQuoted && prev == ch && sb.isEmpty()) {
+ // its an empty quote so add empty text
if (keepQuotes) {
- sb.append(ch);
+ answer.add("\""); // append ending quote
+ } else {
+ answer.add("");
}
- continue;
- } else if (prev != '\\') {
- doubleQuoted = false;
- if (keepQuotes) {
- sb.append(ch);
+ }
+ // special logic needed if this quote is the end
+ if (last) {
+ if (doubleQuoted && !sb.isEmpty()) {
+ String text = sb.toString();
+ // do not trim a quoted string
+ if (keepQuotes) {
+ answer.add(text + "\"");
+ } else {
+ answer.add(text);
+ }
+ sb.setLength(0);
}
- continue;
+ break; // break out as we are finished
}
- }
-
- if (isQuoting) {
- sb.append(ch);
+ doubleQuoted = !doubleQuoted;
+ if (keepQuotes) {
+ sb.append(ch);
+ }
+ continue;
+ } else if (!isQuoting && ch == separator) {
+ separating = true;
+ // add as answer if we are not in a quote
+ if (!sb.isEmpty()) {
+ String text = sb.toString();
+ if (trim) {
+ text = text.trim();
+ }
+ answer.add(text);
+ sb.setLength(0);
+ }
+ // we should avoid adding the separator
continue;
}
- if (ch == separator) {
- if (separating) {
- continue;
- }
- String s = sb.toString();
- if (trim) {
- s = s.trim();
- }
- answer.add(s);
- sb.setLength(0);
- separating = true;
+ if (trim && !isQuoting && separating && separator != ' ' && ch ==
' ') {
continue;
- } else if (separating) {
- separating = false;
}
+ separating = false;
+ // append char
sb.append(ch);
+ }
- if (last) {
- String s = sb.toString();
- if (trim) {
- s = s.trim();
- }
- answer.add(s);
+ // any leftover
+ if (!sb.isEmpty()) {
+ String text = sb.toString();
+ if (trim) {
+ text = text.trim();
}
+ answer.add(text);
}
return answer.toArray(new String[0]);
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 2e5d7ba037b3..f0b291e5aaff 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
@@ -17,9 +17,7 @@
package org.apache.camel.language.simple.ast;
import java.net.URISyntaxException;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.stream.Collectors;
@@ -389,11 +387,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
if (misc != null) {
return misc;
}
- // math functions
- Expression math = createSimpleExpressionMath(function);
- if (math != null) {
- return math;
- }
// functions from external components (attachments, base64, html, ...)
Expression external =
SimpleFunctionDispatcher.tryCreateExternal(camelContext, function,
token.getIndex());
@@ -707,169 +700,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return SimpleExpressionBuilder.setVariableExpression(name, type,
exp);
}
- // replace function
- remainder = ifStartsWithReturnRemainder("replace(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${replace(from,to)} or
${replace(from,to,expression)} was: " + function,
- token.getIndex());
- }
- String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
- if (tokens.length > 3) {
- throw new SimpleParserException(
- "Valid syntax: ${replace(from,to,expression)} was: " +
function, token.getIndex());
- }
- String from = StringHelper.xmlDecode(tokens[0]);
- String to = StringHelper.xmlDecode(tokens[1]);
- // special to make it easy to replace to an empty value (ie remove)
- if ("∅".equals(to)) {
- to = "";
- }
- String exp = "${body}";
- if (tokens.length == 3) {
- exp = tokens[2];
- }
- return SimpleExpressionBuilder.replaceExpression(exp, from, to);
- }
-
- // substring function
- remainder = ifStartsWithReturnRemainder("substring(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${substring(num)},
${substring(num,num)}, or ${substring(num,num,expression)} was: "
- + function,
- token.getIndex());
- }
- String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
- if (tokens.length > 3) {
- throw new SimpleParserException(
- "Valid syntax: ${substring(num,num,expression)} was: "
+ function, token.getIndex());
- }
- String num1 = tokens[0];
- String num2 = "0";
- if (tokens.length > 1) {
- num2 = tokens[1];
- }
- String exp = "${body}";
- if (tokens.length == 3) {
- exp = tokens[2];
- }
- return SimpleExpressionBuilder.substringExpression(exp, num1,
num2);
- }
- remainder = ifStartsWithReturnRemainder("substringBefore(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${substringBefore(exp)} or
${substringBefore(exp,exp)} was: "
- + function,
- token.getIndex());
- }
- String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
- if (tokens.length > 2) {
- throw new SimpleParserException(
- "Valid syntax: ${substringBefore(exp)} or
${substringBefore(exp,exp)} was: "
- + function,
- token.getIndex());
- }
- String exp1 = "${body}";
- String before;
- if (tokens.length == 2) {
- exp1 = tokens[0];
- before = tokens[1];
- } else {
- before = tokens[0];
- }
- return SimpleExpressionBuilder.substringBeforeExpression(exp1,
before);
- }
- remainder = ifStartsWithReturnRemainder("substringAfter(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${substringAfter(exp)} or
${substringAfter(exp,exp)} was: "
- + function,
- token.getIndex());
- }
- String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
- if (tokens.length > 2) {
- throw new SimpleParserException(
- "Valid syntax: ${substringAfter(exp)} or
${substringAfter(exp,exp)} was: "
- + function,
- token.getIndex());
- }
- String exp1 = "${body}";
- String after;
- if (tokens.length == 2) {
- exp1 = tokens[0];
- after = tokens[1];
- } else {
- after = tokens[0];
- }
- return SimpleExpressionBuilder.substringAfterExpression(exp1,
after);
- }
- remainder = ifStartsWithReturnRemainder("substringBetween(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${substringBetween(after,before)} or
${substringAfter(exp,after,before)} was: "
- + function,
- token.getIndex());
- }
- String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
- if (tokens.length < 2 || tokens.length > 3) {
- throw new SimpleParserException(
- "Valid syntax: ${substringBetween(after,before)} or
${substringAfter(exp,after,before)} was: "
- + function,
- token.getIndex());
- }
- String exp1 = "${body}";
- String after;
- String before;
- if (tokens.length == 3) {
- exp1 = tokens[0];
- after = tokens[1];
- before = tokens[2];
- } else {
- after = tokens[0];
- before = tokens[1];
- }
- return SimpleExpressionBuilder.substringBetweenExpression(exp1,
after, before);
- }
-
- // contains function
- remainder = ifStartsWithReturnRemainder("contains(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${contains(text)} or
${contains(exp,text)} was: "
- + function,
- token.getIndex());
- }
- String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
- if (tokens.length < 1 || tokens.length > 2) {
- throw new SimpleParserException(
- "Valid syntax: ${contains(text)} or
${contains(exp,text)} was: "
- + function,
- token.getIndex());
- }
- String exp = "${body}";
- String pattern;
- if (tokens.length == 1) {
- pattern = tokens[0];
- } else {
- exp = tokens[0];
- pattern = tokens[1];
- }
- return SimpleExpressionBuilder.containsExpression(exp, pattern);
- }
-
// range function
remainder = ifStartsWithReturnRemainder("range(", function);
if (remainder != null) {
@@ -1157,129 +987,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return SimpleExpressionBuilder.kindOfTypeExpression(exp);
}
- // quote function
- remainder = ifStartsWithReturnRemainder("quote(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.quoteExpression(exp);
- }
- // safeQuote function
- remainder = ifStartsWithReturnRemainder("safeQuote(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.safeQuoteExpression(exp);
- }
- // unquote function
- remainder = ifStartsWithReturnRemainder("unquote(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.unquoteExpression(exp);
- }
-
- // trim function
- remainder = ifStartsWithReturnRemainder("trim(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.trimExpression(exp);
- }
-
- // val function
- remainder = ifStartsWithReturnRemainder("val(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (value == null || ObjectHelper.isEmpty(value)) {
- throw new SimpleParserException(
- "Valid syntax: ${val(exp)} was: " + function,
- token.getIndex());
- }
- return ExpressionBuilder.simpleExpression(value);
- }
-
- // capitalize
- remainder = ifStartsWithReturnRemainder("capitalize(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.capitalizeExpression(exp);
- }
-
- // pad function
- remainder = ifStartsWithReturnRemainder("pad(", function);
- if (remainder != null) {
- String exp;
- String len;
- String separator = null;
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${pad(len)} or ${pad(exp,len)} or
${pad(exp,len,separator)} was: " + function,
- token.getIndex());
- }
- String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
true, true);
- if (tokens.length < 2 || tokens.length > 3) {
- throw new SimpleParserException(
- "Valid syntax: ${pad(exp,len)} or
${pad(exp,len,separator)} was: " + function,
- token.getIndex());
- }
- exp = StringHelper.removeQuotes(tokens[0]);
- len = StringHelper.removeQuotes(tokens[1]);
- if (tokens.length == 3) {
- separator = StringHelper.removeQuotes(tokens[2]);
- }
- return SimpleExpressionBuilder.padExpression(exp, len, separator);
- }
-
- // concat function
- remainder = ifStartsWithReturnRemainder("concat(", function);
- if (remainder != null) {
- String separator = null;
- String exp1 = "${body}";
- String exp2;
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${concat(exp)} or ${concat(exp,exp)} or
${concat(exp,exp,separator)} was: " + function,
- token.getIndex());
- }
- if (values.contains(",")) {
- String[] tokens = StringQuoteHelper.splitSafeQuote(values,
',', true, true);
- if (tokens.length > 3) {
- throw new SimpleParserException(
- "Valid syntax: ${concat(exp)} or
${concat(exp,exp)} or ${concat(exp,exp,separator)} was: "
- + function,
- token.getIndex());
- }
- exp1 = StringHelper.removeQuotes(tokens[0]);
- exp2 = StringHelper.removeQuotes(tokens[1]);
- if (tokens.length == 3) {
- separator = StringHelper.removeQuotes(tokens[2]);
- }
- } else {
- exp2 = StringHelper.removeQuotes(values.trim());
- }
- return SimpleExpressionBuilder.concatExpression(exp1, exp2,
separator);
- }
-
// throwException function
remainder = ifStartsWithReturnRemainder("throwException(", function);
if (remainder != null) {
@@ -1365,58 +1072,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
}
}
- // uppercase function
- remainder = ifStartsWithReturnRemainder("uppercase(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.uppercaseExpression(exp);
- }
- // lowercase function
- remainder = ifStartsWithReturnRemainder("lowercase(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.lowercaseExpression(exp);
- }
-
- // length function
- remainder = ifStartsWithReturnRemainder("length(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.lengthExpression(exp);
- }
- // size function
- remainder = ifStartsWithReturnRemainder("size(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.sizeExpression(exp);
- }
- // normalizeWhitespace function
- remainder = ifStartsWithReturnRemainder("normalizeWhitespace(",
function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.normalizeWhitespaceExpression(exp);
- }
-
// messageHistory function
remainder = ifStartsWithReturnRemainder("messageHistory", function);
if (remainder != null) {
@@ -1539,109 +1194,32 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return null;
}
- private Expression createSimpleExpressionMath(String function) {
- String remainder;
+ @Deprecated(since = "4.21")
+ public static String ifStartsWithReturnRemainder(String prefix, String
text) {
+ return SimpleFunctionHelper.ifStartsWithReturnRemainder(prefix, text);
+ }
- // abs function
- remainder = ifStartsWithReturnRemainder("abs(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.absExpression(exp);
+ @Override
+ public String createCode(CamelContext camelContext, String expression)
throws SimpleParserException {
+ return BaseSimpleParser.CODE_START + doCreateCode(camelContext,
expression) + BaseSimpleParser.CODE_END;
+ }
+
+ private String doCreateCode(CamelContext camelContext, String expression)
throws SimpleParserException {
+ String function = getText();
+
+ // return the function directly if we can create function without
analyzing the prefix
+ String answer = createCodeDirectly(function);
+ if (answer != null) {
+ return answer;
}
- // floor function
- remainder = ifStartsWithReturnRemainder("floor(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.floorExpression(exp);
+
+ // exchange property first
+ answer = createCodeExchangeProperty(function);
+ if (answer != null) {
+ return answer;
}
- // ceil function
- remainder = ifStartsWithReturnRemainder("ceil(", function);
- if (remainder != null) {
- String exp = null;
- String value = StringHelper.beforeLast(remainder, ")");
- if (ObjectHelper.isNotEmpty(value)) {
- exp = StringHelper.removeQuotes(value);
- }
- return SimpleExpressionBuilder.ceilExpression(exp);
- }
- // sum function
- remainder = ifStartsWithReturnRemainder("sum(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- String[] tokens = null;
- if (ObjectHelper.isNotEmpty(values)) {
- tokens = StringQuoteHelper.splitSafeQuote(values, ',', true,
false);
- }
- return SimpleExpressionBuilder.sumExpression(tokens);
- }
- // max function
- remainder = ifStartsWithReturnRemainder("max(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- String[] tokens = null;
- if (ObjectHelper.isNotEmpty(values)) {
- tokens = StringQuoteHelper.splitSafeQuote(values, ',', true,
false);
- }
- return SimpleExpressionBuilder.maxExpression(tokens);
- }
- // min function
- remainder = ifStartsWithReturnRemainder("min(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- String[] tokens = null;
- if (ObjectHelper.isNotEmpty(values)) {
- tokens = StringQuoteHelper.splitSafeQuote(values, ',', true,
false);
- }
- return SimpleExpressionBuilder.minExpression(tokens);
- }
- // average function
- remainder = ifStartsWithReturnRemainder("average(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- String[] tokens = null;
- if (ObjectHelper.isNotEmpty(values)) {
- tokens = StringQuoteHelper.splitSafeQuote(values, ',', true,
false);
- }
- return SimpleExpressionBuilder.averageExpression(tokens);
- }
-
- return null;
- }
-
- @Deprecated(since = "4.21")
- public static String ifStartsWithReturnRemainder(String prefix, String
text) {
- return SimpleFunctionHelper.ifStartsWithReturnRemainder(prefix, text);
- }
-
- @Override
- public String createCode(CamelContext camelContext, String expression)
throws SimpleParserException {
- return BaseSimpleParser.CODE_START + doCreateCode(camelContext,
expression) + BaseSimpleParser.CODE_END;
- }
-
- private String doCreateCode(CamelContext camelContext, String expression)
throws SimpleParserException {
- String function = getText();
-
- // return the function directly if we can create function without
analyzing the prefix
- String answer = createCodeDirectly(function);
- if (answer != null) {
- return answer;
- }
-
- // exchange property first
- answer = createCodeExchangeProperty(function);
- if (answer != null) {
- return answer;
- }
- // camelContext OGNL
- String remainder = ifStartsWithReturnRemainder("camelContext",
function);
+ // camelContext OGNL
+ String remainder = ifStartsWithReturnRemainder("camelContext",
function);
if (remainder != null) {
boolean invalid =
OgnlHelper.isInvalidValidOgnlExpression(remainder);
if (invalid) {
@@ -1831,11 +1409,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
if (misc != null) {
return misc;
}
- // math functions
- String math = createCodeExpressionMath(function);
- if (math != null) {
- return math;
- }
// code from external components (attachments, base64, ...)
String external =
SimpleFunctionDispatcher.tryCreateCodeExternal(camelContext, function,
token.getIndex());
@@ -2132,142 +1705,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return "Object value = " + exp + ";\n return
setVariable(exchange, " + name + ", " + type + ", value);";
}
- // substring function
- remainder = ifStartsWithReturnRemainder("substring(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${substring(num)},
${substring(num,num)} was: "
- + function,
- token.getIndex());
- }
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length > 2) {
- throw new SimpleParserException(
- "Valid syntax: ${substring(num,num)} was: " +
function, token.getIndex());
- }
- String num1 = tokens[0];
- String num2 = "0";
- if (tokens.length > 1) {
- num2 = tokens[1];
- }
- num1 = num1.trim();
- num2 = num2.trim();
- return "substring(exchange, " + num1 + ", " + num2 + ")";
- }
- remainder = ifStartsWithReturnRemainder("substringBefore(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${substringBefore(before)},
${substringBefore(exp,before)} was: "
- + function,
- token.getIndex());
- }
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length > 2) {
- throw new SimpleParserException(
- "Valid syntax: ${substringBefore(before)},
${substringBefore(exp,before)} was: "
- + function,
- token.getIndex());
- }
- // single quotes should be double quotes
- for (int i = 0; i < tokens.length; i++) {
- String s = tokens[i];
- if (StringHelper.isSingleQuoted(s)) {
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- tokens[i] = s;
- }
- }
- String body = "body";
- String before;
- if (tokens.length > 1) {
- body = tokens[0];
- before = tokens[1];
- } else {
- before = tokens[0];
- }
- return "Object value = " + body + ";\n Object before = " +
before
- + ";\n return substringBefore(exchange, value,
before);";
- }
- remainder = ifStartsWithReturnRemainder("substringAfter(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${substringAfter(before)},
${substringAfter(exp,before)} was: "
- + function,
- token.getIndex());
- }
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length > 2) {
- throw new SimpleParserException(
- "Valid syntax: ${substringAfter(before)},
${substringAfter(exp,before)} was: "
- + function,
- token.getIndex());
- }
- // single quotes should be double quotes
- for (int i = 0; i < tokens.length; i++) {
- String s = tokens[i];
- if (StringHelper.isSingleQuoted(s)) {
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- tokens[i] = s;
- }
- }
- String body = "body";
- String before;
- if (tokens.length > 1) {
- body = tokens[0];
- before = tokens[1];
- } else {
- before = tokens[0];
- }
- return "Object value = " + body + ";\n Object after = " +
before
- + ";\n return substringAfter(exchange, value,
after);";
- }
- remainder = ifStartsWithReturnRemainder("substringBetween(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${substringBetween(after,before)},
${substringBetween(exp,after,before)} was: "
- + function,
- token.getIndex());
- }
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length < 2 || tokens.length > 3) {
- throw new SimpleParserException(
- "Valid syntax: ${substringBetween(after,before)},
${substringBetween(exp,after,before)} was: "
- + function,
- token.getIndex());
- }
- // single quotes should be double quotes
- for (int i = 0; i < tokens.length; i++) {
- String s = tokens[i];
- if (StringHelper.isSingleQuoted(s)) {
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- tokens[i] = s;
- }
- }
- String body = "body";
- String after;
- String before;
- if (tokens.length == 3) {
- body = tokens[0];
- after = tokens[1];
- before = tokens[2];
- } else {
- after = tokens[0];
- before = tokens[1];
- }
- return "Object value = " + body + ";\n Object after = " +
after
- + ";\n Object before = " + before
- + ";\n return substringBetween(exchange, value,
after, before);";
- }
// split function
remainder = ifStartsWithReturnRemainder("split(", function);
if (remainder != null) {
@@ -2313,45 +1750,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
throw new UnsupportedOperationException("filter is not supported
in csimple language");
}
- // contains function
- remainder = ifStartsWithReturnRemainder("contains(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${contains(text)} or
${contains(exp,text)} was: "
- + function,
- token.getIndex());
- }
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length < 1 || tokens.length > 2) {
- throw new SimpleParserException(
- "Valid syntax: ${contains(text)} or
${contains(exp,text)} 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 exp = "body";
- String pattern;
- if (tokens.length == 1) {
- pattern = tokens[0];
- } else {
- exp = tokens[0];
- pattern = tokens[1];
- }
- pattern = StringHelper.removeLeadingAndEndingQuotes(pattern);
- pattern = StringQuoteHelper.doubleQuote(pattern);
- return "Object value = " + exp + ";\n return
containsIgnoreCase(exchange, value, " + pattern + ");";
- }
-
remainder = ifStartsWithReturnRemainder("range(", function);
if (remainder != null) {
String values = StringHelper.beforeLast(remainder, ")");
@@ -2373,37 +1771,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
}
}
- // replace function
- remainder = ifStartsWithReturnRemainder("replace(", function);
- if (remainder != null) {
- String values = StringHelper.before(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${replace(from,to)} was: " + function,
- token.getIndex());
- }
- String[] tokens = codeSplitSafe(values, ',', true, false);
- if (tokens.length > 2) {
- throw new SimpleParserException(
- "Valid syntax: ${replace(from,to)} was: " + function,
token.getIndex());
- }
- String from = StringHelper.xmlDecode(tokens[0]);
- String to = StringHelper.xmlDecode(tokens[1]);
- // special to make it easy to replace to an empty value (ie remove)
- if ("∅".equals(to)) {
- to = "";
- }
- if ("\"".equals(from)) {
- from = "\\\"";
- }
- if ("\"".equals(to)) {
- to = "\\\"";
- }
- from = StringQuoteHelper.doubleQuote(from);
- to = StringQuoteHelper.doubleQuote(to);
- return "replace(exchange, " + from + ", " + to + ")";
- }
-
// distinct function
remainder = ifStartsWithReturnRemainder("distinct(", function);
if (remainder != null) {
@@ -2468,42 +1835,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return "shuffle(exchange, " + p + ")";
}
- // pad function
- remainder = ifStartsWithReturnRemainder("pad(", function);
- if (remainder != null) {
- String separator = null;
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${pad(len)} or ${pad(exp,len)} or
${pad(exp,len,separator)} was: " + function,
- token.getIndex());
- }
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length < 2 || tokens.length > 3) {
- throw new SimpleParserException(
- "Valid syntax: ${pad(exp,len)} or
${pad(exp,len,separator)} 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;
- }
- }
- if (tokens.length == 3) {
- separator = tokens[2];
- }
- // separator must be in double quotes
- separator = StringHelper.removeLeadingAndEndingQuotes(separator);
- separator = separator != null ?
StringQuoteHelper.doubleQuote(separator) : "null";
- return "Object value = " + tokens[0] + ";\n " + "Object
width = " + tokens[1]
- + ";\n String separator = " + separator
- + ";\n return pad(exchange, value, width,
separator);";
- }
-
// kindOfType function
remainder = ifStartsWithReturnRemainder("kindOfType(", function);
if (remainder != null) {
@@ -2529,8 +1860,8 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return "Object o = " + exp + ";\n return
kindOfType(exchange, o);";
}
- // quote function
- remainder = ifStartsWithReturnRemainder("quote(", function);
+ // isEmpty function
+ remainder = ifStartsWithReturnRemainder("isEmpty(", function);
if (remainder != null) {
String exp = null;
String values = StringHelper.beforeLast(remainder, ")");
@@ -2538,7 +1869,7 @@ public class SimpleFunctionExpression extends
LiteralExpression {
String[] tokens = codeSplitSafe(values, ',', true, true);
if (tokens.length != 1) {
throw new SimpleParserException(
- "Valid syntax: ${quote(exp)} was: " + function,
token.getIndex());
+ "Valid syntax: ${isEmpty(exp)} was: " + function,
token.getIndex());
}
// single quotes should be double quotes
String s = tokens[0];
@@ -2549,12 +1880,13 @@ public class SimpleFunctionExpression extends
LiteralExpression {
exp = s;
}
if (ObjectHelper.isEmpty(exp)) {
- exp = "null";
+ exp = "body";
}
- return "Object o = " + exp + ";\n return quote(exchange,
o);";
+ return "Object o = " + exp + ";\n return isEmpty(exchange,
o);";
}
- // safaeQuote function
- remainder = ifStartsWithReturnRemainder("safeQuote(", function);
+
+ // isNumeric function
+ remainder = ifStartsWithReturnRemainder("isAlpha(", function);
if (remainder != null) {
String exp = null;
String values = StringHelper.beforeLast(remainder, ")");
@@ -2562,7 +1894,7 @@ public class SimpleFunctionExpression extends
LiteralExpression {
String[] tokens = codeSplitSafe(values, ',', true, true);
if (tokens.length != 1) {
throw new SimpleParserException(
- "Valid syntax: ${safeQuote(exp)} was: " +
function, token.getIndex());
+ "Valid syntax: ${isAlpha(exp)} was: " + function,
token.getIndex());
}
// single quotes should be double quotes
String s = tokens[0];
@@ -2575,10 +1907,10 @@ public class SimpleFunctionExpression extends
LiteralExpression {
if (ObjectHelper.isEmpty(exp)) {
exp = "body";
}
- return "Object o = " + exp + ";\n return
safeQuote(exchange, o);";
+ return "Object o = " + exp + ";\n return isAlpha(exchange,
o);";
}
- // unquote function
- remainder = ifStartsWithReturnRemainder("unquote(", function);
+ // isAlphaNumeric function
+ remainder = ifStartsWithReturnRemainder("isAlphaNumeric(", function);
if (remainder != null) {
String exp = null;
String values = StringHelper.beforeLast(remainder, ")");
@@ -2586,27 +1918,23 @@ public class SimpleFunctionExpression extends
LiteralExpression {
String[] tokens = codeSplitSafe(values, ',', true, true);
if (tokens.length != 1) {
throw new SimpleParserException(
- "Valid syntax: ${unquote(exp)} was: " + function,
token.getIndex());
+ "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);
- // need to escape double quotes
- s = s.replace("\"", "\\\"");
- // and enclose in a string
s = StringQuoteHelper.doubleQuote(s);
}
exp = s;
}
if (ObjectHelper.isEmpty(exp)) {
- exp = "null";
+ exp = "body";
}
- return "Object o = " + exp + ";\n return unquote(exchange,
o);";
+ return "Object o = " + exp + ";\n return
isAlphaNumeric(exchange, o);";
}
-
- // trim function
- remainder = ifStartsWithReturnRemainder("trim(", function);
+ // isNumeric function
+ remainder = ifStartsWithReturnRemainder("isNumeric(", function);
if (remainder != null) {
String exp = null;
String values = StringHelper.beforeLast(remainder, ")");
@@ -2614,7 +1942,7 @@ public class SimpleFunctionExpression extends
LiteralExpression {
String[] tokens = codeSplitSafe(values, ',', true, true);
if (tokens.length != 1) {
throw new SimpleParserException(
- "Valid syntax: ${trim(exp)} was: " + function,
token.getIndex());
+ "Valid syntax: ${isNumeric(exp)} was: " +
function, token.getIndex());
}
// single quotes should be double quotes
String s = tokens[0];
@@ -2625,127 +1953,14 @@ public class SimpleFunctionExpression extends
LiteralExpression {
exp = s;
}
if (ObjectHelper.isEmpty(exp)) {
- exp = "null";
- }
- return "Object o = " + exp + ";\n return trim(exchange,
o);";
- }
-
- // val function
- remainder = ifStartsWithReturnRemainder("val(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${val(exp)} was: " + function,
- token.getIndex());
+ exp = "body";
}
- String s = values;
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- return "Object o = " + s + ";\n return o;";
+ return "Object o = " + exp + ";\n return
isNumeric(exchange, o);";
}
-
- // isEmpty function
- remainder = ifStartsWithReturnRemainder("isEmpty(", function);
+ // not function
+ remainder = ifStartsWithReturnRemainder("not(", 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 exp = "body";
String values = StringHelper.beforeLast(remainder, ")");
if (ObjectHelper.isNotEmpty(values)) {
String[] tokens = codeSplitSafe(values, ',', true, true);
@@ -2762,79 +1977,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return "Object o = " + exp + ";\n return isNot(exchange,
o);";
}
- // capitalize function
- remainder = ifStartsWithReturnRemainder("capitalize(", 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: ${capitalize(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 = "null";
- }
- return "Object o = " + exp + ";\n return
capitalize(exchange, o);";
- }
-
- // concat function
- remainder = ifStartsWithReturnRemainder("concat(", function);
- if (remainder != null) {
- String separator = "null";
- String exp1 = "body";
- String exp2;
- String values = StringHelper.beforeLast(remainder, ")");
- if (values == null || ObjectHelper.isEmpty(values)) {
- throw new SimpleParserException(
- "Valid syntax: ${concat(exp)} or ${concat(exp,exp)} or
${concat(exp,exp,separator)} was: " + function,
- token.getIndex());
- }
- if (values.contains(",")) {
- String[] tokens = codeSplitSafe(values, ',', true, true);
- if (tokens.length > 3) {
- throw new SimpleParserException(
- "Valid syntax: ${concat(exp)} or
${concat(exp,exp)} or ${concat(exp,exp,separator)} 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;
- }
- }
- if (tokens.length == 1) {
- exp2 = tokens[0];
- } else {
- exp1 = tokens[0];
- exp2 = tokens[1];
- }
- if (tokens.length == 3) {
- separator = tokens[2];
- }
- } else {
- String s = values.trim();
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- exp2 = s;
- }
- return "Object right = " + exp2 + ";\n Object left = " +
exp1 + ";\n " + "Object separator = "
- + separator + ";\n return concat(exchange, left,
right, separator);";
- }
-
// convertTo function
remainder = ifStartsWithReturnRemainder("convertTo(", function);
if (remainder != null) {
@@ -2921,128 +2063,6 @@ public class SimpleFunctionExpression extends
LiteralExpression {
throw new UnsupportedOperationException("assertExpression is not
supported in csimple language");
}
- // uppercase function
- remainder = ifStartsWithReturnRemainder("uppercase(", 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: ${uppercase(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 = "null";
- }
- return "Object o = " + exp + ";\n return
uppercase(exchange, o);";
- }
- // lowercase
- remainder = ifStartsWithReturnRemainder("lowercase(", 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: ${lowercase(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 = "null";
- }
- return "Object o = " + exp + ";\n return
lowercase(exchange, o);";
- }
-
- // length function
- remainder = ifStartsWithReturnRemainder("length(", 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: ${length(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 length(exchange,
o);";
- }
- // size function
- remainder = ifStartsWithReturnRemainder("size(", 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: ${size(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 size(exchange,
o);";
- }
- // normalizeWhitespace function
- remainder = ifStartsWithReturnRemainder("normalizeWhitespace(",
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: ${normalizeWhitespace(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 = "null";
- }
- return "Object o = " + exp + ";\n return
normalizeWhitespace(exchange, o);";
- }
-
// messageHistory function
remainder = ifStartsWithReturnRemainder("messageHistory", function);
if (remainder != null) {
@@ -3259,343 +2279,14 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return null;
}
- private static List<String> splitOgnl(String remainder) {
- List<String> methods = OgnlHelper.splitOgnl(remainder);
- // if its a double index [foo][0] then we want them combined into a
single element
- List<String> answer = new ArrayList<>();
- for (String m : methods) {
- if (m.startsWith(".")) {
- m = m.substring(1);
- }
- boolean index = m.startsWith("[") && m.endsWith("]");
- if (index) {
- String last = answer.isEmpty() ? null :
answer.get(answer.size() - 1);
- boolean lastIndex = last != null && last.startsWith("[") &&
last.endsWith("]");
- if (lastIndex) {
- String line = last + m;
- answer.set(answer.size() - 1, line);
- } else {
- answer.add(m);
- }
- } else {
- answer.add(m);
- }
- }
-
- return answer;
- }
-
- private String createCodeExpressionMath(String function) {
- String remainder;
-
- // sum function
- remainder = ifStartsWithReturnRemainder("sum(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- String[] tokens = null;
- if (ObjectHelper.isNotEmpty(values)) {
- tokens = codeSplitSafe(values, ',', true, true);
- }
- StringJoiner sj = new StringJoiner(", ");
- for (int i = 0; tokens != null && i < tokens.length; i++) {
- String s = tokens[i];
- // single quotes should be double quotes
- if (StringHelper.isSingleQuoted(s)) {
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- }
- sj.add(s);
- }
- String p = sj.length() > 0 ? sj.toString() : "null";
- return "sum(exchange, " + p + ")";
- }
- // abs function
- remainder = ifStartsWithReturnRemainder("abs(", 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: ${abs(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 = "null";
- }
- return "Object o = " + exp + ";\n return abs(exchange, o);";
- }
- // floor function
- remainder = ifStartsWithReturnRemainder("floor(", 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: ${floor(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 = "null";
- }
- return "Object o = " + exp + ";\n return floor(exchange,
o);";
- }
- remainder = ifStartsWithReturnRemainder("ceil(", 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: ${ceil(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 = "null";
- }
- return "Object o = " + exp + ";\n return ceil(exchange,
o);";
- }
-
- // max function
- remainder = ifStartsWithReturnRemainder("max(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- String[] tokens = null;
- if (ObjectHelper.isNotEmpty(values)) {
- tokens = codeSplitSafe(values, ',', true, true);
- }
- StringJoiner sj = new StringJoiner(", ");
- for (int i = 0; tokens != null && i < tokens.length; i++) {
- String s = tokens[i];
- // single quotes should be double quotes
- if (StringHelper.isSingleQuoted(s)) {
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- }
- sj.add(s);
- }
- String p = sj.length() > 0 ? sj.toString() : "null";
- return "max(exchange, " + p + ")";
- }
- // min function
- remainder = ifStartsWithReturnRemainder("min(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- String[] tokens = null;
- if (ObjectHelper.isNotEmpty(values)) {
- tokens = codeSplitSafe(values, ',', true, true);
- }
- StringJoiner sj = new StringJoiner(", ");
- for (int i = 0; tokens != null && i < tokens.length; i++) {
- String s = tokens[i];
- // single quotes should be double quotes
- if (StringHelper.isSingleQuoted(s)) {
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- }
- sj.add(s);
- }
- String p = sj.length() > 0 ? sj.toString() : "null";
- return "min(exchange, " + p + ")";
- }
- // average function
- remainder = ifStartsWithReturnRemainder("average(", function);
- if (remainder != null) {
- String values = StringHelper.beforeLast(remainder, ")");
- String[] tokens = null;
- if (ObjectHelper.isNotEmpty(values)) {
- tokens = codeSplitSafe(values, ',', true, true);
- }
- StringJoiner sj = new StringJoiner(", ");
- for (int i = 0; tokens != null && i < tokens.length; i++) {
- String s = tokens[i];
- // single quotes should be double quotes
- if (StringHelper.isSingleQuoted(s)) {
- s = StringHelper.removeLeadingAndEndingQuotes(s);
- s = StringQuoteHelper.doubleQuote(s);
- }
- sj.add(s);
- }
- String p = sj.length() > 0 ? sj.toString() : "null";
- return "average(exchange, " + p + ")";
- }
-
- return null;
- }
-
@Deprecated(since = "4.21")
public static String ognlCodeMethods(String remainder, String type) {
return SimpleFunctionHelper.ognlCodeMethods(remainder, type);
}
+ @Deprecated(since = "4.21")
public static String[] codeSplitSafe(String input, char separator, boolean
trim, boolean keepQuotes) {
- if (input == null) {
- return null;
- }
-
- if (input.indexOf(separator) == -1) {
- if (input.length() > 1) {
- char ch = input.charAt(0);
- char ch2 = input.charAt(input.length() - 1);
- boolean singleQuoted = ch == '\'' && ch2 == '\'';
- boolean doubleQuoted = ch == '"' && ch2 == '"';
- if (!keepQuotes && (singleQuoted || doubleQuoted)) {
- input = input.substring(1, input.length() - 1);
- // do not trim quoted text
- } else if (trim) {
- input = input.trim();
- }
- }
- // no separator in data, so return single string with input as is
- return new String[] { input };
- }
-
- List<String> answer = new ArrayList<>();
- StringBuilder sb = new StringBuilder(256);
-
- int codeLevel = 0;
- boolean singleQuoted = false;
- boolean doubleQuoted = false;
- boolean separating = false;
-
- for (int i = 0; i < input.length(); i++) {
- char ch = input.charAt(i);
- char prev = i > 0 ? input.charAt(i - 1) : 0;
- boolean isQuoting = singleQuoted || doubleQuoted;
- boolean last = i == input.length() - 1;
-
- // do not split inside code blocks
- if (input.indexOf(BaseSimpleParser.CODE_START, i) == i) {
- codeLevel++;
- sb.append(BaseSimpleParser.CODE_START);
- i = i + BaseSimpleParser.CODE_START.length() - 1;
- continue;
- } else if (input.indexOf(BaseSimpleParser.CODE_END, i) == i) {
- codeLevel--;
- sb.append(BaseSimpleParser.CODE_END);
- i = i + BaseSimpleParser.CODE_END.length() - 1;
- continue;
- }
- if (codeLevel > 0) {
- sb.append(ch);
- continue;
- }
-
- if (!doubleQuoted && ch == '\'') {
- if (singleQuoted && prev == ch && sb.isEmpty()) {
- // its an empty quote so add empty text
- if (keepQuotes) {
- answer.add("''");
- } else {
- answer.add("");
- }
- }
- // special logic needed if this quote is the end
- if (last) {
- if (singleQuoted && !sb.isEmpty()) {
- String text = sb.toString();
- // do not trim a quoted string
- if (keepQuotes) {
- answer.add(text + "'"); // append ending quote
- } else {
- answer.add(text);
- }
- sb.setLength(0);
- }
- break; // break out as we are finished
- }
- singleQuoted = !singleQuoted;
- if (keepQuotes) {
- sb.append(ch);
- }
- continue;
- } else if (!singleQuoted && ch == '"') {
- if (doubleQuoted && prev == ch && sb.isEmpty()) {
- // its an empty quote so add empty text
- if (keepQuotes) {
- answer.add("\""); // append ending quote
- } else {
- answer.add("");
- }
- }
- // special logic needed if this quote is the end
- if (last) {
- if (doubleQuoted && !sb.isEmpty()) {
- String text = sb.toString();
- // do not trim a quoted string
- if (keepQuotes) {
- answer.add(text + "\"");
- } else {
- answer.add(text);
- }
- sb.setLength(0);
- }
- break; // break out as we are finished
- }
- doubleQuoted = !doubleQuoted;
- if (keepQuotes) {
- sb.append(ch);
- }
- continue;
- } else if (!isQuoting && ch == separator) {
- separating = true;
- // add as answer if we are not in a quote
- if (!sb.isEmpty()) {
- String text = sb.toString();
- if (trim) {
- text = text.trim();
- }
- answer.add(text);
- sb.setLength(0);
- }
- // we should avoid adding the separator
- continue;
- }
-
- if (trim && !isQuoting && separating && separator != ' ' && ch ==
' ') {
- continue;
- }
- separating = false;
-
- // append char
- sb.append(ch);
- }
-
- // any leftover
- if (!sb.isEmpty()) {
- String text = sb.toString();
- if (trim) {
- text = text.trim();
- }
- answer.add(text);
- }
-
- return answer.toArray(new String[0]);
+ return SimpleFunctionHelper.codeSplitSafe(input, separator, trim,
keepQuotes);
}
}
diff --git
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/MathFunctionFactory.java
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/MathFunctionFactory.java
new file mode 100644
index 000000000000..bbd3e1e97f4f
--- /dev/null
+++
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/MathFunctionFactory.java
@@ -0,0 +1,164 @@
+/*
+ * 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.StringJoiner;
+
+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.StringHelper;
+import org.apache.camel.util.StringQuoteHelper;
+
+import static
org.apache.camel.language.simple.SimpleFunctionHelper.codeSplitSafe;
+import static
org.apache.camel.language.simple.SimpleFunctionHelper.ifStartsWithReturnRemainder;
+
+/**
+ * Built-in Simple math functions: {@code ${abs}}, {@code ${floor}}, {@code
${ceil}}, {@code ${sum}}, {@code ${max}},
+ * {@code ${min}}, {@code ${average}}.
+ */
+public final class MathFunctionFactory implements
SimpleLanguageFunctionFactory {
+
+ @Override
+ public Expression createFunction(CamelContext camelContext, String
function, int index) {
+ String remainder;
+
+ remainder = ifStartsWithReturnRemainder("abs(", function);
+ if (remainder != null) {
+ String value = StringHelper.beforeLast(remainder, ")");
+ return SimpleExpressionBuilder
+ .absExpression(ObjectHelper.isNotEmpty(value) ?
StringHelper.removeQuotes(value) : null);
+ }
+ remainder = ifStartsWithReturnRemainder("floor(", function);
+ if (remainder != null) {
+ String value = StringHelper.beforeLast(remainder, ")");
+ return SimpleExpressionBuilder.floorExpression(
+ ObjectHelper.isNotEmpty(value) ?
StringHelper.removeQuotes(value) : null);
+ }
+ remainder = ifStartsWithReturnRemainder("ceil(", function);
+ if (remainder != null) {
+ String value = StringHelper.beforeLast(remainder, ")");
+ return SimpleExpressionBuilder.ceilExpression(
+ ObjectHelper.isNotEmpty(value) ?
StringHelper.removeQuotes(value) : null);
+ }
+ remainder = ifStartsWithReturnRemainder("sum(", function);
+ if (remainder != null) {
+ return
SimpleExpressionBuilder.sumExpression(parseVariadicTokens(remainder));
+ }
+ remainder = ifStartsWithReturnRemainder("max(", function);
+ if (remainder != null) {
+ return
SimpleExpressionBuilder.maxExpression(parseVariadicTokens(remainder));
+ }
+ remainder = ifStartsWithReturnRemainder("min(", function);
+ if (remainder != null) {
+ return
SimpleExpressionBuilder.minExpression(parseVariadicTokens(remainder));
+ }
+ remainder = ifStartsWithReturnRemainder("average(", function);
+ if (remainder != null) {
+ return
SimpleExpressionBuilder.averageExpression(parseVariadicTokens(remainder));
+ }
+
+ return null;
+ }
+
+ @Override
+ public String createCode(CamelContext camelContext, String function, int
index) {
+ String remainder;
+
+ remainder = ifStartsWithReturnRemainder("sum(", function);
+ if (remainder != null) {
+ return codeVariadic("sum", remainder);
+ }
+ remainder = ifStartsWithReturnRemainder("abs(", function);
+ if (remainder != null) {
+ return codeUnary("abs", remainder, function, index);
+ }
+ remainder = ifStartsWithReturnRemainder("floor(", function);
+ if (remainder != null) {
+ return codeUnary("floor", remainder, function, index);
+ }
+ remainder = ifStartsWithReturnRemainder("ceil(", function);
+ if (remainder != null) {
+ return codeUnary("ceil", remainder, function, index);
+ }
+ remainder = ifStartsWithReturnRemainder("max(", function);
+ if (remainder != null) {
+ return codeVariadic("max", remainder);
+ }
+ remainder = ifStartsWithReturnRemainder("min(", function);
+ if (remainder != null) {
+ return codeVariadic("min", remainder);
+ }
+ remainder = ifStartsWithReturnRemainder("average(", function);
+ if (remainder != null) {
+ return codeVariadic("average", remainder);
+ }
+
+ return null;
+ }
+
+ private static String[] parseVariadicTokens(String remainder) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(values)) {
+ return StringQuoteHelper.splitSafeQuote(values, ',', true, false);
+ }
+ return null;
+ }
+
+ private static String codeUnary(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 = "null";
+ }
+ return "Object o = " + exp + ";\n return " + name + "(exchange,
o);";
+ }
+
+ private static String codeVariadic(String name, String remainder) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ String[] tokens = null;
+ if (ObjectHelper.isNotEmpty(values)) {
+ tokens = codeSplitSafe(values, ',', true, true);
+ }
+ StringJoiner sj = new StringJoiner(", ");
+ for (int i = 0; tokens != null && i < tokens.length; i++) {
+ String s = tokens[i];
+ if (StringHelper.isSingleQuoted(s)) {
+ s = StringHelper.removeLeadingAndEndingQuotes(s);
+ s = StringQuoteHelper.doubleQuote(s);
+ }
+ sj.add(s);
+ }
+ String p = sj.length() > 0 ? sj.toString() : "null";
+ return name + "(exchange, " + p + ")";
+ }
+}
diff --git
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/StringFunctionFactory.java
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/StringFunctionFactory.java
new file mode 100644
index 000000000000..442c9be46086
--- /dev/null
+++
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/StringFunctionFactory.java
@@ -0,0 +1,687 @@
+/*
+ * 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.support.builder.ExpressionBuilder;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
+import org.apache.camel.util.StringQuoteHelper;
+
+import static
org.apache.camel.language.simple.SimpleFunctionHelper.codeSplitSafe;
+import static
org.apache.camel.language.simple.SimpleFunctionHelper.ifStartsWithReturnRemainder;
+
+/**
+ * Built-in Simple string functions: {@code ${replace}}, {@code ${substring}},
{@code ${substringBefore}},
+ * {@code ${substringAfter}}, {@code ${substringBetween}}, {@code
${contains}}, {@code ${trim}}, {@code ${val}},
+ * {@code ${capitalize}}, {@code ${pad}}, {@code ${concat}}, {@code ${quote}},
{@code ${safeQuote}}, {@code ${unquote}},
+ * {@code ${uppercase}}, {@code ${lowercase}}, {@code ${length}}, {@code
${size}}, {@code ${normalizeWhitespace}}.
+ */
+public final class StringFunctionFactory implements
SimpleLanguageFunctionFactory {
+
+ @Override
+ public Expression createFunction(CamelContext camelContext, String
function, int index) {
+ String remainder;
+
+ remainder = ifStartsWithReturnRemainder("replace(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${replace(from,to)} or
${replace(from,to,expression)} was: " + function, index);
+ }
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
+ if (tokens.length > 3) {
+ throw new SimpleParserException(
+ "Valid syntax: ${replace(from,to,expression)} was: " +
function, index);
+ }
+ String from = StringHelper.xmlDecode(tokens[0]);
+ String to = StringHelper.xmlDecode(tokens[1]);
+ if ("∅".equals(to)) {
+ to = "";
+ }
+ String exp = "${body}";
+ if (tokens.length == 3) {
+ exp = tokens[2];
+ }
+ return SimpleExpressionBuilder.replaceExpression(exp, from, to);
+ }
+
+ remainder = ifStartsWithReturnRemainder("substring(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substring(num)},
${substring(num,num)}, or ${substring(num,num,expression)} was: "
+ + function,
+ index);
+ }
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
+ if (tokens.length > 3) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substring(num,num,expression)} was: "
+ function, index);
+ }
+ String num1 = tokens[0];
+ String num2 = "0";
+ if (tokens.length > 1) {
+ num2 = tokens[1];
+ }
+ String exp = "${body}";
+ if (tokens.length == 3) {
+ exp = tokens[2];
+ }
+ return SimpleExpressionBuilder.substringExpression(exp, num1,
num2);
+ }
+
+ remainder = ifStartsWithReturnRemainder("substringBefore(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringBefore(exp)} or
${substringBefore(exp,exp)} was: " + function, index);
+ }
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringBefore(exp)} or
${substringBefore(exp,exp)} was: " + function, index);
+ }
+ String exp1 = "${body}";
+ String before;
+ if (tokens.length == 2) {
+ exp1 = tokens[0];
+ before = tokens[1];
+ } else {
+ before = tokens[0];
+ }
+ return SimpleExpressionBuilder.substringBeforeExpression(exp1,
before);
+ }
+
+ remainder = ifStartsWithReturnRemainder("substringAfter(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringAfter(exp)} or
${substringAfter(exp,exp)} was: " + function, index);
+ }
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringAfter(exp)} or
${substringAfter(exp,exp)} was: " + function, index);
+ }
+ String exp1 = "${body}";
+ String after;
+ if (tokens.length == 2) {
+ exp1 = tokens[0];
+ after = tokens[1];
+ } else {
+ after = tokens[0];
+ }
+ return SimpleExpressionBuilder.substringAfterExpression(exp1,
after);
+ }
+
+ remainder = ifStartsWithReturnRemainder("substringBetween(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringBetween(after,before)} or
${substringAfter(exp,after,before)} was: "
+ + function,
+ index);
+ }
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
+ if (tokens.length < 2 || tokens.length > 3) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringBetween(after,before)} or
${substringAfter(exp,after,before)} was: "
+ + function,
+ index);
+ }
+ String exp1 = "${body}";
+ String after;
+ String before;
+ if (tokens.length == 3) {
+ exp1 = tokens[0];
+ after = tokens[1];
+ before = tokens[2];
+ } else {
+ after = tokens[0];
+ before = tokens[1];
+ }
+ return SimpleExpressionBuilder.substringBetweenExpression(exp1,
after, before);
+ }
+
+ remainder = ifStartsWithReturnRemainder("contains(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${contains(text)} or
${contains(exp,text)} was: " + function, index);
+ }
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
+ if (tokens.length < 1 || tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${contains(text)} or
${contains(exp,text)} was: " + function, index);
+ }
+ String exp = "${body}";
+ String pattern;
+ if (tokens.length == 1) {
+ pattern = tokens[0];
+ } else {
+ exp = tokens[0];
+ pattern = tokens[1];
+ }
+ return SimpleExpressionBuilder.containsExpression(exp, pattern);
+ }
+
+ remainder = ifStartsWithReturnRemainder("trim(", function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.trimExpression(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("val(", function);
+ if (remainder != null) {
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (value == null || ObjectHelper.isEmpty(value)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${val(exp)} was: " + function, index);
+ }
+ return ExpressionBuilder.simpleExpression(value);
+ }
+
+ remainder = ifStartsWithReturnRemainder("capitalize(", function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.capitalizeExpression(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("pad(", function);
+ if (remainder != null) {
+ String exp;
+ String len;
+ String separator = null;
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${pad(len)} or ${pad(exp,len)} or
${pad(exp,len,separator)} was: " + function,
+ index);
+ }
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
true, true);
+ if (tokens.length < 2 || tokens.length > 3) {
+ throw new SimpleParserException(
+ "Valid syntax: ${pad(exp,len)} or
${pad(exp,len,separator)} was: " + function, index);
+ }
+ exp = StringHelper.removeQuotes(tokens[0]);
+ len = StringHelper.removeQuotes(tokens[1]);
+ if (tokens.length == 3) {
+ separator = StringHelper.removeQuotes(tokens[2]);
+ }
+ return SimpleExpressionBuilder.padExpression(exp, len, separator);
+ }
+
+ remainder = ifStartsWithReturnRemainder("concat(", function);
+ if (remainder != null) {
+ String separator = null;
+ String exp1 = "${body}";
+ String exp2;
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${concat(exp)} or ${concat(exp,exp)} or
${concat(exp,exp,separator)} was: "
+ + function,
+ index);
+ }
+ if (values.contains(",")) {
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values,
',', true, true);
+ if (tokens.length > 3) {
+ throw new SimpleParserException(
+ "Valid syntax: ${concat(exp)} or
${concat(exp,exp)} or ${concat(exp,exp,separator)} was: "
+ + function,
+ index);
+ }
+ exp1 = StringHelper.removeQuotes(tokens[0]);
+ exp2 = StringHelper.removeQuotes(tokens[1]);
+ if (tokens.length == 3) {
+ separator = StringHelper.removeQuotes(tokens[2]);
+ }
+ } else {
+ exp2 = StringHelper.removeQuotes(values.trim());
+ }
+ return SimpleExpressionBuilder.concatExpression(exp1, exp2,
separator);
+ }
+
+ remainder = ifStartsWithReturnRemainder("quote(", function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.quoteExpression(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("safeQuote(", function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.safeQuoteExpression(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("unquote(", function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.unquoteExpression(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("uppercase(", function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.uppercaseExpression(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("lowercase(", function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.lowercaseExpression(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("length(", function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.lengthExpression(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("size(", function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.sizeExpression(exp);
+ }
+
+ remainder = ifStartsWithReturnRemainder("normalizeWhitespace(",
function);
+ if (remainder != null) {
+ String exp = null;
+ String value = StringHelper.beforeLast(remainder, ")");
+ if (ObjectHelper.isNotEmpty(value)) {
+ exp = StringHelper.removeQuotes(value);
+ }
+ return SimpleExpressionBuilder.normalizeWhitespaceExpression(exp);
+ }
+
+ return null;
+ }
+
+ @Override
+ public String createCode(CamelContext camelContext, String function, int
index) {
+ String remainder;
+
+ remainder = ifStartsWithReturnRemainder("substring(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substring(num)},
${substring(num,num)} was: " + function, index);
+ }
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substring(num,num)} was: " +
function, index);
+ }
+ String num1 = tokens[0].trim();
+ String num2 = tokens.length > 1 ? tokens[1].trim() : "0";
+ return "substring(exchange, " + num1 + ", " + num2 + ")";
+ }
+
+ remainder = ifStartsWithReturnRemainder("substringBefore(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringBefore(before)},
${substringBefore(exp,before)} was: " + function,
+ index);
+ }
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringBefore(before)},
${substringBefore(exp,before)} was: " + function,
+ index);
+ }
+ for (int i = 0; i < tokens.length; i++) {
+ tokens[i] = squoteToDouble(tokens[i]);
+ }
+ String body = tokens.length > 1 ? tokens[0] : "body";
+ String before = tokens.length > 1 ? tokens[1] : tokens[0];
+ return "Object value = " + body + ";\n Object before = " +
before
+ + ";\n return substringBefore(exchange, value,
before);";
+ }
+
+ remainder = ifStartsWithReturnRemainder("substringAfter(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringAfter(before)},
${substringAfter(exp,before)} was: " + function,
+ index);
+ }
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringAfter(before)},
${substringAfter(exp,before)} was: " + function,
+ index);
+ }
+ for (int i = 0; i < tokens.length; i++) {
+ tokens[i] = squoteToDouble(tokens[i]);
+ }
+ String body = tokens.length > 1 ? tokens[0] : "body";
+ String after = tokens.length > 1 ? tokens[1] : tokens[0];
+ return "Object value = " + body + ";\n Object after = " +
after
+ + ";\n return substringAfter(exchange, value,
after);";
+ }
+
+ remainder = ifStartsWithReturnRemainder("substringBetween(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringBetween(after,before)},
${substringBetween(exp,after,before)} was: "
+ + function,
+ index);
+ }
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length < 2 || tokens.length > 3) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substringBetween(after,before)},
${substringBetween(exp,after,before)} was: "
+ + function,
+ index);
+ }
+ for (int i = 0; i < tokens.length; i++) {
+ tokens[i] = squoteToDouble(tokens[i]);
+ }
+ String body = tokens.length == 3 ? tokens[0] : "body";
+ String after = tokens.length == 3 ? tokens[1] : tokens[0];
+ String before = tokens.length == 3 ? tokens[2] : tokens[1];
+ return "Object value = " + body + ";\n Object after = " +
after
+ + ";\n Object before = " + before
+ + ";\n return substringBetween(exchange, value,
after, before);";
+ }
+
+ remainder = ifStartsWithReturnRemainder("contains(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${contains(text)} or
${contains(exp,text)} was: " + function, index);
+ }
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length < 1 || tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${contains(text)} or
${contains(exp,text)} was: " + function, index);
+ }
+ for (int i = 0; i < tokens.length; i++) {
+ tokens[i] = squoteToDouble(tokens[i]);
+ }
+ String exp = tokens.length == 1 ? "body" : tokens[0];
+ String pattern = tokens.length == 1 ? tokens[0] : tokens[1];
+ pattern = StringHelper.removeLeadingAndEndingQuotes(pattern);
+ pattern = StringQuoteHelper.doubleQuote(pattern);
+ return "Object value = " + exp + ";\n return
containsIgnoreCase(exchange, value, " + pattern + ");";
+ }
+
+ remainder = ifStartsWithReturnRemainder("replace(", function);
+ if (remainder != null) {
+ String values = StringHelper.before(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${replace(from,to)} was: " + function,
index);
+ }
+ String[] tokens = codeSplitSafe(values, ',', true, false);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${replace(from,to)} was: " + function,
index);
+ }
+ String from = StringHelper.xmlDecode(tokens[0]);
+ String to = StringHelper.xmlDecode(tokens[1]);
+ if ("∅".equals(to)) {
+ to = "";
+ }
+ if ("\"".equals(from)) {
+ from = "\\\"";
+ }
+ if ("\"".equals(to)) {
+ to = "\\\"";
+ }
+ from = StringQuoteHelper.doubleQuote(from);
+ to = StringQuoteHelper.doubleQuote(to);
+ return "replace(exchange, " + from + ", " + to + ")";
+ }
+
+ remainder = ifStartsWithReturnRemainder("trim(", function);
+ if (remainder != null) {
+ return codeSimpleUnary("trim", remainder, function, index, "null");
+ }
+
+ remainder = ifStartsWithReturnRemainder("val(", function);
+ if (remainder != null) {
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${val(exp)} was: " + function, index);
+ }
+ String s = StringHelper.removeLeadingAndEndingQuotes(values);
+ s = StringQuoteHelper.doubleQuote(s);
+ return "Object o = " + s + ";\n return o;";
+ }
+
+ remainder = ifStartsWithReturnRemainder("capitalize(", function);
+ if (remainder != null) {
+ return codeSimpleUnary("capitalize", remainder, function, index,
"null");
+ }
+
+ remainder = ifStartsWithReturnRemainder("pad(", function);
+ if (remainder != null) {
+ String separator = null;
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${pad(len)} or ${pad(exp,len)} or
${pad(exp,len,separator)} was: " + function,
+ index);
+ }
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length < 2 || tokens.length > 3) {
+ throw new SimpleParserException(
+ "Valid syntax: ${pad(exp,len)} or
${pad(exp,len,separator)} was: " + function, index);
+ }
+ for (int i = 0; i < tokens.length; i++) {
+ tokens[i] = squoteToDouble(tokens[i]);
+ }
+ if (tokens.length == 3) {
+ separator = tokens[2];
+ }
+ separator = StringHelper.removeLeadingAndEndingQuotes(separator);
+ separator = separator != null ?
StringQuoteHelper.doubleQuote(separator) : "null";
+ return "Object value = " + tokens[0] + ";\n " + "Object
width = " + tokens[1]
+ + ";\n String separator = " + separator
+ + ";\n return pad(exchange, value, width,
separator);";
+ }
+
+ remainder = ifStartsWithReturnRemainder("concat(", function);
+ if (remainder != null) {
+ String separator = "null";
+ String exp1 = "body";
+ String exp2;
+ String values = StringHelper.beforeLast(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${concat(exp)} or ${concat(exp,exp)} or
${concat(exp,exp,separator)} was: "
+ + function,
+ index);
+ }
+ if (values.contains(",")) {
+ String[] tokens = codeSplitSafe(values, ',', true, true);
+ if (tokens.length > 3) {
+ throw new SimpleParserException(
+ "Valid syntax: ${concat(exp)} or
${concat(exp,exp)} or ${concat(exp,exp,separator)} was: "
+ + function,
+ index);
+ }
+ for (int i = 0; i < tokens.length; i++) {
+ tokens[i] = squoteToDouble(tokens[i]);
+ }
+ if (tokens.length == 1) {
+ exp2 = tokens[0];
+ } else {
+ exp1 = tokens[0];
+ exp2 = tokens[1];
+ }
+ if (tokens.length == 3) {
+ separator = tokens[2];
+ }
+ } else {
+ String s = values.trim();
+ s = StringHelper.removeLeadingAndEndingQuotes(s);
+ s = StringQuoteHelper.doubleQuote(s);
+ exp2 = s;
+ }
+ return "Object right = " + exp2 + ";\n Object left = " +
exp1 + ";\n " + "Object separator = "
+ + separator + ";\n return concat(exchange, left,
right, separator);";
+ }
+
+ remainder = ifStartsWithReturnRemainder("quote(", function);
+ if (remainder != null) {
+ return codeSimpleUnary("quote", remainder, function, index,
"null");
+ }
+
+ remainder = ifStartsWithReturnRemainder("safeQuote(", function);
+ if (remainder != null) {
+ return codeSimpleUnary("safeQuote", remainder, function, index,
"body");
+ }
+
+ remainder = ifStartsWithReturnRemainder("unquote(", 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: ${unquote(exp)} was: " + function,
index);
+ }
+ String s = tokens[0];
+ if (StringHelper.isSingleQuoted(s)) {
+ s = StringHelper.removeLeadingAndEndingQuotes(s);
+ s = s.replace("\"", "\\\"");
+ s = StringQuoteHelper.doubleQuote(s);
+ }
+ exp = s;
+ }
+ if (ObjectHelper.isEmpty(exp)) {
+ exp = "null";
+ }
+ return "Object o = " + exp + ";\n return unquote(exchange,
o);";
+ }
+
+ remainder = ifStartsWithReturnRemainder("uppercase(", function);
+ if (remainder != null) {
+ return codeSimpleUnary("uppercase", remainder, function, index,
"null");
+ }
+
+ remainder = ifStartsWithReturnRemainder("lowercase(", function);
+ if (remainder != null) {
+ return codeSimpleUnary("lowercase", remainder, function, index,
"null");
+ }
+
+ remainder = ifStartsWithReturnRemainder("length(", function);
+ if (remainder != null) {
+ return codeSimpleUnary("length", remainder, function, index,
"body");
+ }
+
+ remainder = ifStartsWithReturnRemainder("size(", function);
+ if (remainder != null) {
+ return codeSimpleUnary("size", remainder, function, index, "body");
+ }
+
+ remainder = ifStartsWithReturnRemainder("normalizeWhitespace(",
function);
+ if (remainder != null) {
+ return codeSimpleUnary("normalizeWhitespace", remainder, function,
index, "null");
+ }
+
+ return null;
+ }
+
+ private static String codeSimpleUnary(String name, String remainder,
String function, int index, String defaultExp) {
+ 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 = defaultExp;
+ }
+ return "Object o = " + exp + ";\n return " + name + "(exchange,
o);";
+ }
+
+ private static String squoteToDouble(String s) {
+ if (StringHelper.isSingleQuoted(s)) {
+ s = StringHelper.removeLeadingAndEndingQuotes(s);
+ s = StringQuoteHelper.doubleQuote(s);
+ }
+ return s;
+ }
+}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/MathFunctionFactoryTest.java
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/MathFunctionFactoryTest.java
new file mode 100644
index 000000000000..b5a868368724
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/MathFunctionFactoryTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.spi.SimpleLanguageFunctionFactory;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class MathFunctionFactoryTest extends
AbstractSimpleFunctionFactoryTestSupport {
+
+ @Override
+ protected SimpleLanguageFunctionFactory createFactory() {
+ return new MathFunctionFactory();
+ }
+
+ @Test
+ public void testAbs() {
+ exchange.getIn().setBody(-5);
+ assertEquals(5, evaluate("abs(${body})", Integer.class));
+ }
+
+ @Test
+ public void testAbsLiteral() {
+ assertEquals(7.0, evaluate("abs(-7)", Double.class));
+ }
+
+ @Test
+ public void testFloor() {
+ exchange.getIn().setBody(3.7);
+ assertEquals(3L, evaluate("floor(${body})", Long.class));
+ }
+
+ @Test
+ public void testCeil() {
+ exchange.getIn().setBody(3.2);
+ assertEquals(4L, evaluate("ceil(${body})", Long.class));
+ }
+
+ @Test
+ public void testSum() {
+ assertEquals(6.0, evaluate("sum(1, 2, 3)", Double.class));
+ }
+
+ @Test
+ public void testSumWithBody() {
+ exchange.getIn().setBody(10);
+ assertEquals(16.0, evaluate("sum(${body}, 3, 3)", Double.class));
+ }
+
+ @Test
+ public void testMax() {
+ assertEquals(3.0, evaluate("max(1, 2, 3)", Double.class));
+ }
+
+ @Test
+ public void testMin() {
+ assertEquals(1.0, evaluate("min(1, 2, 3)", Double.class));
+ }
+
+ @Test
+ public void testAverage() {
+ assertEquals(2.0, evaluate("average(1, 2, 3)", Double.class));
+ }
+
+ @Test
+ public void testCreateCodeAbs() {
+ assertEquals("Object o = null;\n return abs(exchange, o);",
createCode("abs()"));
+ assertEquals("Object o = 5;\n return abs(exchange, o);",
createCode("abs(5)"));
+ }
+
+ @Test
+ public void testCreateCodeFloor() {
+ assertEquals("Object o = null;\n return floor(exchange, o);",
createCode("floor()"));
+ assertEquals("Object o = 3.7;\n return floor(exchange, o);",
createCode("floor(3.7)"));
+ }
+
+ @Test
+ public void testCreateCodeCeil() {
+ assertEquals("Object o = null;\n return ceil(exchange, o);",
createCode("ceil()"));
+ }
+
+ @Test
+ public void testCreateCodeSum() {
+ assertEquals("sum(exchange, 1, 2, 3)", createCode("sum(1, 2, 3)"));
+ }
+
+ @Test
+ public void testCreateCodeMax() {
+ assertEquals("max(exchange, 1, 2)", createCode("max(1, 2)"));
+ }
+
+ @Test
+ public void testCreateCodeMin() {
+ assertEquals("min(exchange, 1, 2)", createCode("min(1, 2)"));
+ }
+
+ @Test
+ public void testCreateCodeAverage() {
+ assertEquals("average(exchange, 1, 2, 3)", createCode("average(1, 2,
3)"));
+ }
+
+ @Test
+ public void testUnknownFunctionReturnsNull() {
+ assertNull(createFactory().createFunction(context, "trim()", 0));
+ assertNull(createFactory().createCode(context, "trim()", 0));
+ }
+}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/StringFunctionFactoryTest.java
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/StringFunctionFactoryTest.java
new file mode 100644
index 000000000000..f9d76206bccc
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/StringFunctionFactoryTest.java
@@ -0,0 +1,319 @@
+/*
+ * 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 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.assertNull;
+
+public class StringFunctionFactoryTest extends
AbstractSimpleFunctionFactoryTestSupport {
+
+ @Override
+ protected SimpleLanguageFunctionFactory createFactory() {
+ return new StringFunctionFactory();
+ }
+
+ // --- replace ---
+
+ @Test
+ public void testReplace() {
+ exchange.getIn().setBody("Hello World");
+ assertEquals("Hello Camel", evaluate("replace(World,Camel)",
String.class));
+ }
+
+ @Test
+ public void testReplaceWithExpression() {
+ exchange.getIn().setHeader("msg", "foo bar");
+ assertEquals("foo-bar", evaluate("replace( ,-,${header.msg})",
String.class));
+ }
+
+ @Test
+ public void testCreateCodeReplace() {
+ assertEquals("replace(exchange, \"a\", \"b\")",
createCode("replace(a,b)"));
+ }
+
+ @Test
+ public void testCreateCodeReplaceEmpty() {
+ assertEquals("replace(exchange, \"a\", \"\")",
createCode("replace(a,∅)"));
+ }
+
+ // --- substring ---
+
+ @Test
+ public void testSubstringRange1() {
+ exchange.getIn().setBody("Hello World");
+ assertEquals("World", evaluate("substring(6)", String.class));
+ }
+
+ @Test
+ public void testSubstringRange2() {
+ exchange.getIn().setBody("Hello World");
+ assertEquals("Hello", evaluate("substring(0,6)", String.class));
+ }
+
+ @Test
+ public void testSubstringRange3() {
+ exchange.getIn().setBody("Hello World");
+ assertEquals("", evaluate("substring(6,5)", String.class));
+ }
+
+ @Test
+ public void testSubstringRange4() {
+ assertEquals("World", evaluate("substring(6,0,'Hello World')",
String.class));
+ }
+
+ @Test
+ public void testCreateCodeSubstring() {
+ assertEquals("substring(exchange, 2, 0)", createCode("substring(2)"));
+ assertEquals("substring(exchange, 1, 5)", createCode("substring(1,
5)"));
+ }
+
+ // --- substringBefore / substringAfter / substringBetween ---
+
+ @Test
+ public void testSubstringBefore() {
+ exchange.getIn().setBody("Hello World");
+ assertEquals("Hello ", evaluate("substringBefore(World)",
String.class));
+ }
+
+ @Test
+ public void testSubstringAfter() {
+ exchange.getIn().setBody("Hello World");
+ assertEquals(" World", evaluate("substringAfter(Hello)",
String.class));
+ }
+
+ @Test
+ public void testSubstringBetween() {
+ exchange.getIn().setBody("[Hello World]");
+ assertEquals("Hello World", evaluate("substringBetween([,])",
String.class));
+ }
+
+ @Test
+ public void testCreateCodeSubstringBefore() {
+ assertEquals(
+ "Object value = body;\n Object before = \" \";\n
return substringBefore(exchange, value, before);",
+ createCode("substringBefore(' ')"));
+ }
+
+ @Test
+ public void testCreateCodeSubstringAfterWithExp() {
+ assertEquals(
+ "Object value = body;\n Object after = \" \";\n
return substringAfter(exchange, value, after);",
+ createCode("substringAfter(' ')"));
+ }
+
+ // --- contains ---
+
+ @Test
+ public void testContains() {
+ exchange.getIn().setBody("Hello World");
+ assertEquals(true, evaluate("contains(World)", Boolean.class));
+ assertEquals(false, evaluate("contains(Camel)", Boolean.class));
+ }
+
+ @Test
+ public void testContainsWithExpression() {
+ exchange.getIn().setHeader("greeting", "Hello World");
+ assertEquals(true, evaluate("contains(${header.greeting}, World)",
Boolean.class));
+ }
+
+ @Test
+ public void testCreateCodeContains() {
+ assertEquals(
+ "Object value = body;\n return
containsIgnoreCase(exchange, value, \"World\");",
+ createCode("contains(World)"));
+ }
+
+ // --- trim ---
+
+ @Test
+ public void testTrim() {
+ exchange.getIn().setBody(" hello ");
+ assertEquals("hello", evaluate("trim()", String.class));
+ }
+
+ @Test
+ public void testCreateCodeTrim() {
+ assertEquals("Object o = null;\n return trim(exchange, o);",
createCode("trim()"));
+ assertEquals("Object o = body;\n return trim(exchange, o);",
createCode("trim(body)"));
+ }
+
+ // --- val ---
+
+ @Test
+ public void testVal() {
+ exchange.getIn().setBody("hello");
+ assertEquals("hello", evaluate("val(${body})", String.class));
+ }
+
+ @Test
+ public void testCreateCodeVal() {
+ assertEquals("Object o = \"hello\";\n return o;",
createCode("val('hello')"));
+ }
+
+ // --- capitalize ---
+
+ @Test
+ public void testCapitalize() {
+ exchange.getIn().setBody("hello world");
+ assertEquals("Hello World", evaluate("capitalize()", String.class));
+ }
+
+ @Test
+ public void testCreateCodeCapitalize() {
+ assertEquals("Object o = null;\n return capitalize(exchange,
o);", createCode("capitalize()"));
+ }
+
+ // --- pad ---
+
+ @Test
+ public void testPad() {
+ exchange.getIn().setBody("hi");
+ assertEquals("hi ", evaluate("pad(${body}, 5)", String.class));
+ }
+
+ @Test
+ public void testCreateCodePad() {
+ assertEquals(
+ "Object value = body;\n Object width = 10;\n
String separator = null;\n return pad(exchange, value, width,
separator);",
+ createCode("pad(body, 10)"));
+ }
+
+ // --- concat ---
+
+ @Test
+ public void testConcat() {
+ exchange.getIn().setBody("Hello");
+ assertEquals("Hello World", evaluate("concat(${body}, World, ' ')",
String.class));
+ }
+
+ @Test
+ public void testCreateCodeConcat() {
+ assertEquals(
+ "Object right = \"World\";\n Object left = body;\n
Object separator = null;\n return concat(exchange, left, right,
separator);",
+ createCode("concat('World')"));
+ }
+
+ // --- quote / safeQuote / unquote ---
+
+ @Test
+ public void testQuote() {
+ exchange.getIn().setBody("hello");
+ assertEquals("\"hello\"", evaluate("quote()", String.class));
+ }
+
+ @Test
+ public void testSafeQuote() {
+ exchange.getIn().setBody("hello");
+ assertEquals("\"hello\"", evaluate("safeQuote()", String.class));
+ }
+
+ @Test
+ public void testUnquote() {
+ exchange.getIn().setBody("'hello'");
+ assertEquals("hello", evaluate("unquote()", String.class));
+ }
+
+ @Test
+ public void testCreateCodeQuote() {
+ assertEquals("Object o = null;\n return quote(exchange, o);",
createCode("quote()"));
+ }
+
+ @Test
+ public void testCreateCodeSafeQuote() {
+ assertEquals("Object o = body;\n return safeQuote(exchange,
o);", createCode("safeQuote()"));
+ }
+
+ @Test
+ public void testCreateCodeUnquote() {
+ assertEquals("Object o = null;\n return unquote(exchange, o);",
createCode("unquote()"));
+ }
+
+ // --- uppercase / lowercase ---
+
+ @Test
+ public void testUppercase() {
+ exchange.getIn().setBody("hello");
+ assertEquals("HELLO", evaluate("uppercase()", String.class));
+ }
+
+ @Test
+ public void testLowercase() {
+ exchange.getIn().setBody("HELLO");
+ assertEquals("hello", evaluate("lowercase()", String.class));
+ }
+
+ @Test
+ public void testCreateCodeUppercase() {
+ assertEquals("Object o = null;\n return uppercase(exchange,
o);", createCode("uppercase()"));
+ }
+
+ @Test
+ public void testCreateCodeLowercase() {
+ assertEquals("Object o = null;\n return lowercase(exchange,
o);", createCode("lowercase()"));
+ }
+
+ // --- length / size ---
+
+ @Test
+ public void testLength() {
+ exchange.getIn().setBody("Hello");
+ assertEquals(5, evaluate("length()", Integer.class));
+ }
+
+ @Test
+ public void testSize() {
+ exchange.getIn().setBody(List.of("a", "b", "c"));
+ assertEquals(3, evaluate("size()", Integer.class));
+ }
+
+ @Test
+ public void testCreateCodeLength() {
+ assertEquals("Object o = body;\n return length(exchange, o);",
createCode("length()"));
+ }
+
+ @Test
+ public void testCreateCodeSize() {
+ assertEquals("Object o = body;\n return size(exchange, o);",
createCode("size()"));
+ }
+
+ // --- normalizeWhitespace ---
+
+ @Test
+ public void testNormalizeWhitespace() {
+ exchange.getIn().setBody(" hello world ");
+ assertEquals("hello world", evaluate("normalizeWhitespace()",
String.class));
+ }
+
+ @Test
+ public void testCreateCodeNormalizeWhitespace() {
+ assertEquals("Object o = null;\n return
normalizeWhitespace(exchange, o);",
+ createCode("normalizeWhitespace()"));
+ }
+
+ // --- unknown function ---
+
+ @Test
+ public void testUnknownFunctionReturnsNull() {
+ assertNull(createFactory().createFunction(context, "abs()", 0));
+ assertNull(createFactory().createCode(context, "abs()", 0));
+ }
+}