When designing your Camel routes, you may sometimes want a route to have multiple inputs. Maybe you want to receive messages from a web service and from a JMS queue.
You can’t have multiple
from() methods in the same route, so how can you have multiple entry points to the same route?
Similarly, you might want to reuse the same Camel message processing logic in multiple places, so how do you avoid duplicating code?
The answer to both these questions is to join your routes together, using Camel’s in-memory messaging components: Direct, Direct-VM, VM and SEDA.
In this article I’ll explain each of these components, how they differ, and how you can use them to make your routes more modular and awesome.
First…an example scenario
First I’m going to start with an example.
I have defined a route that validates an incoming order, by passing a message to some underlying system. My orders initially arrive through JMS messages.
But what happens when orders start coming from new sources - such as a file upload, or a web service call?
To avoid having to repeat the same route code, Camel has features built-in which allow routes to have multiple inputs, by using a range of joining components to glue these routes together.
So how does it work? Camel glues endpoints together using the components Direct, VM and SEDA.
These components join your Camel routes together in different ways. They are collectively known as Camel’s in-memory messaging components, because they allow messages to be passed between routes, while the message stays in memory at all times. This is a really important detail, which I’ll touch on again later.
But for now, let’s now look at each of these components to see how they differ, and where you might use them.
This has to be one of the most frequently-asked questions by Camel beginners:
What does “direct” mean in a route?
You’ve probably seen the code
direct:... in so many Camel tutorials on the web. But what does
direct actually do?
direct is one of the most simple ways of linking your routes together. When it’s used in a
from() definition, it creates a synchronous endpoint that can be invoked by other Camel routes. For example, this code:
Means that a Direct endpoint called
yourname is created. That same endpoint can then be invoked in another
to() statement somewhere else, like this:
.to("direct:yourname"); // sends the message to the direct:yourname endpoint
The Direct component joins routes in a synchronous way. This means that when one route sends a message to another
direct endpoint using
to("direct:myroute"), the route
myroute will be executed in the same thread as the first route, and a response message will be returned.
In examples, it’s often used because it provides a simple entry point into a route, without having to expose a web service, or otherwise rely on an external interface.
The simplicity of Direct comes with some drawbacks.
Direct endpoints can only be accessed by other routes that are running in the same CamelContext and in the same JVM. This means that you cannot access a Direct endpoint from another CamelContext. Remember the CamelContext is the environment where your Camel routes are defined and later instantiated.
So what happens if you want to access a route in another CamelContext? You use the next component, Direct-VM.
This synchronous component works in a very similar way to the Direct component described above.
When used as a start component, Direct-VM allows a route to be invoked synchronously from another route.
The difference with the Direct-VM component is that direct-vm endpoints can be seen from other Camel Contexts, as long as they share the same Java Virtual Machine (JVM).
This opens up possibilities of linking routes together that were not developed in the same CamelContext. For example, you might use this component if you have different CamelContexts deployed in one container - such as when you’re deploying into JBoss Fuse or Talend ESB.
SEDA stands for staged event-driven architecture. The SEDA component joins Camel routes together asynchronously using an in-memory message queue.
While the Direct and Direct-VM components take a synchronous approach to joining routes, SEDA does the opposite. SEDA asynchronously joins routes together.
When a Camel route publishes a message to a
seda: endpoint, the message is sent and control is returned immediately to the calling route.
A SEDA consumer endpoint contains a buffer which is used to store the incoming messages. SEDA is configured by default to create a pool of threads to process incoming messages, so several messages can be processed at once, making it potentially more performant.
In this way, SEDA can be thought of as a simple replacement for JMS queues. It provides queue-like functionality, but without the overhead of running an external message broker like ActiveMQ.
Remember that Camel publishes messages to a SEDA endpoint asynchronously.
You can only access SEDA endpoints that are located in the same CamelContext. So what happens if you want to send a message to a SEDA queue in another CamelContext? You use the next component, VM.
In a similar way to how Direct and Direct-VM are related, VM is a similar component to SEDA.
When used as a start component, SEDA allows a route to be invoked asynchronously from another route.
However the difference between SEDA and VM is that the VM component allows endpoints to be accessed from different Camel Contexts, if they are running in the same JVM.
Again, the VM component opens up possibilities of linking routes together that were not developed in the same Camel Context, in an asynchronous manner.
Summary and best practices
TL;DR? Here’s a reminder of the characteristics of the four components:
|Within same CamelContext||Yes||Yes||Yes||Yes|
|Within same JVM||-||Yes||-||Yes|
Thinking about using these components in your routes? Remember
The biggest drawback of using in-memory messaging is that if the application fails, there’s a big chance you’ll lose your messages.
This isn’t a major consideration if you are designing the kind of integrations where it doesn’t matter if the message goes missing.
But think back to the case of the order processing example at the top of this article. If an order gets lost during a server outage, this potentially means lost business. Uh-oh.
Have a think about when it’s appropriate to use these in-memory messaging components, and when it’s more appropriate to hand over the message to an external broker, such as ActiveMQ, for reliability.
There isn’t a hard and fast rule. The right solution always depends on your use case. So when designing integrations using Camel, think about what you’d do if you lost messages. Would it matter? If it would, consider using transactions and persistent messaging to minimise any message loss.
Has this article helped you understand the difference between the Direct, VM and SEDA components? How are you planning to use these components in your Camel routes? Please share your comments, thoughts and questions in the box below!