Routebox Component
Available as of Camel 2.6
The routebox component enables the creation of specialized endpoints that offer encapsulation and a strategy based indirection service to a collection of camel routes hosted in an automatically created or user injected camel context.
Routebox endpoints are camel endpoints that may be invoked directly on camel routes. The routebox endpoint performs the following key functions
- encapsulation - acts as a blackbox, hosting a collection of camel routes stored in an inner camel context. The inner context is fully under the control of the routebox component and is JVM bound.
- strategy based indirection - direct payloads sent to the routebox endpoint along a camel route to specific inner routes based on a user defined internal routing strategy or a dispatch map.
- exchange propagation - forward exchanges modified by the routebox endpoint to the next segment of the camel route.
The routebox component supports both consumer and producer endpoints.
Producer endpoints are of two flavors
- Producers that send or dispatch incoming requests to a external routebox consumer endpoint
- Producers that directly invoke routes in an internal embedded camel context thereby not sending requests to an external consumer.
Maven users will need to add the following dependency to their pom.xml
for this component:
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-routebox</artifactId> <version>x.x.x</version> <!-- use the same version as your Camel core version --> </dependency>
The need for a Camel Routebox endpoint
The routebox component is designed to ease integration in complex environments needing
- a large collection of routes and
- involving a wide set of endpoint technologies needing integration in different ways
In such environments, it is often necessary to craft an integration solution by creating a sense of layering among camel routes effectively organizing them into
- Coarse grained or higher level routes - routes with Routebox endpoints that facade a collection of inner or lower level routes that are decomposed along
Business needs --> HR routes, Sales routes etc
Objectives --> Shipping routes, Fulfillment routes etc
Technologies --> Database routes, Caching routes, polling routes etc - Fine grained routes - routes that execute a specific business and/or integration pattern.
Requests sent to Routebox endpoints on coarse grained routes can then delegate requests to inner fine grained routes to achieve a specific integration objective, collect the final inner result, and continue to progress to the next step along the coarse-grained route.
URI format
routebox:routeboxname[?options]
You can append query options to the URI in the following format, ?option=value&option=value&...
Options
Name |
Default Value |
Description |
---|---|---|
|
|
A string representing a key in the Camel Registry matching an object value implementing the interface org.apache.camel.component.routebox.strategy.RouteboxDispatchStrategy |
|
|
A string representing a key in the Camel Registry matching an object value of the type HashMap<String, String>. The HashMap key should contain strings that can be matched against the value set for the exchange header ROUTE_DISPATCH_KEY. The HashMap value should contain inner route consumer URI's to which requests should be directed. |
|
|
A string representing a key in the Camel Registry matching an object value of the type org.apache.camel.CamelContext. If a CamelContext is not provided by the user a CamelContext is automatically created for deployment of inner routes. |
|
|
A string representing a key in the Camel Registry matching an object value that implements the interface org.apache.camel.spi.Registry. If Registry values are utilized by inner routes to create endpoints, an innerRegistry parameter must be provided |
|
|
A string representing a key in the Camel Registry matching an object value of the type List<org.apache.camel.builder.RouteBuilder>. If the user does not supply an innerContext pre-primed with inner routes, the routeBuilders option must be provided as a non-empty list of RouteBuilders containing inner routes |
|
|
The Protocol used internally by the Routebox component. Can be Direct or SEDA. The Routebox component currently offers protocols that are JVM bound. |
|
|
Dictates whether a Producer endpoint sends a request to an external routebox consumer. If the setting is false, the Producer creates an embedded inner context and processes requests internally. |
|
|
The Protocol used internally by the Routebox component. Can be Direct or SEDA. The Routebox component currently offers protocols that are JVM bound. |
|
|
Number of threads to be used by the routebox to receive requests. Setting applicable only for innerProtocol SEDA. |
|
|
Create a fixed size queue to receive requests. Setting applicable only for innerProtocol SEDA. |
Sending/Receiving Messages to/from the routebox
Before sending requests it is necessary to properly configure the routebox by loading the required URI parameters into the Registry as shown below. In the case of Spring, if the necessary beans are declared correctly, the registry is automatically populated by Camel.
Example 1: Loading inner route details into the Registry
@Override protected JndiRegistry createRegistry() throws Exception { JndiRegistry registry = new JndiRegistry(createJndiContext()); // Wire the routeDefinitions & dispatchStrategy to the outer camelContext where the routebox is declared List<RouteBuilder> routes = new ArrayList<RouteBuilder>(); routes.add(new SimpleRouteBuilder()); registry.bind("registry", createInnerRegistry()); registry.bind("routes", routes); // Wire a dispatch map to registry HashMap<String, String> map = new HashMap<String, String>(); map.put("addToCatalog", "seda:addToCatalog"); map.put("findBook", "seda:findBook"); registry.bind("map", map); return registry; } private JndiRegistry createInnerRegistry() throws Exception { JndiRegistry innerRegistry = new JndiRegistry(createJndiContext()); BookCatalog catalogBean = new BookCatalog(); innerRegistry.bind("library", catalogBean); return innerRegistry; } ... CamelContext context = new DefaultCamelContext(createRegistry());
When sending requests to the routebox, it is not necessary for producers do not need to know the inner route endpoint URI and they can simply invoke the Routebox URI endpoint with a dispatch strategy or dispatchMap as shown below
Example 2: Using a routebox producer
from("direct:sendToStrategyBasedRoutebox") .to("routebox:multipleRoutes?innerRegistry=#registry&routeBuilders=#routes&dispatchStrategy=#strategy") .to("log:Routes operation performed?showAll=true"); from ("direct:sendToMapBasedRoutebox") .to("routebox:multipleRoutes?innerRegistry=#registry&routeBuilders=#routes&dispatchMap=#map") .to("log:Routes operation performed?showAll=true");
Lucene Producers
This component supports 2 producer endpoints.
- insert - The insert producer builds a searchable index by analyzing the body in incoming exchanges and associating it with a token ("content").
- query - The query producer performs searches on a pre-created index. The query uses the searchable index to perform score & relevance based searches. Queries are sent via the incoming exchange contains a header property name called 'QUERY'. The value of the header property 'QUERY' is a Lucene Query. For more details on how to create Lucene Queries check out http://lucene.apache.org/java/3_0_0/queryparsersyntax.html
Lucene Processor
There is a processor called LuceneQueryProcessor available to perform queries against lucene without the need to create a producer.
Lucene Usage Samples
Example 1: Creating a Lucene index
RouteBuilder builder = new RouteBuilder() { public void configure() { from("direct:start"). to("lucene:whitespaceQuotesIndex:insert? analyzer=#whitespaceAnalyzer&indexDir=#whitespace&srcDir=#load_dir"). to("mock:result"); } };
Example 2: Loading properties into the JNDI registry in the Camel Context
@Override protected JndiRegistry createRegistry() throws Exception { JndiRegistry registry = new JndiRegistry(createJndiContext()); registry.bind("whitespace", new File("./whitespaceIndexDir")); registry.bind("load_dir", new File("src/test/resources/sources")); registry.bind("whitespaceAnalyzer", new WhitespaceAnalyzer()); return registry; } ... CamelContext context = new DefaultCamelContext(createRegistry());
Example 2: Performing searches using a Query Producer
RouteBuilder builder = new RouteBuilder() { public void configure() { from("direct:start"). setHeader("QUERY", constant("Seinfeld")). to("lucene:searchIndex:query? analyzer=#whitespaceAnalyzer&indexDir=#whitespace&maxHits=20"). to("direct:next"); from("direct:next").process(new Processor() { public void process(Exchange exchange) throws Exception { Hits hits = exchange.getIn().getBody(Hits.class); printResults(hits); } private void printResults(Hits hits) { LOG.debug("Number of hits: " + hits.getNumberOfHits()); for (int i = 0; i < hits.getNumberOfHits(); i++) { LOG.debug("Hit " + i + " Index Location:" + hits.getHit().get(i).getHitLocation()); LOG.debug("Hit " + i + " Score:" + hits.getHit().get(i).getScore()); LOG.debug("Hit " + i + " Data:" + hits.getHit().get(i).getData()); } } }).to("mock:searchResult"); } };
Example 3: Performing searches using a Query Processor
RouteBuilder builder = new RouteBuilder() { public void configure() { try { from("direct:start"). setHeader("QUERY", constant("Rodney Dangerfield")). process(new LuceneQueryProcessor("target/stdindexDir", analyzer, null, 20)). to("direct:next"); } catch (Exception e) { e.printStackTrace(); } from("direct:next").process(new Processor() { public void process(Exchange exchange) throws Exception { Hits hits = exchange.getIn().getBody(Hits.class); printResults(hits); } private void printResults(Hits hits) { LOG.debug("Number of hits: " + hits.getNumberOfHits()); for (int i = 0; i < hits.getNumberOfHits(); i++) { LOG.debug("Hit " + i + " Index Location:" + hits.getHit().get(i).getHitLocation()); LOG.debug("Hit " + i + " Score:" + hits.getHit().get(i).getScore()); LOG.debug("Hit " + i + " Data:" + hits.getHit().get(i).getData()); } } }).to("mock:searchResult"); } };