The CamelContext is the container that is the runtime Camel. The
CamelContext is the runtime system, which holds everything together as depicted in the figure below.
CamelContext provides access to many useful services, the most notable being components, type converters, a registry, endpoints, routes, data formats, and languages.
The following table lists the most common services provided by
Contains the components used.
Contains the endpoints that have been used.
The routes in use.
Contains the loaded data formats.
Contains the loaded languages.
Contains the loaded type converters. Camel has a mechanism that allows you to manually or automatically convert from one type to another.
Contains a registry that allows you to look up beans.
To better understand Apache Camel then lets talk a bit more about what is inside the
Camel’s routing engine is what moves messages under the hood. This engine isn’t exposed to the developer, but you should be aware that it’s there and that it does all the heavy lifting, ensuring that messages are routed properly.
Routes are a core abstraction for Camel. The simplest way to define a route is as a chain of Processors. There are many reasons for using routers in messaging applications. By decoupling clients from servers, and producers from consumers, routes can for example do the following:
Decide dynamically what server a client will invoke
Provide a flexible way to add extra processing
Allow for clients and servers to be developed independently
Foster better design practices by connecting disparate systems that do one thing well
Allow for clients of servers to be stubbed out (using mocks) for testing purposes
Each route in Camel has a unique identifier that’s used for logging, debugging, monitoring, and starting and stopping routes.
Routes also have exactly one input source for messages, so they’re effectively tied to an input endpoint.
To wire processors and endpoints together to form routes, Camel defines a DSL.
In Camel with Java, DSL means a fluent Java API that contains methods named for EIP terms.
Consider this example:
from("file:data/inbox") .filter().xpath("/order[not(@test)]") .to("jms:queue:order");
Here, in a single Java statement, you define a route that consumes files from a file endpoint. Messages are then routed to the Filter EIP, which will use an XPath predicate to test whether the message is not a test order. If a message passes the test, it’s forwarded to the JMS endpoint. Messages failing the filter test are skipped.
Camel provides multiple DSL languages, so you could define the same route by using the XML DSL, like this:
<route> <from uri="file:data/inbox"/> <filter> <xpath>/order[not(@test)]</xpath> <to uri="jms:queue:order"/> </filter> </route>
And in YAML:
- from: uri: "file:data/inbox" steps: - filter: xpath: "/order[not(@test)]" steps: - to: "jms:queue:order"
The DSLs provide a nice abstraction for Camel users to build applications with. Under the hood, though, a route is composed of a graph of processors.
During routing, exchanges flow from one processor to another; as such, you can think of a route as a graph having specialized processors as the nodes, and lines that connect the output of one processor to the input of another. Processors could be implementations of EIPs, producers for specific components, or your own custom code. The figure below shows the flow between processors.
A route first starts with a consumer (i.e.
from in the DSL) that populates the initial exchange. At each processor step, the out message from the previous step is the in message of the next. In many cases, processors don’t set an out message, so in this case the in message is reused. At the end of a route, the MEP of the exchange determines whether a reply needs to be sent back to the caller of the route. If the MEP is InOnly, no reply will be sent back. If it’s InOut, Camel will take the out message from the last step and return it.
Components are the main extension point in Camel.
FileComponent is referred to by file in a URI, and it creates
FileEndpoint. The endpoint is perhaps an even more fundamental concept in Camel.
An endpoint is the Camel abstraction that models the end of a channel through which a system can send or receive messages.
In Camel, you configure endpoints by using URIs, such as
file:data/inbox?delay=5000, and you also refer to endpoints this way. At runtime, Camel looks up an endpoint based on the URI notation. The figure below shows how this works.
The scheme (1) denotes which Camel component handles that type of endpoint. In this case, the scheme of
FileComponent then works as a factory, creating
FileEndpoint based on the remaining parts of the URI. The context path
data/inbox (2) tells
FileComponent that the starting folder is
data/inbox. The option,
delay=5000 (3) indicates that files should be polled at a 5-second interval.
The next figure shows how an endpoint works together with an exchange, producers,and consumers.
An endpoint acts as a factory for creating consumers and producers that are capable of receiving and sending messages to a particular endpoint.
A producer is the Camel abstraction that refers to an entity capable of sending a message to an endpoint. When a message is sent to an endpoint, the producer handles the details of getting the message data compatible with that particular endpoint. For example,
FileProducer will write the message body to a
JmsProducer, on the other hand, will map the Camel message to
javax.jms.Message before sending it to a JMS destination. This is an important feature in Camel, because it hides the complexity of interacting with particular transports. All you need to do is route a message to an endpoint, and the producer does the heavy lifting.
A consumer is the service that receives messages produced by some external system, wraps them in an exchange, and sends them to be processed. Consumers are the source of the exchanges being routed in Camel. To create a new exchange, a consumer will use the endpoint that wraps the payload being consumed. A processor is then used to initiate the routing of the exchange in Camel via the routing engine.
Camel has two kinds of consumers: event-driven consumers, and polling consumers (or scheduled polling consumers). The differences between these consumers are important, because they help solve different problems.
The most familiar consumer is the event-driven consumer, as illustrated:
This kind of consumer is mostly associated with client-server architectures and web services. It’s also referred to as an asynchronous receiver in the EIP world. An event-driven consumer listens on a particular messaging channel, such as a TCP/IP port, JMS queue, Twitter handle, Amazon SQS queue, WebSocket, and so on. It then waits for a client to send messages to it. When a message arrives, the consumer wakes up and takes the message for processing.
In contrast to the event-driven consumer, the polling consumer actively goes and fetches messages from a particular source, such as an FTP server. The polling consumer is also known as a synchronous receiver in EIP lingo, because it won’t poll for more messages until it’s finished processing the current message. A common flavor of the polling consumer is the scheduled polling consumer, which polls at scheduled intervals. File, FTP, and email components all use scheduled polling consumers.
| In the Camel components its only either the event driven or scheduled polling consumers that are in use. The polling consumer (non-scheduled) is only used to poll on-demand, such as when using the Poll Enrich EIP, or from Java by creating a |