Chapter 30. The Simple Language
Abstract
The simple language is a language that was developed in Apache Camel specifically for the purpose of accessing and manipulating the various parts of an exchange object. The language is not quite as simple as when it was originally created and it now features a comprehensive set of logical operators and conjunctions.
30.1. Java DSL
Simple expressions in Java DSL
In the Java DSL, there are two styles for using the simple()
command in a route. You can either pass the simple()
command as an argument to a processor, as follows:
from("seda:order") .filter(simple("${in.header.foo}")) .to("mock:fooOrders");
Or you can call the simple()
command as a sub-clause on the processor, for example:
from("seda:order") .filter() .simple("${in.header.foo}") .to("mock:fooOrders");
Embedding in a string
If you are embedding a simple expression inside a plain text string, you must use the placeholder syntax, ${Expression}
. For example, to embed the in.header.name
expression in a string:
simple("Hello ${in.header.name}, how are you?")
Customizing the start and end tokens
From Java, you can customize the start and end tokens ({
and }
, by default) by calling the changeFunctionStartToken
static method and the changeFunctionEndToken
static method on the SimpleLanguage
object.
For example, you can change the start and end tokens to [
and ]
in Java, as follows:
// Java import org.apache.camel.language.simple.SimpleLanguage; ... SimpleLanguage.changeFunctionStartToken("["); SimpleLanguage.changeFunctionEndToken("]");
Customizing the start and end tokens affects all Apache Camel applications that share the same camel-core
library on their classpath. For example, in an OSGi server this might affect many applications; whereas in a Web application (WAR file) it would affect only the Web application itself.
30.2. XML DSL
Simple expressions in XML DSL
In the XML DSL, you can use a simple expression by putting the expression inside a simple
element. For example, to define a route that performs filtering based on the contents of the foo
header:
<route id="simpleExample"> <from uri="seda:orders"/> <filter> <simple>${in.header.foo}</simple> <to uri="mock:fooOrders"/> </filter> </route>
Alternative placeholder syntax
Sometimes — for example, if you have enabled Spring property placeholders or OSGi blueprint property placeholders — you might find that the ${Expression}
syntax clashes with another property placeholder syntax. In this case, you can disambiguate the placeholder using the alternative syntax, $simple{Expression}
, for the simple expression. For example:
<simple>Hello $simple{in.header.name}, how are you?</simple>
Customizing the start and end tokens
From XML configuration, you can customize the start and end tokens ({
and }
, by default) by overriding the SimpleLanguage
instance. For example, to change the start and end tokens to [
and ]
, define a new SimpleLanguage
bean in your XML configuration file, as follows:
<bean id="simple" class="org.apache.camel.language.simple.SimpleLanguage"> <constructor-arg name="functionStartToken" value="["/> <constructor-arg name="functionEndToken" value="]"/> </bean>
Customizing the start and end tokens affects all Apache Camel applications that share the same camel-core
library on their classpath. For example, in an OSGi server this might affect many applications; whereas in a Web application (WAR file) it would affect only the Web application itself.
Whitespace and auto-trim in XML DSL
By default, whitespace preceding and following a simple expression is automatically trimmed in XML DSL. So this expression with surrounding whitespace:
<transform> <simple> data=${body} </simple> </transform>
is automatically trimmed, so that it is equivalent to this expression (no surrounding whitespace):
<transform> <simple>data=${body}</simple> </transform>
If you want to include newlines before or after the expression, you can either explicitly add a newline character, as follows:
<transform> <simple>data=${body}\n</simple> </transform>
or you can switch off auto-trimming, by setting the trim
attribute to false
, as follows:
<transform trim="false"> <simple>data=${body} </simple> </transform>
30.3. Invoking an External Script
Overview
It is possible to execute Simple scripts that are stored in an external resource, as described here.
Syntax for script resource
Use the following syntax to access a Simple script that is stored as an external resource:
resource:Scheme:Location
Where the Scheme:
can be either classpath:
, file:
, or http:
.
For example, to read the mysimple.txt
script from the classpath,
simple("resource:classpath:mysimple.txt")
30.4. Expressions
Overview
The simple language provides various elementary expressions that return different parts of a message exchange. For example, the expression, simple("${header.timeOfDay}")
, would return the contents of a header called timeOfDay
from the incoming message.
Since Apache Camel 2.9, you must always use the placeholder syntax, ${Expression}
, to return a variable value. It is never permissible to omit the enclosing tokens (${
and }
).
Contents of a single variable
You can use the simple language to define string expressions, based on the variables provided. For example, you can use a variable of the form, in.header.
HeaderName, to obtain the value of the HeaderName header, as follows:
simple("${in.header.foo}")
Variables embedded in a string
You can embed simple variables in a string expression — for example:
simple("Received a message from ${in.header.user} on ${date:in.header.date:yyyyMMdd}.")
date and bean variables
As well as providing variables that access all of the different parts of an exchange (see Table 30.1, “Variables for the Simple Language”), the simple language also provides special variables for formatting dates, date:
command:
pattern, and for calling bean methods, bean:
beanRef. For example, you can use the date and the bean variables as follows:
simple("Todays date is ${date:now:yyyyMMdd}") simple("The order type is ${bean:orderService?method=getOrderType}")
Specifying the result type
You can specify the result type of an expression explicitly. This is mainly useful for converting the result type to a boolean or numerical type.
In the Java DSL, specify the result type as an extra argument to simple()
. For example, to return an integer result, you could evaluate a simple expression as follows:
...
.setHeader("five", simple("5", Integer.class))
In the XML DSL, specify the result type using the resultType
attribute. For example:
<setHeader headerName="five">
<!-- use resultType to indicate that the type should be a java.lang.Integer -->
<simple resultType="java.lang.Integer">5</simple>
</setHeader>
Dynamic Header Key
From Camel 2.17, the setHeader
and setExchange
properties allows to use a dynamic header key using the Simple language, if the name of the key is a Simple language expression.
<camelContext xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="direct:start"/> <setHeader headerName="$simple{type:org.apache.camel.spring.processor.SpringSetPropertyNameDynamicTest$TestConstans.EXCHANGE_PROP_TX_FAILED}"> <simple>${type:java.lang.Boolean.TRUE}</simple> </setHeader> <to uri="mock:end"/> </route> </camelContext>
Nested expressions
Simple expressions can be nested — for example:
simple("${header.${bean:headerChooser?method=whichHeader}}")
Accessing constants or enums
You can access a bean’s constant or enum fields using the following syntax:
type:ClassName.Field
For example, consider the following Java enum
type:
package org.apache.camel.processor; ... public enum Customer { GOLD, SILVER, BRONZE }
You can access the Customer
enum fields, as follows:
from("direct:start") .choice() .when().simple("${header.customer} == ${type:org.apache.camel.processor.Customer.GOLD}") .to("mock:gold") .when().simple("${header.customer} == ${type:org.apache.camel.processor.Customer.SILVER}") .to("mock:silver") .otherwise() .to("mock:other");
OGNL expressions
The Object Graph Navigation Language (OGNL) is a notation for invoking bean methods in a chain-like fashion. If a message body contains a Java bean, you can easily access its bean properties using OGNL notation. For example, if the message body is a Java object with a getAddress()
accessor, you can access the Address
object and the Address
object’s properties as follows:
simple("${body.address}") simple("${body.address.street}") simple("${body.address.zip}") simple("${body.address.city}")
Where the notation, ${body.address.street}
, is shorthand for ${body.getAddress.getStreet}
.
OGNL null-safe operator
You can use the null-safe operator, ?.
, to avoid encountering null-pointer exceptions, in case the body does not have an address. For example:
simple("${body?.address?.street}")
If the body is a java.util.Map
type, you can look up a value in the map with the key, foo
, using the following notation:
simple("${body[foo]?.name}")
OGNL list element access
You can also use square brackets notation, [k]
, to access the elements of a list. For example:
simple("${body.address.lines[0]}") simple("${body.address.lines[1]}") simple("${body.address.lines[2]}")
The last
keyword returns the index of the last element of a list. For example, you can access the second last element of a list, as follows:
simple("${body.address.lines[last-1]}")
You can use the size
method to query the size of a list, as follows:
simple("${body.address.lines.size}")
OGNL array length access
You can access the length of a Java array through the length
method, as follows:
String[] lines = new String[]{"foo", "bar", "cat"}; exchange.getIn().setBody(lines); simple("There are ${body.length} lines")
30.5. Predicates
Overview
You can construct predicates by testing expressions for equality. For example, the predicate, simple("${header.timeOfDay} == '14:30'")
, tests whether the timeOfDay
header in the incoming message is equal to 14:30
.
In addition, whenever the resultType
is specified as a Boolean the expression is evaluated as a predicate instead of an expression. This allows the predicate syntax to be used for these expressions.
Syntax
You can also test various parts of an exchange (headers, message body, and so on) using simple predicates. Simple predicates have the following general syntax:
${LHSVariable} Op RHSValue
Where the variable on the left hand side, LHSVariable, is one of the variables shown in Table 30.1, “Variables for the Simple Language” and the value on the right hand side, RHSValue, is one of the following:
-
Another variable,
${
RHSVariable}
. -
A string literal, enclosed in single quotes,
' '
. -
A numeric constant, enclosed in single quotes,
' '
. -
The null object,
null
.
The simple language always attempts to convert the RHS value to the type of the LHS value.
While the simple language will attempt to convert the RHS, depending on the operator the LHS may need to be cast into the appropriate Type before the comparison is made.
Examples
For example, you can perform simple string comparisons and numerical comparisons as follows:
simple("${in.header.user} == 'john'") simple("${in.header.number} > '100'") // String literal can be converted to integer
You can test whether the left hand side is a member of a comma-separated list, as follows:
simple("${in.header.type} in 'gold,silver'")
You can test whether the left hand side matches a regular expression, as follows:
simple("${in.header.number} regex '\d{4}'")
You can test the type of the left hand side using the is
operator, as follows:
simple("${in.header.type} is 'java.lang.String'") simple("${in.header.type} is 'String'") // You can abbreviate java.lang. types
You can test whether the left hand side lies in a specified numerical range (where the range is inclusive), as follows:
simple("${in.header.number} range '100..199'")
Conjunctions
You can also combine predicates using the logical conjunctions, &&
and ||
.
For example, here is an expression using the &&
conjunction (logical and):
simple("${in.header.title} contains 'Camel' && ${in.header.type} == 'gold'")
And here is an expression using the ||
conjunction (logical inclusive or):
simple("${in.header.title} contains 'Camel' || ${in.header.type} == 'gold'")
30.6. Variable Reference
Table of variables
Table 30.1, “Variables for the Simple Language” shows all of the variables supported by the simple language.
Variable | Type | Description |
---|---|---|
|
| The Camel context. Supports OGNL expressions. |
|
| The Camel context’s ID value. |
|
| The exchange’s ID value. |
|
| The In message ID value. |
|
| The In message body. Supports OGNL expressions. |
|
| The In message body. Supports OGNL expressions. |
|
| The Out message body. |
| Type |
The In message body, converted to the specified type. All types, Type, must be specified using their fully-qualified Java name, except for the types: |
| Type |
The In message body, converted to the specified type. All types, Type, must be specified using their fully-qualified Java name, except for the types: |
|
| The In message’s HeaderName header. Supports OGNL expressions. |
|
| The In message’s HeaderName header (alternative syntax). |
|
| The In message’s HeaderName header. |
|
| The In message’s HeaderName header (alternative syntax). |
|
| The In message’s HeaderName header. Supports OGNL expressions. |
|
| The In message’s HeaderName header (alternative syntax). |
|
| The In message’s HeaderName header. Supports OGNL expressions. |
|
| The In message’s HeaderName header (alternative syntax). |
|
| The Out message’s HeaderName header. |
|
| The Out message’s HeaderName header (alternative syntax). |
|
| The Out message’s HeaderName header. |
|
| The Out message’s HeaderName header (alternative syntax). |
| Type |
The Key header, converted to the specified type. All types, Type, must be specified using their fully-qualified Java name, except for the types: |
|
|
All of the In headers (as a |
|
|
All of the In headers (as a |
|
| The PropertyName property on the exchange. |
|
| The PropertyName property on the exchange (alternative syntax). |
|
| The SysPropertyName Java system property. |
|
| The SysEnvVar system environment variable. |
|
|
Either the exception object from |
|
|
If an exception is set on the exchange, returns the value of |
|
|
If an exception is set on the exchange, returns the value of |
|
|
A date formatted using a java.text.SimpleDateFormat pattern. The following commands are supported: |
|
|
Invokes a method on the referenced bean and returns the result of the method invocation. To specify a method name, you can either use the |
|
| Looks up the bean with the ID, beanID, in the registry and returns a reference to the bean itself. For example, if you are using the splitter EIP, you could use this variable to reference the bean that implements the splitting algorithm. |
|
| The value of the Key property placeholder . |
|
| The value of the Key property placeholder, where the location of the properties file is given by Location . |
|
| The name of the current thread. |
|
|
Returns the ID of the current route through which the |
|
|
References a type or field by its Fully-Qualified-Name (FQN). To refer to a field, append |
|
| From Camel 2.17, the collate function iterates the message body and groups the data into the sub lists of specific size. You can use with the Splitter EIP to split a message body and group or batch the submessages into a group of N sublists. |
|
| 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. |
30.7. Operator Reference
Binary operators
The binary operators for simple language predicates are shown in Table 30.2, “Binary Operators for the Simple Language”.
Operator | Description |
---|---|
| Equals. |
| Equals ignore case. Ignore the case when comparing string values. |
| Greater than. |
| Greater than or equals. |
| Less than. |
| Less than or equals. |
| Not equal to. |
| Test if LHS string contains RHS string. |
| Test if LHS string does not contain RHS string. |
| Test if LHS string matches RHS regular expression. |
| Test if LHS string does not match RHS regular expression. |
| Test if LHS string appears in the RHS comma-separated list. |
| Test if LHS string does not appear in the RHS comma-separated list. |
|
Test if LHS is an instance of RHS Java type (using Java |
|
Test if LHS is not an instance of RHS Java type (using Java |
|
Test if LHS number lies in the RHS range (where range has the format, |
|
Test if LHS number does not lie in the RHS range (where range has the format, |
| New in Camel 2.18. Test if the LHS string starts with the RHS string. |
| New in Camel 2.18. Test if the LHS string ends with the RHS string. |
Unary operators and character escapes
The binary operators for simple language predicates are shown in Table 30.3, “Unary Operators for the Simple Language”.
Operator | Description |
---|---|
| Increment a number by 1. |
| Decrement a number by 1. |
| The newline character. |
| The carriage return character. |
| The tab character. |
| (Obsolete) Since Camel version 2.11, the backslash escape character is not supported. |
Combining predicates
The conjunctions shown in Table 30.4, “Conjunctions for Simple Language Predicates” can be used to combine two or more simple language predicates.
Operator | Description |
---|---|
| Combine two predicates with logical and. |
| Combine two predicates with logical inclusive or. |
|
Deprecated. Use |
|
Deprecated. Use |