Appendix B. Expressions and predicates

Expressions and predicates are built-in types in Camel that you’ve seen used throughout this book. They’re very versatile and are used in different places, but they’re most noticeable in the Camel routes. For example, predicates are used in the Message Filter and Content-Based Router EIPs. Expressions are used for computing correlation keys for the Aggregator EIP, and appendix A covered the Simple expression language, which is another testament to the versatility of expressions.

B.1. Expressions

A Camel expression (org.apache.camel.Expression) is evaluated at runtime on the instance of Exchange that is under processing. You can use either standard or custom expressions.

B.1.1. Standard expressions

The org.apache.camel.Expression interface is as follows:

public interface Expression {
<T> T evaluate(Exchange exchange, Class<T> type);
}

The evaluate method uses generics to specify the desired return type.

Syntax sugar

Camel provides syntax sugar for working with expressions. Suppose you want to implement a route that can return a message consisting of “Hello” plus the input message. This can be done using the Message Translator EIP, which leverages an Expression to transform a message. With the help of the syntax sugar, you can use the fluent builder style in the Java DSL to express that you want to prepend “Hello” to the message body:

from("direct:hey").transform(body().prepend("Hello "));

Alternatively, you could use the Simple expression language (covered in appendix A), which may be easier to understand in this example:

from("direct:hey").transform(simple("Hello ${body}"));

Simple comes in handy when using Spring XML, because it’s a scripting language that can be used in XML, as opposed to the former solution, which can’t easily be used in Spring XML. That’s because it’s based on Java code, which you can’t use directly in Spring XML files.

Using expressions with Spring XML

In the Java DSL, you have all the power of the Java language, which you don’t have at your fingertips in Spring XML. The following route isn’t possible in Spring XML.

<route>
<from uri="direct:hey"/>
<transform>
<body><prepend>Hello </prepend></body>
</transform>
</route>

Instead, you can leverage Simple, like this:

<route>
<from uri="direct:hey"/>
<transform>
<simple>Hello ${body}</simple>
</transform>
</route>

Although Camel provides a lot of built-in expressions to support many common use cases, there could be situations where you need to implement a custom expression.

B.1.2. Using custom expressions

Suppose you need to transform the message in a different way, and only the power of the Java programming language can perform the transformation. In this case, you can use a custom expression, as shown in listing B.1.

Listing B.1. Implementing a custom expression
public class MyExpression implements Expression {

public <T> T evaluate(Exchange exchange, Class<T> type) {
String body = exchange.getIn().getBody(String.class);
Object answer;
if (body.contains("Camel")) {
answer = "Yes Camel rocks";
} else {
answer = "Hello " + body;
}
return exchange.getContext().getTypeConverter()
.convertTo(type, answer);
}

}

Using a custom expression in the Java DSL is just a matter of providing an instance in the Transform EIP, as follows:

from("direct:hey").transform(new MyExpression());

When using custom expressions in Spring XML, you have to define the expression as a bean, and then use the method call expression to invoke the expression:

<bean id="myExpression" class="camelinaction.MyExpression"/>

<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:hey"/>
<transform>
<method ref="myExpression"/>
</transform>
</route>
</camelContext>

You may have noticed that listing B.1 uses the Camel type converter to convert the answer to the given type. Camel offers an ExpressionAdapter class that removes the need for converting. Here’s the same custom expression using the adapter:

Listing B.2. Implementing custom expression by extending ExpressionAdapter
public class MyExpression extends ExpressionAdapter {

@Override
public Object evaluate(Exchange exchange) {
String body = exchange.getIn().getBody(String.class);
if (body.contains("Camel")) {
return "Yes Camel rocks";
} else {
return "Hello " + body;
}
}
}

That’s it for expressions. Let’s look now at predicates.

B.2. Predicates

A Camel predicate (org.apache.camel.Predicate) is a specialized expression that always returns a boolean type. This makes predicates useful for yes/no kinds of expressions. For example, predicates are used with the Content-Based Router EIP. There are standard predicates and also custom and compound predicates.

