Using components (Simple)
As of this writing Camel has around 150 components with support for many protocols and technologies. The full list of components is available at http://camel.apache.org/components.html with links to each component's details page where all the configuration options are explained. A component represents an adapter for a specific API and allows Camel to exchange messages with external applications. The following diagram depicts how components enable external applications sending data to a messaging channel using components' endpoints and also receive data from it:
In this tutorial, we will demonstrate how to leverage Camel components by creating an HTTP endpoint, and calling external services with the Jetty component.
Getting ready
The complete source code for this tutorial is located under the project camel-message-routing-examples/using-components
.
How to do it...
Camel-core contains a dozen components which are always available with Camel. These include bean
, direct
, vm
, file
, log
, mock
, seda
, timer
, xslt
, and a few more. All of the other components used for routing have to be retrieved and added additionally to the classpath.
In this tutorial, we will use the jetty component, so the following camel-jetty dependency will be needed:
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jetty</artifactId> <version>${camel-version}</version> </dependency>
Next, we will create a route with Jetty consumer and log the messages using log component. Finally, we use a Jetty producer to make external HTTP calls to Google.
from("jetty:http://localhost:8181?matchOnUriPrefix=true") .to("log://org.apache.camel.howto?showAll=true") .to("jetty:http://www.google.co.uk?bridgeEndpoint=true&throwExceptionOnFailure=false");
When this route is started, it will start a Jetty web server listening on localhost port 8080
. If we use a web browser and try to access http://localhost:8080
, the route will log the request, make an HTTP call to http://www.google.co.uk, and return the result to the requestor. And, what we should see in our browser (if all works fine) is Google's home page. So this route is in fact an HTTP proxy that logs all requests.
How it works...
Routes in Camel consist of EIPs and components. EIPs transform the messages inside the routes, whereas components usually allow messages to reach external systems. Components can be added to Camel runtime (CamelContext
) in two ways. The less popular way is manually instantiating a component and adding it to the context:
camelContext.addComponent("jetty", new JettyHttpComponent());
The second way of adding components to Camel runtime is through the auto-discovery mechanism. In this mode, when a component is needed as part of the routing process and it is not available to CamelContext
, Camel will scan the classpath and look at META-INF/services/org/apache/camel/component
for a file matching the component name. The jetty component's file META-INF/services/org/apache/camel/component/jetty
contains the following:
class=org.apache.camel.component.jetty.JettyHttpComponent
The content of the file shows the actual component class, so that Camel can instantiate it, and add it to CamelContext
. A component is in essence an endpoint factory, it creates endpoints based on URLs. The Endpoint
interface models the end of channel through which systems can send and receive messages. Camel endpoints are usually referenced using URLs. URLs provide a unified way for describing endpoints for various systems. The Camel URL has the following structure: schema:context path:options
. For example, the Jetty URL from the previous route looks like:
jetty://http://www.google.co.uk?bridgeEndpoint=true&throwExceptionOnFailure=false
Its schema is jetty, which tells Camel what is the component class name, that the context path is http://www.google.co.uk and it has two options bridgeEndpoint=true&throwExceptionOnFailure=false
. The context path is endpoint specific; it means different things for different endpoints. For example, the context path of the log endpoint used above org.apache.camel.howto
represents the logging category, whereas in Jetty it is the host and port name. Options are also endpoint specific, and each endpoint has different options for the underlying technology. Once an endpoint is instantiated for a specific URL, then it is responsible for creating consumers and producers.
At a very high level, the process of using a component in a Camel route goes through the following steps: when a URI is used in a route, based on the URI schema, a component is instantiated. The component uses the context path and the options to create an endpoint. Then the endpoint creates a consumer or producer depending on what is needed in the route. When the consumer receives a message from the external system, it transforms the message to an exchange and starts routing it in Camel. The producer, on the other hand, receives an exchange as part of the routing, and delivers it to the external system using the external API.
There's more...
We saw how to pass primitive types and string literals as Endpoint
options. Next, we will see how Camel offers a unified access to the environment it is running on, and how to pass complex objects from its environment as options in the URLs.
Accessing the Registry
Camel Registry provides a unified interface for accessing Java beans on the runtime environment. There are different Registry
implementations and depending on our DSL choice, one is always in use. If we use the Java DSL, by default the Registry
will be JndiRegistry
. This Registry
uses Java Naming and Directory Interface (JNDI) to lookup beans. There is also a simpler Map based Registry
available to use with Java DSL. With SimpleRegistry
, we can manually add bean instances to make them available during routing:
SimpleRegistry registry = new SimpleRegistry(); registry.put("myHttpClient", new HttpClient()); CamelContext context = new DefaultCamelContext(registry);
Once a bean is available in the Registry
, we can pass it as an option to an endpoint by prefixing its key with #
. For example, the Jetty producer has an option called httpClient
for setting a custom HttpClient
, and we can pass our instance from the SimpleRegistry
, as shown in the following code:
.to("jetty:http://www.google.co.uk?bridgeEndpoint=true&httpClient=#myHttpClient");
Options are usually fields on the concrete Endpoint
implementation, and to set the httpClient
field of JettyHttpEndpoint
, Camel will look up the Registry
using myHttpClient
as the key.
When Spring XML DSL is used, the Registry
implementation is provided by the ApplicationContextRegistry
class, which gives access to the beans from the Spring ApplicationContext
. So, if we have a Spring bean declaration like the following line of code, we can access it as Endpoint
options with the same syntax as the previous #myHttpClient
:
<bean id="myHttpClient" class="org.eclipse.jetty.client.HttpClient"/>
There is also an OsgiServiceRegistry
implementation used when running Camel in the OSGI container and giving access to the beans from the OSGI service registry.