This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push:
new 5595d43 CAMEL-13430: Simple language. Operator functions should use
syntax without spaces in the function names. Added a few more operators and to
use ! as not syntax.
5595d43 is described below
commit 5595d434dd35759796d512ea35df5df257b6d029
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Apr 29 08:01:52 2019 +0200
CAMEL-13430: Simple language. Operator functions should use syntax without
spaces in the function names. Added a few more operators and to use ! as not
syntax.
---
core/camel-core/src/main/docs/simple-language.adoc | 188 +++++++++------------
.../camel/language/simple/SimpleTokenizer.java | 11 +-
.../language/simple/ast/BinaryExpression.java | 4 +
.../language/simple/types/BinaryOperatorType.java | 46 +++--
.../camel/language/simple/SimpleOperatorTest.java | 91 +++++++++-
.../resources/META-INF/spring/camel-context.xml | 2 +-
6 files changed, 214 insertions(+), 128 deletions(-)
diff --git a/core/camel-core/src/main/docs/simple-language.adoc
b/core/camel-core/src/main/docs/simple-language.adoc
index b505ea4..38e81e5 100644
--- a/core/camel-core/src/main/docs/simple-language.adoc
+++ b/core/camel-core/src/main/docs/simple-language.adoc
@@ -50,16 +50,16 @@ The Simple language supports 2 options, which are listed
below.
|=======================================================================
|Variable |Type |Description
-|camelId |String |*Camel 2.10:* the CamelContext name
+|camelId |String |the CamelContext name
-|camelContext.*OGNL* |Object |*Camel 2.11:* the CamelContext invoked using a
Camel OGNL expression.
+|camelContext.*OGNL* |Object |the CamelContext invoked using a Camel OGNL
expression.
-|exchange |Exchange |*Camel 2.16:* the Exchange
+|exchange |Exchange |the Exchange
-|exchange.*OGNL* |Object |*Camel 2.16:* the Exchange invoked using a Camel
+|exchange.*OGNL* |Object |the Exchange invoked using a Camel
OGNL expression.
-|exchangeId |String |*Camel 2.3:* the exchange id
+|exchangeId |String |the exchange id
|id |String |the input message id
@@ -67,101 +67,101 @@ OGNL expression.
|in.body |Object |the input body
-|body.*OGNL* |Object |*Camel 2.3:* the input body invoked using a Camel OGNL
expression.
+|body.*OGNL* |Object |the input body invoked using a Camel OGNL expression.
-|in.body.*OGNL* |Object |*Camel 2.3:* the input body invoked using a Camel
OGNL expression.
+|in.body.*OGNL* |Object |the input body invoked using a Camel OGNL expression.
-|bodyAs(_type_) |Type |*Camel 2.3:* Converts the body to the given type
determined by its
+|bodyAs(_type_) |Type |Converts the body to the given type determined by its
classname. The converted body can be null.
-|bodyAs(_type_).*OGNL* |Object |*Camel 2.18:* Converts the body to the given
type determined by its
+|bodyAs(_type_).*OGNL* |Object |Converts the body to the given type determined
by its
classname and then invoke methods using a Camel OGNL expression. The
converted body can be null.
-|mandatoryBodyAs(_type_) |Type |*Camel 2.5:* Converts the body to the given
type determined by its
+|mandatoryBodyAs(_type_) |Type |Converts the body to the given type determined
by its
classname, and expects the body to be not null.
-|mandatoryBodyAs(_type_).*OGNL* |Object |*Camel 2.18:* Converts the body to
the given type determined by its
+|mandatoryBodyAs(_type_).*OGNL* |Object |Converts the body to the given type
determined by its
classname and then invoke methods using a Camel OGNL expression.
|out.body |Object |the output body
|header.foo |Object |refer to the input foo header
-|header[foo] |Object |*Camel 2.9.2:* refer to the input foo header
+|header[foo] |Object |refer to the input foo header
|headers.foo |Object |refer to the input foo header
-|headers[foo] |Object |*Camel 2.9.2:* refer to the input foo header
+|headers[foo] |Object |refer to the input foo header
|in.header.foo |Object |refer to the input foo header
-|in.header[foo] |Object |*Camel 2.9.2:* refer to the input foo header
+|in.header[foo] |Object |refer to the input foo header
|in.headers.foo |Object |refer to the input foo header
-|in.headers[foo] |Object |*Camel 2.9.2:* refer to the input foo header
+|in.headers[foo] |Object |refer to the input foo header
-|header.foo[bar] |Object |*Camel 2.3:* regard input foo header as a map and
perform lookup on the
+|header.foo[bar] |Object |regard input foo header as a map and perform lookup
on the
map with bar as key
-|in.header.foo[bar] |Object |*Camel 2.3:* regard input foo header as a map and
perform lookup on the
+|in.header.foo[bar] |Object |regard input foo header as a map and perform
lookup on the
map with bar as key
-|in.headers.foo[bar] |Object |*Camel 2.3:* regard input foo header as a map
and perform lookup on the
+|in.headers.foo[bar] |Object |regard input foo header as a map and perform
lookup on the
map with bar as key
-|header.foo.*OGNL* |Object |*Camel 2.3:* refer to the input foo header and
invoke its value using a
+|header.foo.*OGNL* |Object |refer to the input foo header and invoke its value
using a
Camel OGNL expression.
-|in.header.foo.*OGNL* |Object |*Camel 2.3:* refer to the input foo header and
invoke its value using a
+|in.header.foo.*OGNL* |Object |refer to the input foo header and invoke its
value using a
Camel OGNL expression.
-|in.headers.foo.*OGNL* |Object |*Camel 2.3:* refer to the input foo header and
invoke its value using a
+|in.headers.foo.*OGNL* |Object |refer to the input foo header and invoke its
value using a
Camel OGNL expression.
|out.header.foo |Object |refer to the out header foo
-|out.header[foo] |Object |*Camel 2.9.2:* refer to the out header foo
+|out.header[foo] |Object |refer to the out header foo
|out.headers.foo |Object |refer to the out header foo
-|out.headers[foo] |Object |*Camel 2.9.2:* refer to the out header foo
+|out.headers[foo] |Object |refer to the out header foo
-|headerAs(_key_,_type_) |Type |*Camel 2.5:* Converts the header to the given
type determined by its
+|headerAs(_key_,_type_) |Type |converts the header to the given type
determined by its
classname
-|headers |Map |*Camel 2.9:* refer to the input headers
+|headers |Map |refer to the input headers
-|in.headers |Map |*Camel 2.9:* refer to the input headers
+|in.headers |Map |refer to the input headers
-|exchangeProperty.foo |Object |*Camel 2.15:* refer to the foo property on the
exchange
+|exchangeProperty.foo |Object |refer to the foo property on the exchange
-|exchangeProperty[foo] |Object |*Camel 2.15:* refer to the foo property on the
exchange
+|exchangeProperty[foo] |Object |refer to the foo property on the exchange
-|exchangeProperty.foo.*OGNL* |Object |*Camel 2.15:* refer to the foo property
on the exchange and invoke its
+|exchangeProperty.foo.*OGNL* |Object |refer to the foo property on the
exchange and invoke its
value using a Camel OGNL expression.
|sys.foo |String |refer to the system property
-|sysenv.foo |String |*Camel 2.3:* refer to the system environment
+|sysenv.foo |String |refer to the system environment
-|exception |Object |*Camel 2.4:* Refer to the exception object on the
exchange, is *null* if
+|exception |Object |refer to the exception object on the exchange, is *null* if
no exception set on exchange. Will fallback and grab caught exceptions
(`Exchange.EXCEPTION_CAUGHT`) if the Exchange has any.
-|exception.*OGNL* |Object |*Camel 2.4:* Refer to the exchange exception
invoked using a Camel OGNL
+|exception.*OGNL* |Object |refer to the exchange exception invoked using a
Camel OGNL
expression object
-|exception.message |String |Refer to the exception.message on the exchange, is
*null* if no
+|exception.message |String |refer to the exception.message on the exchange, is
*null* if no
exception set on exchange. Will fallback and grab caught exceptions
(`Exchange.EXCEPTION_CAUGHT`) if the Exchange has any.
-|exception.stacktrace |String |*Camel 2.6.* Refer to the exception.stracktrace
on the exchange, is
+|exception.stacktrace |String |refer to the exception.stracktrace on the
exchange, is
*null* if no exception set on exchange. Will fallback and grab caught
exceptions (`Exchange.EXCEPTION_CAUGHT`) if the Exchange has any.
-|date:_command_ |Date |Evaluates to a Date object.
+|date:_command_ |Date |evaluates to a Date object.
Supported commands are: *now* for current timestamp, *in.header.xxx* or
*header.xxx* to use the Date object in the IN header with the key xxx.
*out.header.xxx* to use the Date object in the OUT header with the key xxx.
@@ -178,61 +178,59 @@ Specifying a method name you must use dot as separator.
We also support
the ?method=methodname syntax that is used by the <<bean-component,Bean>>
component.
-|properties-location:_http://locationskey[locations:key]_ |String |*Camel
2.14.1:* Lookup a property with the given key. The `locations`
+|properties-location:_http://locationskey[locations:key]_ |String |Lookup a
property with the given key. The `locations`
option is optional. See more at
Using PropertyPlaceholder.
-|`properties:key:default` |String |*Camel 2.14.1*: Lookup a property with the
given key. If the key does
+|`properties:key:default` |String |Lookup a property with the given key. If
the key does
not exists or has no value, then an optional default value can be
specified.
-|routeId |String |*Camel 2.11:* Returns the id of the current route the
+|routeId |String |Returns the id of the current route the
Exchange is being routed.
-|stepId |String |*Camel 3:* Returns the id of the current step the
+|stepId |String |Returns the id of the current step the
Exchange is being routed.
-|threadName |String |*Camel 2.3:* Returns the name of the current thread. Can
be used for
+|threadName |String |Returns the name of the current thread. Can be used for
logging purpose.
-|ref:xxx |Object |*Camel 2.6:* To lookup a bean from the Registry with
+|ref:xxx |Object |To lookup a bean from the Registry with
the given id.
-|type:name.field |Object |*Camel 2.11:* To refer to a type or field by its FQN
name. To refer to a
+|type:name.field |Object |To refer to a type or field by its FQN name. To
refer to a
field you can append .FIELD_NAME. For example you can refer to the
constant field from Exchange as: `org.apache.camel.Exchange.FILE_NAME`
-|null |null |*Camel 2.12.3:* represents a *null*
+|null |null |represents a *null*
-|random_(value)_ |Integer |*Camel 2.16.0:*returns a random Integer between 0
(included) and _value_
+|random_(value)_ |Integer |returns a random Integer between 0 (included) and
_value_
(excluded)
-|random_(min,max)_ |Integer |*Camel 2.16.0:*returns a random Integer between
_min_ (included) and
+|random_(min,max)_ |Integer |returns a random Integer between _min_ (included)
and
_max_ (excluded)
-|collate(group) |List |*Camel 2.17:* The collate function iterates the message
body and groups
+|collate(group) |List |The collate function iterates the message body and
groups
the data into sub lists of specified size. This can be used with the
Splitter EIP to split a message body and group/batch
the splitted sub message into a group of N sub lists. This method works
similar to the collate method in Groovy.
-|skip(number) |Iterator |*Camel 2.19:* The skip function iterates the message
body and skips
+|skip(number) |Iterator |The skip function iterates the message body and skips
the first number of items. This can be used with the
Splitter EIP to split a message body and skip the first N number of items.
-|messageHistory |String |*Camel 2.17:* The message history of the current
exchange how it has
+|messageHistory |String |The message history of the current exchange how it has
been routed. This is similar to the route stack-trace message history
the error handler logs in case of an unhandled exception.
-|messageHistory(false) |String |*Camel 2.17:* As messageHistory but without
the exchange details (only
+|messageHistory(false) |String |As messageHistory but without the exchange
details (only
includes the route strack-trace). This can be used if you do not want to
log sensitive data from the message itself.
|=======================================================================
=== OGNL expression support
-*Available as of Camel 2.3*
-
INFO:Camel's OGNL support is for invoking methods only. You cannot access
fields. From *Camel 2.11.1* onwards we added special support for accessing the
length field of Java arrays.
@@ -392,8 +390,7 @@ The following operators are supported:
|== |equals
-|=~ |*Camel 2.16:* equals ignore case (will ignore case when comparing String
-values)
+|=~ |equals ignore case (will ignore case when comparing String values)
|> |greater than
@@ -403,44 +400,46 @@ values)
|<= |less than or equals
-|!= |not equals
+|!=~ |not equals
+
+|!=~ |not equals ignore case (will ignore case when comparing String values)
|contains |For testing if contains in a string based value
-|not contains |For testing if not contains in a string based value
+|!contains |For testing if not contains in a string based value
|~~ |For testing if contains by ignoring case sensitivity in a string based
value
+|!~~ |For testing if not contains by ignoring case sensitivity in a string
based value
+
|regex |For matching against a given regular expression pattern defined as a
String value
-|not regex |For not matching against a given regular expression pattern
defined as a
+|!regex |For not matching against a given regular expression pattern defined
as a
String value
|in |For matching if in a set of values, each element must be separated by
comma. If you want to include an empty value, then it must be defined using
double comma, eg ',,bronze,silver,gold', which
is a set of four values with an empty value and then the three medals.
-|not in |For matching if not in a set of values, each element must be separated
+|!in |For matching if not in a set of values, each element must be separated
by comma. If you want to include an empty value, then it must be defined using
double comma, eg ',,bronze,silver,gold', which
is a set of four values with an empty value and then the three medals.
|is |For matching if the left hand side type is an instanceof the value.
-|not is |For matching if the left hand side type is not an instanceof the
value.
+|!is |For matching if the left hand side type is not an instanceof the value.
|range |For matching if the left hand side is within a range of values defined
-as numbers: `from..to`. From *Camel 2.9* onwards the range values must
-be enclosed in single quotes.
+as numbers: `from..to`..
-|not range |For matching if the left hand side is not within a range of values
-defined as numbers: `from..to`. From *Camel 2.9* onwards the range
-values must be enclosed in single quotes.
+|!range |For matching if the left hand side is not within a range of values
+defined as numbers: `from..to`. .
-|starts with |*Camel 2.17.1, 2.18*: For testing if the left hand side string
starts
+|startsWith |For testing if the left hand side string starts
with the right hand string.
-|ends with |*Camel 2.17.1, 2.18*: For testing if the left hand side string
ends with
+|endsWith |For testing if the left hand side string ends with
the right hand string.
|===
@@ -450,26 +449,26 @@ And the following unary operators can be used:
|===
|Operator |Description
-|++ |*Camel 2.9:* To increment a number by one. The left hand side must be a
+|++ |To increment a number by one. The left hand side must be a
function, otherwise parsed as literal.
-|-- |*Camel 2.9:* To decrement a number by one. The left hand side must be a
+|-- |To decrement a number by one. The left hand side must be a
function, otherwise parsed as literal.
-|\ |*Camel 2.9.3 to 2.10.x* To escape a value, eg \$, to indicate a $ sign.
+|\ |To escape a value, eg \$, to indicate a $ sign.
Special: Use \n for new line, \t for tab, and \r for carriage return.
*Notice:* Escaping is *not* supported using the
<<file-language,File Language>>. *Notice:* From Camel 2.11
onwards the escape character is no longer support, but replaced with the
following three special escaping.
-|\n |*Camel 2.11:* To use newline character.
+|\n |To use newline character.
-|\t |*Camel 2.11:* To use tab character.
+|\t |To use tab character.
-|\r |*Camel 2.11:* To use carriage return character.
+|\r |To use carriage return character.
-|\} |*Camel 2.18:* To use the } character as text
+|\} |To use the } character as text
|===
And the following logical operators can be used to group expressions:
@@ -478,27 +477,23 @@ And the following logical operators can be used to group
expressions:
|===
|Operator |Description
-|&& |*Camel 2.9:* The logical and operator is used to group two expressions.
+|&& |The logical and operator is used to group two expressions.
-| \|\| |*Camel 2.9:* The logical or operator is used to group two expressions.
+| \|\| |The logical or operator is used to group two expressions.
|===
-IMPORTANT: *Using and,or operators* In *Camel 2.4 or older* the `and` or `or`
can only be used *once* in a
-simple language expression. From *Camel 2.5* onwards you can use these
-operators multiple times.
-
The syntax for AND is:
[source]
----------------------------------------------------------
-${leftValue} OP rightValue and ${leftValue} OP rightValue
+${leftValue} OP rightValue && ${leftValue} OP rightValue
----------------------------------------------------------
And the syntax for OR is:
[source]
---------------------------------------------------------
-${leftValue} OP rightValue or ${leftValue} OP rightValue
+${leftValue} OP rightValue || ${leftValue} OP rightValue
---------------------------------------------------------
Some examples:
@@ -590,7 +585,7 @@ And for all the last 3 we also support the negate test
using not:
[source,java]
----
-simple("${in.header.type} not in 'gold,silver'")
+simple("${in.header.type} !in 'gold,silver'")
----
And you can test if the type is a certain instance, eg for instance a
@@ -648,32 +643,30 @@ order:
=== Using and / or
-If you have two expressions you can combine them with the `and` or `or`
+If you have two expressions you can combine them with the `&&` or `||`
operator.
-TIP: *Camel 2.9 onwards* Use && or || from Camel 2.9 onwards.
-
For instance:
[source,java]
-----
-simple("${in.header.title} contains 'Camel' and ${in.header.type'} == 'gold'")
+simple("${in.header.title} contains 'Camel' && ${in.header.type'} == 'gold'")
-----
-And of course the `or` is also supported. The sample would be:
+And of course the `||` is also supported. The sample would be:
[source,java]
-----
-simple("${in.header.title} contains 'Camel' or ${in.header.type'} == 'gold'")
+simple("${in.header.title} contains 'Camel' || ${in.header.type'} == 'gold'")
-----
-*Notice:* Currently `and` or `or` can only be used *once* in a simple
+*Notice:* Currently `&&` or `||` can only be used *once* in a simple
language expression. This might change in the future. +
So you *cannot* do:
[source,java]
-----
-simple("${in.header.title} contains 'Camel' and ${in.header.type'} == 'gold'
and ${in.header.number} range 100..200")
+simple("${in.header.title} contains 'Camel' && ${in.header.type'} == 'gold' &&
${in.header.number} range 100..200")
-----
@@ -804,8 +797,6 @@ From Camel 2.9 onwards you can nest functions, such as
shown below:
=== Referring to constants or enums
-*Available as of Camel 2.11*
-
Suppose you have an enum for customers
And in a Content Based Router we can use
@@ -814,8 +805,6 @@ the message which enum it matches.
=== Using new lines or tabs in XML DSLs
-*Available as of Camel 2.9.3*
-
From Camel 2.9.3 onwards it is easier to specify new lines or tabs in
XML DSLs as you can escape the value now
@@ -828,9 +817,7 @@ XML DSLs as you can escape the value now
=== Leading and trailing whitespace handling
-*Available as of Camel 2.10.0*
-
-From Camel 2.10.0 onwards, the trim attribute of the expression can be
+The trim attribute of the expression can be
used to control whether the leading and trailing whitespace characters
are removed or preserved. The default value is true, which removes the
whitespace characters.
@@ -844,8 +831,6 @@ whitespace characters.
=== Setting result type
-*Available as of Camel 2.8*
-
You can now provide a result type to the <<simple-language,Simple>>
expression, which means the result of the evaluation will be converted
to the desired type. This is most useable to define types such as
@@ -870,8 +855,6 @@ And in XML DSL
=== Loading script from external resource
-*Available as of Camel 2.11*
-
You can externalize the script and have Camel load it from a resource
such as `"classpath:"`, `"file:"`, or `"http:"`. +
This is done using the following syntax: `"resource:scheme:location"`,
@@ -884,8 +867,6 @@ eg to refer to a file on the classpath you can do:
=== Setting Spring beans to Exchange properties
-*Available as of Camel 2.6*
-
You can set a spring bean into an exchange property as shown below:
[source,xml]
@@ -901,6 +882,3 @@ You can set a spring bean into an exchange property as
shown below:
</route>
----
-=== Dependencies
-
-The <<simple-language,Simple>> language is part of *camel-core*.
diff --git
a/core/camel-core/src/main/java/org/apache/camel/language/simple/SimpleTokenizer.java
b/core/camel-core/src/main/java/org/apache/camel/language/simple/SimpleTokenizer.java
index 600a191..ef7ffd7 100644
---
a/core/camel-core/src/main/java/org/apache/camel/language/simple/SimpleTokenizer.java
+++
b/core/camel-core/src/main/java/org/apache/camel/language/simple/SimpleTokenizer.java
@@ -58,19 +58,28 @@ public final class SimpleTokenizer {
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "<="));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, ">"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "<"));
+ KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "!=~"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "!="));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "not
is"));
+ KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "!is"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "is"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "not
contains"));
+ KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator,
"!contains"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator,
"contains"));
+ KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "!~~"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "~~"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "not
regex"));
+ KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator,
"!regex"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator,
"regex"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "not
in"));
+ KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "!in"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "in"));
- KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator,
"range"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "not
range"));
+ KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator,
"!range"));
+ KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator,
"range"));
+ KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator,
"startsWith"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "starts
with"));
+ KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator,
"endsWith"));
KNOWN_TOKENS.add(new SimpleTokenType(TokenType.binaryOperator, "ends
with"));
// unary operators
diff --git
a/core/camel-core/src/main/java/org/apache/camel/language/simple/ast/BinaryExpression.java
b/core/camel-core/src/main/java/org/apache/camel/language/simple/ast/BinaryExpression.java
index 0422679..87753c7 100644
---
a/core/camel-core/src/main/java/org/apache/camel/language/simple/ast/BinaryExpression.java
+++
b/core/camel-core/src/main/java/org/apache/camel/language/simple/ast/BinaryExpression.java
@@ -92,12 +92,16 @@ public class BinaryExpression extends BaseSimpleNode {
return createExpression(leftExp, rightExp,
PredicateBuilder.isLessThanOrEqualTo(leftExp, rightExp));
} else if (operator == BinaryOperatorType.NOT_EQ) {
return createExpression(leftExp, rightExp,
PredicateBuilder.isNotEqualTo(leftExp, rightExp));
+ } else if (operator == BinaryOperatorType.NOT_EQ_IGNORE) {
+ return createExpression(leftExp, rightExp,
PredicateBuilder.not(PredicateBuilder.isEqualToIgnoreCase(leftExp, rightExp)));
} else if (operator == BinaryOperatorType.CONTAINS) {
return createExpression(leftExp, rightExp,
PredicateBuilder.contains(leftExp, rightExp));
} else if (operator == BinaryOperatorType.NOT_CONTAINS) {
return createExpression(leftExp, rightExp,
PredicateBuilder.not(PredicateBuilder.contains(leftExp, rightExp)));
} else if (operator == BinaryOperatorType.CONTAINS_IGNORECASE) {
return createExpression(leftExp, rightExp,
PredicateBuilder.containsIgnoreCase(leftExp, rightExp));
+ } else if (operator == BinaryOperatorType.NOT_CONTAINS_IGNORECASE) {
+ return createExpression(leftExp, rightExp,
PredicateBuilder.not(PredicateBuilder.containsIgnoreCase(leftExp, rightExp)));
} else if (operator == BinaryOperatorType.IS || operator ==
BinaryOperatorType.NOT_IS) {
return createIsExpression(expression, leftExp, rightExp);
} else if (operator == BinaryOperatorType.REGEX || operator ==
BinaryOperatorType.NOT_REGEX) {
diff --git
a/core/camel-core/src/main/java/org/apache/camel/language/simple/types/BinaryOperatorType.java
b/core/camel-core/src/main/java/org/apache/camel/language/simple/types/BinaryOperatorType.java
index a8ebf26..100ee94 100644
---
a/core/camel-core/src/main/java/org/apache/camel/language/simple/types/BinaryOperatorType.java
+++
b/core/camel-core/src/main/java/org/apache/camel/language/simple/types/BinaryOperatorType.java
@@ -21,9 +21,9 @@ package org.apache.camel.language.simple.types;
*/
public enum BinaryOperatorType {
- EQ, EQ_IGNORE, GT, GTE, LT, LTE, NOT_EQ, CONTAINS, NOT_CONTAINS,
- CONTAINS_IGNORECASE, REGEX, NOT_REGEX,
- IN, NOT_IN, IS, NOT_IS, RANGE, NOT_RANGE, STARTS_WITH, ENDS_WITH;
+ EQ, EQ_IGNORE, GT, GTE, LT, LTE, NOT_EQ, NOT_EQ_IGNORE,
+ CONTAINS, NOT_CONTAINS, CONTAINS_IGNORECASE, NOT_CONTAINS_IGNORECASE,
+ REGEX, NOT_REGEX, IN, NOT_IN, IS, NOT_IS, RANGE, NOT_RANGE, STARTS_WITH,
ENDS_WITH;
public static BinaryOperatorType asOperator(String text) {
if ("==".equals(text)) {
@@ -40,31 +40,35 @@ public enum BinaryOperatorType {
return LTE;
} else if ("!=".equals(text)) {
return NOT_EQ;
+ } else if ("!=~".equals(text)) {
+ return NOT_EQ_IGNORE;
} else if ("contains".equals(text)) {
return CONTAINS;
- } else if ("not contains".equals(text)) {
+ } else if ("!contains".equals(text) || "not contains".equals(text)) {
return NOT_CONTAINS;
} else if ("~~".equals(text)) {
return CONTAINS_IGNORECASE;
+ } else if ("!~~".equals(text)) {
+ return NOT_CONTAINS_IGNORECASE;
} else if ("regex".equals(text)) {
return REGEX;
- } else if ("not regex".equals(text)) {
+ } else if ("!regex".equals(text) || "not regex".equals(text)) {
return NOT_REGEX;
} else if ("in".equals(text)) {
return IN;
- } else if ("not in".equals(text)) {
+ } else if ("!in".equals(text) || "not in".equals(text)) {
return NOT_IN;
} else if ("is".equals(text)) {
return IS;
- } else if ("not is".equals(text)) {
+ } else if ("!is".equals(text) || "not is".equals(text)) {
return NOT_IS;
} else if ("range".equals(text)) {
return RANGE;
- } else if ("not range".equals(text)) {
+ } else if ("!range".equals(text) || "not range".equals(text)) {
return NOT_RANGE;
- } else if ("starts with".equals(text)) {
+ } else if ("startsWith".equals(text) || "starts with".equals(text)) {
return STARTS_WITH;
- } else if ("ends with".equals(text)) {
+ } else if ("endsWith".equals(text) || "ends with".equals(text)) {
return ENDS_WITH;
}
throw new IllegalArgumentException("Operator not supported: " + text);
@@ -85,32 +89,36 @@ public enum BinaryOperatorType {
return "<=";
} else if (operator == NOT_EQ) {
return "!=";
+ } else if (operator == NOT_EQ_IGNORE) {
+ return "!=~";
} else if (operator == CONTAINS) {
return "contains";
} else if (operator == NOT_CONTAINS) {
- return "not contains";
+ return "!contains";
} else if (operator == CONTAINS_IGNORECASE) {
return "~~";
+ } else if (operator == NOT_CONTAINS_IGNORECASE) {
+ return "!~~";
} else if (operator == REGEX) {
return "regex";
} else if (operator == NOT_REGEX) {
- return "not regex";
+ return "!regex";
} else if (operator == IN) {
return "in";
} else if (operator == NOT_IN) {
- return "not in";
+ return "!in";
} else if (operator == IS) {
return "is";
} else if (operator == NOT_IS) {
- return "not is";
+ return "!is";
} else if (operator == RANGE) {
return "range";
} else if (operator == NOT_RANGE) {
- return "not range";
+ return "!range";
} else if (operator == STARTS_WITH) {
- return "starts with";
+ return "startsWith";
} else if (operator == ENDS_WITH) {
- return "ends with";
+ return "endsWith";
}
return "";
}
@@ -179,12 +187,16 @@ public enum BinaryOperatorType {
return null;
} else if (operator == NOT_EQ) {
return null;
+ } else if (operator == NOT_EQ_IGNORE) {
+ return null;
} else if (operator == CONTAINS) {
return null;
} else if (operator == NOT_CONTAINS) {
return null;
} else if (operator == CONTAINS_IGNORECASE) {
return null;
+ } else if (operator == NOT_CONTAINS_IGNORECASE) {
+ return null;
} else if (operator == REGEX) {
return new ParameterType[]{ParameterType.Literal,
ParameterType.Function};
} else if (operator == NOT_REGEX) {
diff --git
a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleOperatorTest.java
b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleOperatorTest.java
index bf98d18..5bfb552 100644
---
a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleOperatorTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleOperatorTest.java
@@ -195,6 +195,23 @@ public class SimpleOperatorTest extends
LanguageTestSupport {
}
@Test
+ public void testNotEqualIgnoreOperator() throws Exception {
+ // string to string comparison
+ assertPredicate("${in.header.foo} !=~ 'abc'", false);
+ assertPredicate("${in.header.foo} !=~ 'ABC'", false);
+ assertPredicate("${in.header.foo} !=~ 'Abc'", false);
+ assertPredicate("${in.header.foo} !=~ 'Def'", true);
+ assertPredicate("${in.header.foo} !=~ '1'", true);
+
+ // integer to string comparison
+ assertPredicate("${in.header.bar} !=~ '123'", false);
+ assertPredicate("${in.header.bar} !=~ 123", false);
+ assertPredicate("${in.header.bar} !=~ '444'", true);
+ assertPredicate("${in.header.bar} !=~ 444", true);
+ assertPredicate("${in.header.bar} !=~ '1'", true);
+ }
+
+ @Test
public void testFloatingNumber() throws Exception {
// set a String value
exchange.getIn().setBody("0.02");
@@ -312,9 +329,9 @@ public class SimpleOperatorTest extends LanguageTestSupport
{
exchange.getIn().setHeader("strNum", "123");
assertPredicate("${in.header.strNum} contains '123'", true);
- assertPredicate("${in.header.strNum} not contains '123'", false);
+ assertPredicate("${in.header.strNum} !contains '123'", false);
assertPredicate("${in.header.strNum} contains '-123'", false);
- assertPredicate("${in.header.strNum} not contains '-123'", true);
+ assertPredicate("${in.header.strNum} !contains '-123'", true);
assertPredicate("${in.header.strNum} ~~ '123'", true);
assertPredicate("${in.header.strNum} ~~ '-123'", false);
@@ -334,9 +351,9 @@ public class SimpleOperatorTest extends LanguageTestSupport
{
exchange.getIn().setHeader("strNumNegative", "-123");
assertPredicate("${in.header.strNumNegative} contains '123'", true);
- assertPredicate("${in.header.strNumNegative} not contains '123'",
false);
+ assertPredicate("${in.header.strNumNegative} !contains '123'", false);
assertPredicate("${in.header.strNumNegative} contains '-123'", true);
- assertPredicate("${in.header.strNumNegative} not contains '-123'",
false);
+ assertPredicate("${in.header.strNumNegative} !contains '-123'", false);
assertPredicate("${in.header.strNumNegative} ~~ '123'", true);
assertPredicate("${in.header.strNumNegative} ~~ '-123'", true);
@@ -399,6 +416,10 @@ public class SimpleOperatorTest extends
LanguageTestSupport {
assertPredicate("${in.header.foo} not contains 'ab'", false);
assertPredicate("${in.header.foo} not contains 'abc'", false);
assertPredicate("${in.header.foo} not contains 'def'", true);
+ assertPredicate("${in.header.foo} !contains 'a'", false);
+ assertPredicate("${in.header.foo} !contains 'ab'", false);
+ assertPredicate("${in.header.foo} !contains 'abc'", false);
+ assertPredicate("${in.header.foo} !contains 'def'", true);
}
@Test
@@ -410,6 +431,14 @@ public class SimpleOperatorTest extends
LanguageTestSupport {
}
@Test
+ public void testNotContainsIgnoreCase() throws Exception {
+ assertPredicate("${in.header.foo} !~~ 'A'", false);
+ assertPredicate("${in.header.foo} !~~ 'Ab'", false);
+ assertPredicate("${in.header.foo} !~~ 'Abc'", false);
+ assertPredicate("${in.header.foo} !~~ 'defG'", true);
+ }
+
+ @Test
public void testRegex() throws Exception {
assertPredicate("${in.header.foo} regex '^a..$'", true);
assertPredicate("${in.header.foo} regex '^ab.$'", true);
@@ -452,11 +481,18 @@ public class SimpleOperatorTest extends
LanguageTestSupport {
assertPredicate("${in.header.foo} not in
${bean:generator.generateFilename}", false);
assertPredicate("${in.header.foo} not in 'foo,abc,def'", false);
assertPredicate("${in.header.foo} not in 'foo,def'", true);
+ assertPredicate("${in.header.foo} !in 'foo,abc,def'", false);
+ assertPredicate("${in.header.foo} !in
${bean:generator.generateFilename}", false);
+ assertPredicate("${in.header.foo} !in 'foo,abc,def'", false);
+ assertPredicate("${in.header.foo} !in 'foo,def'", true);
// integer to string
assertPredicate("${in.header.bar} not in '100,123,200'", false);
assertPredicate("${in.header.bar} not in
${bean:generator.generateId}", false);
assertPredicate("${in.header.bar} not in '100,200'", true);
+ assertPredicate("${in.header.bar} !in '100,123,200'", false);
+ assertPredicate("${in.header.bar} !in ${bean:generator.generateId}",
false);
+ assertPredicate("${in.header.bar} !in '100,200'", true);
}
@Test
@@ -479,9 +515,13 @@ public class SimpleOperatorTest extends
LanguageTestSupport {
public void testIsNot() throws Exception {
assertPredicate("${in.header.foo} not is 'java.lang.String'", false);
assertPredicate("${in.header.foo} not is 'java.lang.Integer'", true);
+ assertPredicate("${in.header.foo} !is 'java.lang.String'", false);
+ assertPredicate("${in.header.foo} !is 'java.lang.Integer'", true);
assertPredicate("${in.header.foo} not is 'String'", false);
assertPredicate("${in.header.foo} not is 'Integer'", true);
+ assertPredicate("${in.header.foo} !is 'String'", false);
+ assertPredicate("${in.header.foo} !is 'Integer'", true);
try {
assertPredicate("${in.header.foo} not is
com.mycompany.DoesNotExist", false);
@@ -489,6 +529,12 @@ public class SimpleOperatorTest extends
LanguageTestSupport {
} catch (SimpleIllegalSyntaxException e) {
assertEquals(24, e.getIndex());
}
+ try {
+ assertPredicate("${in.header.foo} !is com.mycompany.DoesNotExist",
false);
+ fail("Should have thrown an exception");
+ } catch (SimpleIllegalSyntaxException e) {
+ assertEquals(21, e.getIndex());
+ }
}
@Test
@@ -533,12 +579,19 @@ public class SimpleOperatorTest extends
LanguageTestSupport {
public void testNotRange() throws Exception {
assertPredicate("${in.header.bar} not range '100..200'", false);
assertPredicate("${in.header.bar} not range '200..300'", true);
+ assertPredicate("${in.header.bar} !range '100..200'", false);
+ assertPredicate("${in.header.bar} !range '200..300'", true);
assertPredicate("${in.header.foo} not range '200..300'", true);
assertPredicate("${bean:generator.generateId} not range '123..130'",
false);
assertPredicate("${bean:generator.generateId} not range '120..123'",
false);
assertPredicate("${bean:generator.generateId} not range '120..122'",
true);
assertPredicate("${bean:generator.generateId} not range '124..130'",
true);
+ assertPredicate("${in.header.foo} !range '200..300'", true);
+ assertPredicate("${bean:generator.generateId} !range '123..130'",
false);
+ assertPredicate("${bean:generator.generateId} !range '120..123'",
false);
+ assertPredicate("${bean:generator.generateId} !range '120..122'",
true);
+ assertPredicate("${bean:generator.generateId} !range '124..130'",
true);
try {
assertPredicate("${in.header.foo} not range abc..200", false);
@@ -546,6 +599,12 @@ public class SimpleOperatorTest extends
LanguageTestSupport {
} catch (SimpleIllegalSyntaxException e) {
assertEquals(27, e.getIndex());
}
+ try {
+ assertPredicate("${in.header.foo} !range abc..200", false);
+ fail("Should have thrown an exception");
+ } catch (SimpleIllegalSyntaxException e) {
+ assertEquals(24, e.getIndex());
+ }
try {
assertPredicate("${in.header.foo} not range abc..", false);
@@ -553,6 +612,12 @@ public class SimpleOperatorTest extends
LanguageTestSupport {
} catch (SimpleIllegalSyntaxException e) {
assertEquals(27, e.getIndex());
}
+ try {
+ assertPredicate("${in.header.foo} !range abc..", false);
+ fail("Should have thrown an exception");
+ } catch (SimpleIllegalSyntaxException e) {
+ assertEquals(24, e.getIndex());
+ }
try {
assertPredicate("${in.header.foo} not range 100.200", false);
@@ -560,6 +625,12 @@ public class SimpleOperatorTest extends
LanguageTestSupport {
} catch (SimpleIllegalSyntaxException e) {
assertEquals(34, e.getIndex());
}
+ try {
+ assertPredicate("${in.header.foo} !range 100.200", false);
+ fail("Should have thrown an exception");
+ } catch (SimpleIllegalSyntaxException e) {
+ assertEquals(31, e.getIndex());
+ }
}
@Test
@@ -599,6 +670,12 @@ public class SimpleOperatorTest extends
LanguageTestSupport {
assertPredicate("${in.body} starts with 'Hello ther'", true);
assertPredicate("${in.body} starts with 'ello there'", false);
assertPredicate("${in.body} starts with 'Hi'", false);
+ assertPredicate("${in.body} startsWith 'Hello'", true);
+ assertPredicate("${in.body} startsWith 'H'", true);
+ assertPredicate("${in.body} startsWith 'Hello there'", true);
+ assertPredicate("${in.body} startsWith 'Hello ther'", true);
+ assertPredicate("${in.body} startsWith 'ello there'", false);
+ assertPredicate("${in.body} startsWith 'Hi'", false);
}
@Test
@@ -610,6 +687,12 @@ public class SimpleOperatorTest extends
LanguageTestSupport {
assertPredicate("${in.body} ends with 'Hello there'", true);
assertPredicate("${in.body} ends with 'Hello ther'", false);
assertPredicate("${in.body} ends with 'Hi'", false);
+ assertPredicate("${in.body} endsWith 'there'", true);
+ assertPredicate("${in.body} endsWith 're'", true);
+ assertPredicate("${in.body} endsWith ' there'", true);
+ assertPredicate("${in.body} endsWith 'Hello there'", true);
+ assertPredicate("${in.body} endsWith 'Hello ther'", false);
+ assertPredicate("${in.body} endsWith 'Hi'", false);
}
protected String getLanguageName() {
diff --git
a/examples/camel-example-transformer-demo/src/main/resources/META-INF/spring/camel-context.xml
b/examples/camel-example-transformer-demo/src/main/resources/META-INF/spring/camel-context.xml
index cf32503..dfd2dc4 100644
---
a/examples/camel-example-transformer-demo/src/main/resources/META-INF/spring/camel-context.xml
+++
b/examples/camel-example-transformer-demo/src/main/resources/META-INF/spring/camel-context.xml
@@ -56,7 +56,7 @@
<camel:validators>
<camel:endpointValidator type="xml"
uri="validator:xsd/schema.xsd"/>
<camel:predicateValidator type="json">
- <camel:simple>${body} contains 'orderId' && ${body}
not contains 'accepted'</camel:simple>
+ <camel:simple>${body} contains 'orderId' && ${body}
!contains 'accepted'</camel:simple>
</camel:predicateValidator>
<camel:customValidator
type="java:org.apache.camel.example.transformer.demo.OrderResponse"
className="org.apache.camel.example.transformer.demo.OrderResponseValidator"/>