B.2.1. Standard predicates

This is the Predicate interface:

public interface Predicate {
boolean matches(Exchange exchange);
}

First we’ll cover the common use cases for using predicates.

Syntax sugar

Camel provides syntax sugar for working with predicates. Suppose you want to filter messages using the Message Filter EIP and only allow “Camel” messages to pass through the filter. This can easily be defined in a Camel Java DSL route, as follows:

from("direct:quotes")
.filter(body().contains("Camel")).to("direct:camelQuotes");

As you can see, you can define the predicate as if the body contained the word “Camel” using the fluent builder style.

Implementing this example using Spring XML requires a different approach, because Spring XML is not Java code and it doesn’t provide the same level of syntax sugar.

Using predicates with Spring XML

When you use Spring XML, you can use expression languages such as Simple (covered in appendix A). For example, you can leverage Simple as follows:

<route>
<from uri="direct:quotes"/>
<filter>
<simple>${body} contains 'Camel'</simple>
<to uri="direct:camelQuotes"/>
</filter>
</route>

Although Camel provides a lot of built-in predicates to support many common use case, there may be situations where you need to implement a custom predicate.

B.2.2. Using custom predicates

Suppose you need to filter messages using a more complex algorithm, or you just feel more comfortable using Java code to compute the predicate. In that case, you can implement a custom predicate.

Listing B.3. Implementing a custom predicate
public class MyPredicate implements Predicate {

public boolean matches(Exchange exchange) {
String body = exchange.getIn().getBody(String.class);
if (body.contains("Camel")) {
return true;
} else if (body.startsWith("Secret")) {
return true;
}

return false;
}
}

As you can see in listing B.3, it’s easy to implement a custom predicate. All you have to do is implement the matches method and return either true or false.

Using a custom predicate in a route is just as easy. You simply provide an instance of it to the filter EIP:

from("direct:quotes")
.filter(new MyPredicate()).to("direct:camelQuotes");

When using custom predicates in Spring XML, you have to define the predicate as a bean, and then use the method call expression to invoke the predicate. Here’s the equivalent example in Spring XML:

<bean id="myPredicate" class="camelinaction.MyPredicate"/>

<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:quotes"/>
<filter>
<method ref="myPredicate"/>
<to uri="direct:camelQuotes"/>
<filter>
</route>
</camelContext>

Before we end this appendix, we want to show you one last thing: how to combine other predicates into a compound predicate.

B.2.3. Using compound predicates

You may have a number of existing predicates you want to use together. For example, you may want to define a predicate as follows: Is the message a String message and either a Camel or a secret quote?

In this definition, you have three predicates:

  1. Is the message a String type?
  2. Is the message a "Camel" quote?
  3. Is the message a "Secret" quote?

You just have to use these three predicates together in a compound predicate:

A and (B or C)

Implementing this in Camel can be done with the help of PredicateBuilder, which provides a range of predicate-related methods. The builder has methods to combine two predicates using the binary operators and and or. You can then define this in your Camel routes, like this:

Predicate a = body().isInstanceOf(String.class);
Predicate b = body().contains("Camel");
Predicate c = body().startsWith("Secret");

Predicate bc = PredicateBuilder.or(b, c);
Predicate compound = PredicateBuilder.and(a, bc);

from("direct:quotes")
.filter(compound).to("direct:camelQuotes");

First you define the three predicates. Then, to build the compound predicate, you first combine predicates b and c together using the or operator. Then this combined predicate is combined with the a predicate using the and operator.

B.3. Summary

This appendix covered two central concepts used in Camel: expressions and predicates. Both are used throughout Camel and this book.

In many normal use cases, the built-in predicates and expressions should be sufficient. In this appendix, you learned how to use custom expressions and predicates. This should give you enough information that you’ll have no trouble using predicates and expressions with Camel.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset