A Simple, the expression language

published book

Camel offers a powerful expression language, which back in the earlier days wasn’t as powerful and was labeled Simple. It has evolved to become much more since then, but don’t worry: it’s still simple to use.

The Simple language is provided out of the box in the camel-core JAR file, which means you don’t have to add any JARs on the classpath to use it.

livebook features:
highlight, annotate, and bookmark
Select a piece of text and click the appropriate icon to annotate, bookmark, or highlight (you can also use keyboard shortcuts - h to highlight, b to bookmark, n to create a note).

You can automatically highlight by performing the text selection while keeping the alt/ key pressed.
highlights
join today to enjoy all our content. all the time.
 

A.1   Introducing Simple

In a nutshell, the Simple expression language evaluates an expression on the current instance of Exchange that is under processing. The Simple language can be used for both expressions and predicates, which makes it a perfect match to be used in your Camel routes.

For example, the Content-Based Router EIP can leverage the Simple language to define predicates in the when clauses, as shown here:

The equivalent Spring XML example would be as follows:

As you can see from the preceding examples, the Simple expression is understandable and similar to other scripting languages. In these examples, Camel will evaluate the expression as a Predicate, which means the result is a boolean, which is either true or false. In the example, you use operators to determine whether the message body contains the word Camel or whether the message header amount is larger than 1000.

That gives you a taste of the Simple language. Let’s look at its syntax.

livebook features:
discuss
Ask a question, share an example, or respond to another reader. Start a thread by selecting any piece of text and clicking the discussion icon.
discussions
Get Camel in Action
add to cart

A.2   Syntax

The Simple language uses ${ } placeholders for dynamic expressions, such as those in the previous examples. You can use multiple ${ } placeholders in the same expression, or even nest placeholders.

For example, these are valid Simple expressions:

An alternative syntax is available to accommodate a clash with Spring’s property placeholder feature. You can now also use $simple{ } placeholders with Simple, such as shown in this example:

These examples use variables such as body and header. The next section covers this.

livebook features:
settings
Update your profile, view your dashboard, tweak the text size, or turn on dark mode.
settings
Sign in for more free preview time

A.3   Built-in variables

The Simple language provides a number of variables that bind to information in the current Exchange. You’ve already seen the body and header. Table A.1 lists all the variables available.

Table A.1 Variables in the Simple language

Variable

Type

Description

body

in.body

Object

Contains the input message body

out.body

Object

Contains the output message body

header.XXX

headers.XXX

in.header.XXX

in.headers.XXX

header[XXX]

headers[XXX]

in.header[XXX]

in.headers[XXX]

ObjectC

Contains the input message header XXX

out.header.XXX

out.headers.XXX

out.header[XXX]

out.headers[XXX]

Object

Contains the output message header XXX

exchangeProperty.XXX

exchangeProperty[XXX]

Object

Contains the exchange property XXX

headers

Map

The input message headers

in.headers

Map

The input message headers

exchangeId

String

Contains the unique ID of the Exchange

sys.XXX

sysenv.XXX

String

Contains the system environment XXX

exception

Object

Contains the exception on the Exchange, if any exists

exception.stacktrace

String

Contains the exception stacktrace on the Exchange. If not set, will fallback to the Exchange.EXCEPTION_CAUGHT property on the exchange.

exception.message

String

Contains the exception message on the Exchange, if any exists

threadName

String

Contains the name of the current thread; can be used for logging purposes

camelId

String

The CamelContext name.

exchange

Exchange

The current Exchange object.

routelId

String

The ID of the route where this Exchange is currently being routed.

null

null

Represents null.

messageHistory

String

The message history of the current exchange. This shows how the message has been routed.

messageHistory(false)

String

The message history of the current exchange but without showing an of the Exchange content. Helpful if you don't want sensitive details showing up in the logs.

\n

String

Use a newline character.

\t

String

Use a tab character.

\r

String

Use a carriage return character.

\}

String

Use the '}' character, which is special for a simple expression of course.

The variables can easily be used in a Simple expression, as you’ve already seen. Logging the message body can be done using ${body} as shown in the following route snippet:

The Simple language also has a set of built-in functions.

livebook features:
highlight, annotate, and bookmark
Select a piece of text and click the appropriate icon to annotate, bookmark, or highlight (you can also use keyboard shortcuts - h to highlight, b to bookmark, n to create a note).

You can automatically highlight by performing the text selection while keeping the alt/ key pressed.
highlights
join today to enjoy all our content. all the time.
 

A.4   Built-in functions

The Simple language has four functions at your disposal, as listed in table A.2.

Table A.2 Functions provided in the Simple language

Function

Type

Description

bodyAs(type)

type

Converts the body to the given type. For example, bodyAs(String) or bodyAs(com.foo.MyType). Will return null if the body could not be converted.

 

bodyAs(type).OGNL

Object

Converts the body to the given type and then invokes a method on the resulting object using OGNL notation. May return null if the body could not be converted or if the method returns null.

mandatoryBodyAs(type)

type

Converts the body to the given type. Will throw a NoTypeConversionAvailableException if the body could not be converted.

mandatoryBodyAs(type).OGNL

Object

Converts the body to the given type and then invokes a method on the resulting object using OGNL notation. Will throw a NoTypeConversionAvailableException if the body could not be converted.

headerAs(key, type)

type

Converts the header with the given key to the given type. Will return null if the header could not be converted.

bean:beanId[?method]

Object

Invokes a method on a bean. Camel will look up the bean with the given ID from the Registry and invoke the appropriate method. You can optionally explicitly specify the name of the method to invoke. 

date:command:pattern

String

Formats a date. The command must be either now or header.XXX: now represents the current timestamp, whereas header.XXX will use the header with the key XXX.

The pattern is based on the java.text.SimpleDataFormat format.

camelContext.OGNL

Object

Invoke a method on the CamelContent using Object Graph Navigation Language (OGNL) notation. You can see more about OGNL later in this appendix.

collate(sub_list_size)

Iterator

Split a message body into sub lists of size sub_list_size. Actual result is an Iterator which points to the sub Lists.

exchange.OGNL

Object

Invoke a method on the Exchange using OGNL notation. You can see more about OGNL later in this appendix.

exchangeProperty.XXX.OGNL

Object

Get the exchange property XXX and then invoke a method on the resulting object using OGNL notation.

ref:XXX

Object

Lookup and return bean with ID XXX.

properties-location:[locations:]key

String

Resolves a property with the given key using the Camel Properties component.

properties:key[:default]

String

Resolves a property with the given key using the Camel Properties component. If the key doesn't exits or has no value, a specified default can be used.

random(max)

Integer

Returns a random number between 0 (included) and the specified max (excluded).

random(min, max)

Integer

Returns a random number between the specified min (included) and the specified max (excluded).

skip(number_of_items)

Iterator

Skip the specified number of items in the current message body and return the remainder..

type:name.field

Object

Refers to a type or a field by its FQN. For example, ${type:org.apache.camel.Exchange.FILE_NAME} would refer to the constant Exchange.FILE_NAME field which would resolve to “CamelFileName”.

For example, to log a formatted date from the message header, you could do as follows:

In this example, the input message is expected to contain a header with the key myDate, which should be of type java.util.Date.

Suppose you need to organize received messages into a directory structure containing the current day’s date as a parent folder. The file producer has direct support for specifying the target filename using the Simple language as shown in bold:

Now suppose the file must use a filename generated from a bean. You can use the bean function to achieve this:

In this example, Camel will look up the bean with the ID uuidBean from the Registry and invoke the generate method. The output of this method invocation is returned and used as the filename.

The Camel Properties component is used for property placeholders. For example, you could store a property in a file containing a configuration for a big-spender threshold.

Then you could refer to the big properties key from the Simple language:

The Simple language also has built-in variables when working with the Camel File and FTP components.

livebook features:
discuss
Ask a question, share an example, or respond to another reader. Start a thread by selecting any piece of text and clicking the discussion icon.
discussions
Sign in for more free preview time

A.5   Built-in file variables

Files consumed using the File or FTP components have file-related variables available to the Simple language. Table A.3 lists those variables.

Table A.3 File-related variables available when consuming files

Variable

Type

Description

file:name

String

Contains the filename (relative to the starting directory)

file:name.ext

String

Contains the file extension

file:name.ext.single

String

Contains the file extension whereby only the extension after the last dot is returned. So a “tar.gz” file would have an extension of “gz”

file:name.noext

String

Contains the filename without extension (relative to the starting directory)

