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' &amp;&amp; ${body} 
not contains 'accepted'</camel:simple>
+                <camel:simple>${body} contains 'orderId' &amp;&amp; ${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"/>

Reply via email to