Intercept
The intercept feature in Camel supports intercepting Exchange's' while they are being routed.
Kinds of interceptors
Camel supports three kinds of interceptors:
The interceptSendToEndpoint
is dynamic hence it will also trigger if a
dynamic URI is constructed that Camel was not aware of at startup
time.
The interceptFrom
is not dynamic, and will only intercept
all the known routes when Camel is starting.
So if you construct a Consumer
using the Camel Java API and consumes
messages from this endpoint, then the interceptFrom
is not triggered.
Interceptor scopes
All the interceptors can be configured on global, route scope, or with Route Configuration.
This means multiple interceptors can be triggered.
Most of the examples in this page are on global scope. To use route scope, then its similar but is done on the route.
For example the first example further below can be done as shown on route scope:
from("jms:queue:order")
.intercept().to("log:hello").end() // intercepts only in this route
.to("bean:validateOrder")
.to("bean:processOrder");
And in XML:
<route>
<from uri="jms:queue:order"/>
<intercept>
<to uri="log:hello"/>
</intercept>
<to uri="bean:validateOrder"/>
<to uri="bean:processOrder"/>
</route>
Common features of the interceptors
All these interceptors support the following features:
-
Predicate using
when
to only trigger the interceptor in certain conditions -
stop
forces stopping continue routing the Exchange and mark it as completed successful (it’s actually the Stop EIP). -
skip
when used withinterceptSendToEndpoint
will skip sending the message to the original intended endpoint. -
afterUri
when used withinterceptSendToEndpoint
allows to send the message to an endpoint afterwards. -
interceptFrom
andinterceptSendToEndpoint
supports endpoint URI pattern matching by: exact uri, wildcard, regular expression. See further below for more details. -
The intercepted endpoint uri is stored as message header with the key
Exchange.INTERCEPTED_ENDPOINT
.
Using intercept
The Intercept
is intercepting the Exchange
on every processing steps during routing.
Given the following example:
// global interceptor for all routes
intercept().to("log:hello");
from("jms:queue:order")
.to("bean:validateOrder")
.to("bean:processOrder");
What happens is that the Exchange
is intercepted
before each processing step, that means that it will be intercepted
before
-
.to("bean:validateOrder")
-
.to("bean:processOrder")
So in this example we intercept the Exchange
twice.
The example is as follows in XML:
<camelContext>
<!-- global interceptor for all routes -->
<intercept>
<to uri="log:hello"/>
</intercept>
<route>
<from uri="jms:queue:order"/>
<to uri="bean:validateOrder"/>
<to uri="bean:processOrder"/>
</route>
</camelContext>
Controlling when to intercept using a predicate
If you only want to intercept "sometimes", then you can use a predicate.
For instance in the sample below we only intercept if the message body contains the string word Hello:
intercept().when(body().contains("Hello")).to("mock:intercepted");
from("jms:queue:order")
.to("bean:validateOrder")
.to("bean:processOrder");
And in XML:
<camelContext>
<intercept>
<when>
<simple>${in.body} contains 'Hello'</simple>
</when>
<to uri="mock:intercepted"/>
</intercept>
<route>
<from uri="jms:queue:order"/>
<to uri="bean:validateOrder"/>
<to uri="bean:processOrder"/>
</route>
</camelContext>
Stop routing after being intercepted
It is also possible to stop continue routing after being intercepted. Now suppose if the message body contains the word Test we want to log and stop, then we can do:
intercept().when(body().contains("Hello"))
.to("mock:intercepted")
.stop(); // stop continue routing
from("jms:queue:order")
.to("bean:validateOrder")
.to("bean:processOrder");
And in XML:
<camelContext>
<intercept>
<when>
<simple>${body} contains 'Test'</simple>
<to uri="log:test"/>
<stop/> <!-- stop continue routing -->
</when>
</intercept>
<route>
<from uri="jms:queue:order"/>
<to uri="bean:validateOrder"/>
<to uri="bean:processOrder"/>
</route>
</camelContext>
Using intercept from
The interceptFrom
is for intercepting any incoming
Exchange, in any route (it intercepts all the from EIPs)
This allows you to do some custom behavior for received Exchanges. You can provide a specific uri for a given Endpoint then it only applies for that particular route.
So lets start with the logging example. We want to log all the
incoming messages, so we use interceptFrom
to route to the
Log component.
interceptFrom()
.to("log:incoming");
from("jms:queue:order")
.to("bean:validateOrder")
.to("bean:processOrder");
And in XML:
<camelContext>
<intercept>
<to uri="log:incoming"/>
</intercept>
<route>
<from uri="jms:queue:order"/>
<to uri="bean:validateOrder"/>
<to uri="bean:processOrder"/>
</route>
</camelContext>
If you want to only apply a specific endpoint, such as all jms endpoints, you can do:
interceptFrom("jms*")
.to("log:incoming");
from("jms:queue:order")
.to("bean:validateOrder")
.to("bean:processOrder");
from("file:inbox")
.to("ftp:someserver/backup")
In this example then only messages from the JMS route is intercepted, because
we specified a pattern in the interceptFrom
as jms*
(uses a wildcard).
The pattern syntax is documented in more details later.
And in XML:
<camelContext>
<interceptFrom uri="jms*">
<to uri="log:incoming"/>
</intercept>
<route>
<from uri="jms:queue:order"/>
<to uri="bean:validateOrder"/>
<to uri="bean:processOrder"/>
</route>
<route>
<from uri="file:inbox"/>
<to uri="ftp:someserver/backup"/>
</route>
</camelContext>
Using intercept when sending to an endpoint
You can also intercept when Camel is sending a message to an endpoint.
This can be used to do some custom processing before the message is sent to the intended destination.
The interceptor can also be configured to not send to the destination (skip) which means the message is detoured instead.
A Predicate can also be used to control when to intercept, which has been previously covered.
The afterUri
option, is used when you need to process
the response message from the intended destination. This functionality
was added later to the interceptor, in a form of sending to yet another endpoint.
Let start with a basic example, where we want to intercept when a message is being sent to kafka:
interceptSendToEndpoint("kafka*")
.to("bean:beforeKafka");
from("jms:queue:order")
.to("bean:validateOrder")
.to("bean:processOrder")
.to("kafka:order");
And in XML:
<camelContext>
<interceptSendToEndpoint uri="kafka*">
<to uri="bean:beforeKafka"/>
</intercept>
<route>
<from uri="jms:queue:order"/>
<to uri="bean:validateOrder"/>
<to uri="bean:processOrder"/>
<to uri="kafka:order"/>
</route>
</camelContext>
When you also want to process the message after it has been sent to the intended destination,
then the example is slightly odd because you have to use the afterUri
as shown:
interceptSendToEndpoint("kafka*")
.to("bean:beforeKafka")
.afterUri("bean:afterKafka");
from("jms:queue:order")
.to("bean:validateOrder")
.to("bean:processOrder")
.to("kafka:order");
And in XML:
<camelContext>
<interceptSendToEndpoint uri="kafka*" afterUri="bean:afterKafka">
<to uri="bean:beforeKafka"/>
</intercept>
<route>
<from uri="jms:queue:order"/>
<to uri="bean:validateOrder"/>
<to uri="bean:processOrder"/>
<to uri="kafka:order"/>
</route>
</camelContext>
Skip sending to original endpoint
Sometimes you want to intercept and skip sending messages to a specific endpoint.
For example to avoid sending any message to kafka, but detour them to a mock endpoint, can be done as follows:
interceptSendToEndpoint("kafka*").skipSendToOriginalEndpoint()
.to("mock:kafka");
from("jms:queue:order")
.to("bean:validateOrder")
.to("bean:processOrder")
.to("kafka:order");
And in XML:
<camelContext>
<interceptSendToEndpoint uri="kafka*" skipSendToOriginalEndpoint="true">
<to uri="mock:kafka"/>
</intercept>
<route>
<from uri="jms:queue:order"/>
<to uri="bean:validateOrder"/>
<to uri="bean:processOrder"/>
<to uri="kafka:order"/>
</route>
</camelContext>
Conditional skipping sending to endpoint
You can combine both a predicate and skip sending to the original endpoint. For example suppose you have some "test" messages that sometimes occur, and that you want to avoid sending these message to a downstream kafka system, then this can be done as shown:
interceptSendToEndpoint("kafka*").skipSendToOriginalEndpoint()
.when(simple("${header.biztype} == 'TEST'")
.log("TEST message detected - is NOT send to kafka");
from("jms:queue:order")
.to("bean:validateOrder")
.to("bean:processOrder")
.to("kafka:order");
And in XML:
<camelContext>
<interceptSendToEndpoint uri="kafka*" skipSendToOriginalEndpoint="true">
<when><simple>${header.biztype} == 'TEST'</simple></when>
<log message="TEST message detected - is NOT send to kafka"/>
</intercept>
<route>
<from uri="jms:queue:order"/>
<to uri="bean:validateOrder"/>
<to uri="bean:processOrder"/>
<to uri="kafka:order"/>
</route>
</camelContext>
Intercepting endpoints using pattern matching
The interceptFrom
and interceptSendToEndpoint
supports endpoint pattern
matching by the following rules in the given order:
-
match by exact URI name
-
match by wildcard
-
match by regular expression
Intercepting when matching by exact URI
This matches only a specific endpoint with exactly the same URI.
For example to intercept messages being send to a specific JMS queue you can do:
interceptSendToEndpoint("jms:queue:cheese").to("log:smelly");
Intercepting when matching endpoints by wildcard
Match by wildcard allows you to match a range of endpoint or all of a
given type. For instance use file:*
will match all file based endpoints.
interceptFrom("file:*").to("log:from-file");
Match by wildcard works so that the pattern ends with a \*
and that
the uri matches if it starts with the same pattern.
For example, you can be more specific, to only match for files from specific folders like:
interceptFrom("file:order/inbox/*").to("log:new-file-orders");