file:name.noext.single

String

Contains the filename without extension (relative to the starting directory) whereby only the extension after the last dot is stripped. So a file named “my-dir/backup.tar.gz” would mean “my-dir/backup.tar” is returned.

file:onlyname

String

Contains the filename without any leading paths

file:onlyname.noext

String

Contains the filename without extension and leading paths

file:onlyname.noext.single

String

Contains the filename without extension and leading paths whereby only the extension after the last dot is stripped. So a file named “backup.tar.gz” would mean “backup.tar” is returned.

file:parent

String

Contains the file parent (the paths leading to the file)

file:path

String

Contains the file path (including leading paths)

file:absolute

Boolean

Whether or not the filename is an absolute or relative file path

file:absolute.path

String

Contains the absolute file path.

file:length

file:size

Long

Contains the file length

file:modified

Date

Contains the modification date of the file as a java.util.Date type

Among other things, the file variables can be used to log which file has been consumed:

The File and FTP endpoints have options that accept Simple language expressions. For example, the File consumer can be configured to move processed files into a folder you specify. Suppose you must move files into a directory structure organized by dates. This can be done by specifying the expression in the move option, as follows:

Tip

 The FTP endpoint supports the same move option as shown here.

Another example where the file variables come in handy is if you have to process files differently based on the file extension. For example, suppose you have CSV and XML files:

Note

 You can read more about the file variables at the Camel website: http://camel.apache.org/file-language.html.

In this appendix, we’ve used the Simple language for predicates. In fact, the previous example determines whether the file is a text file or not. Doing this requires operators.

livebook features:
settings
Update your profile, view your dashboard, tweak the text size, or turn on dark mode.
settings
Tour livebook

Take our tour and find out more about liveBook's features:

  • Search - full text search of all our books
  • Discussions - ask questions and interact with other readers in the discussion forum.
  • Highlight, annotate, or bookmark.
take the tour

A.6   Built-in operators

The first example in this appendix implemented the Content-Based Router EIP with the Simple expression language. It used predicates to determine where to route a message, and these predicates use operators. Table A.4 lists all the operators supported in Simple.

Table A.4 Operators provided in the Simple language

Operator

Description

==

Tests whether the left side is equal to the right side

=~

Tests whether the left side is equal to the right side ignoring case

Tests whether the left side is greater than the right side

>=

Tests whether the left side is greater than or equal to the right side

Tests whether the left side is less than the right side

<=

Tests whether the left side is less than or equal to the right side

!=

Tests whether the left side is not equal to the right side

contains

Tests whether the left side contains the String value on the right side

not contains

Tests whether the left side doesn’t contain the String value on the right side

starts with

Tests whether the left side starts with the String value on the right side

ends with

Tests whether the left side ends with the String value on the right side

in

Tests whether the left side is in a set of values specified on the right side; the values must be separated by commas

not in

Tests whether the left side is not in a set of values specified on the right side; the values must be separated by commas

range

Tests whether the left side is within a range of values defined with the following syntax: 'from..to'

not range

Tests whether the left side is not within a range of values defined with the following syntax: 'from..to'

regex

Tests whether the left side matches a regular expression pattern defined as a String value on the right side

not regex

Tests whether the left side doesn’t match a regular expression pattern defined as a String value on the right side

is

Tests whether the left side type is an instance of the value on the right side

not is

Tests whether the left side type is not an instance of the value on the right side

++

Unary operator which increments a left hand side function and returns that value. So if we had a counter header with value = 1, the expression ${header.counter}++ would return 2.

--

Unary operator which decrements a left hand side function and returns that value. So if we had a counter header with value = 2, the expression ${header.counter}-- would return 1.

The operators require the following syntax:

The value on the left side must be enclosed in a ${ } placeholder. The operator must be separated with a single space on the left and right. The right value can either be a fixed value or another dynamic value enclosed using ${ }.

Let’s look at some examples.

Here you test whether the foo header is equal to the String value "Camel". If you want to test for "Camel rocks", you must enclose the String in quotes (because the value contains a space):

Camel will automatically type coerce, so you can compare apples to oranges. Camel will regard both as fruit:

Suppose the bar header is a String with the value "100". Camel will convert this value to the same type as the value on the right side, which is numeric. It will therefore compute 100 < 200, which renders true.

You can use the range operator to test whether a value is in a numeric range. 

Both the from and to range values are inclusive. You must define the range exactly as shown.

A regular expression can be used to test a variety of things, such as whether a value is a four-digit value:

You can also use the built-in functions with the operators. For example, to test whether a given header has today’s date, you can leverage the date function:

Tip

 You can see more examples in the Camel Simple online documentation: http://camel.apache.org/simple.html.

The Simple language also allows you to combine two expressions together.

A.6.1   Combining expressions

The Simple language can combine expressions using the && (and) or || (or) operators.

The syntax for combining two expressions is as follows:

Here’s an example using and to group two expressions:

The Simple language also supports an OGNL feature.

livebook features:
highlight, annotate, and bookmark
Select a piece of text and click the appropriate icon to annotate, bookmark, or highlight (you can also use keyboard shortcuts - h to highlight, b to bookmark, n to create a note).

You can automatically highlight by performing the text selection while keeping the alt/ key pressed.
highlights
join today to enjoy all our content. all the time.
 

A.7   The OGNL feature

Both the Simple language and Bean component support an Object Graph Navigation Language (OGNL) feature when specifying the method name to invoke. OGNL allows you to specify a chain of methods in the expression.

Suppose the message body contains a Customer object that has a getAddress() method. To get the ZIP code of the address, you would simply type the following:

You can use a shorter notation, omitting the get prefix and the parentheses.

In this example, the ZIP code will be returned. But if the getAddress method returns null, the example would cause a NoSuchMethodException to be thrown by Camel. If you want to avoid this, you can use the null-safe operator ?. as follows:

The methods in the OGNL expression can be any method name. For example, to invoke a sayHello method, you would do this:

Camel uses the bean parameter binding, which we covered in chapter 4. This means that the method signature of sayHello can have parameters that are bound to the current Exchange being routed:

The OGNL feature has specialized support for accessing Map and List types. For example, suppose the getAddress method has a getLines method that returns a List. You could access the lines by their index values, as follows:

If you try to index an element that is out of bounds, an IndexOutOfBoundsException exception is thrown. You can use the null-safe operator to suppress this exception:

If you want to access the last element, you can use last as the index value, as shown here:

The access support for Maps is similar, but you use a key instead of a numeric value as the index. Suppose the message body contains a getType method that returns a Map instance. You could access the gold entry as follows:

You could even invoke a method on the gold entry like this:

This concludes our tour of the various features supported by the Camel Simple language. We’ll now take a quick look at how to use the Simple language from custom Java code.

livebook features:
discuss
Ask a question, share an example, or respond to another reader. Start a thread by selecting any piece of text and clicking the discussion icon.
discussions

A.8   Using Simple from custom Java code

The Simple language is most often used directly in your Camel routes, in either the Java DSL or a Spring XML file. But it’s also possible to use it from custom Java code.

Here’s an example that uses the Simple language from a Camel Processor.

Listing A.1 Using the Simple language from custom Java code

As you can see in listing A.1, all it takes is creating an instance of SimpleBuilder, which is capable of evaluating either a predicate or an expression. In the listing, you use the Simple language as a predicate.

To use an expression to say “Hello,” you could do the following:

Notice how you specify that you want the response back as a String by passing in String.class to the evaluate method.

Listing A.1 uses the Simple language from within a Camel Processor, but you’re free to use it anywhere, such as from a custom bean. Just keep in mind that the Exchange must be passed into the matches method on the SimpleBuilder.

livebook features:
settings
Update your profile, view your dashboard, tweak the text size, or turn on dark mode.
settings
Sign in for more free preview time

A.9   Summary

This appendix covered the Simple language, which is an expression language provided with Camel.

You saw how well it blends with Camel routes, which makes it easy to define predicates in routes, such as those needed when using the Content-Based Router.

We also looked at how easy it was with the Simple language to access information from the Exchange message by using the built-in variables. You saw that Simple provides functions, such as a date function that formats dates and a bean function that invokes methods on beans.

Finally, we covered OGNL notation, which makes it even easier to access data from nested beans.

All together, the Simple language is a great expression language that should help you with 95 percent of your use cases.

sitemap

Unable to load book!

The book could not be loaded.

(try again in a couple of minutes)

manning.com homepage
meap badge