| [[DynamicRouter-DynamicRouter]] |
| = Dynamic Router |
| :page-source: core/camel-core-engine/src/main/docs/eips/dynamic-router.adoc |
| |
| The |
| http://www.enterpriseintegrationpatterns.com/DynamicRouter.html[Dynamic |
| Router] from the EIP patterns |
| allows you to route messages while avoiding the dependency of the router |
| on all possible destinations while maintaining its efficiency. |
| |
| image::eip/DynamicRouter.gif[image] |
| |
| The `dynamicRouter` in the DSL is similar to |
| a dynamic Routing Slip which evaluates the slip |
| _on-the-fly_. |
| |
| WARNING: *Beware* |
| You must ensure the expression used for the `dynamicRouter` such as a |
| bean, will return `null` to indicate the end. Otherwise the |
| `dynamicRouter` will keep repeating endlessly. |
| |
| [[DynamicRouter-Options]] |
| == Options |
| |
| [width="100%",cols="10%,10%,80%",options="header",] |
| |======================================================================= |
| |Name |Default Value |Description |
| |
| |`uriDelimiter` |`,` |Delimiter used if the Expression returned multiple |
| endpoints. |
| |
| |`ignoreInvalidEndpoints` |`false` |If an endpoint uri could not be resolved, should it be ignored. |
| Otherwise Camel will thrown an exception stating the endpoint uri is not |
| valid. |
| |
| |`cacheSize` |`1000` |Allows to configure the cache size for the |
| `ProducerCache` which caches producers for reuse in the routing slip. |
| Will by default use the default cache size which is 1000. Setting the |
| value to -1 allows to turn off the cache all together. |
| |======================================================================= |
| |
| [[DynamicRouter-DynamicRouterinCamel2.5onwards]] |
| == Dynamic Router in Camel 2.5 onwards |
| |
| The Dynamic Router will set a |
| property (Exchange.SLIP_ENDPOINT) on the Exchange |
| which contains the current endpoint as it advanced though the slip. This |
| allows you to know how far we have processed in the slip. (It's a slip |
| because the Dynamic Router implementation is |
| based on top of Routing Slip). |
| |
| [[DynamicRouter-JavaDSL]] |
| == Java DSL |
| |
| In Java DSL you can use the `dynamicRouter` as shown below: |
| |
| [source,java] |
| ---- |
| from("direct:start") |
| // use a bean as the dynamic router |
| .dynamicRouter(method(DynamicRouterTest.class, "slip")); |
| ---- |
| |
| Which will leverage a xref:components::bean-component.adoc[Bean] to compute the slip |
| _on-the-fly_, which could be implemented as follows: |
| |
| [source,java] |
| ---- |
| /** |
| * Use this method to compute dynamic where we should route next. |
| * |
| * @param body the message body |
| * @return endpoints to go, or <tt>null</tt> to indicate the end |
| */ |
| public String slip(String body) { |
| bodies.add(body); |
| invoked++; |
| |
| if (invoked == 1) { |
| return "mock:a"; |
| } else if (invoked == 2) { |
| return "mock:b,mock:c"; |
| } else if (invoked == 3) { |
| return "direct:foo"; |
| } else if (invoked == 4) { |
| return "mock:result"; |
| } |
| |
| // no more so return null |
| return null; |
| } |
| ---- |
| |
| Mind that this example is only for show and tell. The current |
| implementation is not thread safe. You would have to store the state on |
| the Exchange, to ensure thread safety, as shown |
| below: |
| |
| [source,java] |
| ---- |
| /** |
| * Use this method to compute dynamic where we should route next. |
| * |
| * @param body the message body |
| * @param properties the exchange properties where we can store state between invocations |
| * @return endpoints to go, or <tt>null</tt> to indicate the end |
| */ |
| public String slip(String body, @Properties Map<String, Object> properties) { |
| bodies.add(body); |
| |
| // get the state from the exchange properties and keep track how many times |
| // we have been invoked |
| int invoked = 0; |
| Object current = properties.get("invoked"); |
| if (current != null) { |
| invoked = Integer.valueOf(current.toString()); |
| } |
| invoked++; |
| // and store the state back on the properties |
| properties.put("invoked", invoked); |
| |
| if (invoked == 1) { |
| return "mock:a"; |
| } else if (invoked == 2) { |
| return "mock:b,mock:c"; |
| } else if (invoked == 3) { |
| return "direct:foo"; |
| } else if (invoked == 4) { |
| return "mock:result"; |
| } |
| |
| // no more so return null |
| return null; |
| } |
| ---- |
| |
| You could also store state as message headers, but they are not |
| guaranteed to be preserved during routing, where as properties on the |
| Exchange are. Although there was a bug in the method |
| call expression, see the warning below. |
| |
| [[DynamicRouter-SpringXML]] |
| == Spring XML |
| |
| The same example in Spring XML would be: |
| |
| [source,xml] |
| ---- |
| <bean id="mySlip" class="org.apache.camel.processor.DynamicRouterTest"/> |
| |
| <camelContext xmlns="http://camel.apache.org/schema/spring"> |
| <route> |
| <from uri="direct:start"/> |
| <dynamicRouter> |
| <!-- use a method call on a bean as dynamic router --> |
| <method ref="mySlip" method="slip"/> |
| </dynamicRouter> |
| </route> |
| |
| <route> |
| <from uri="direct:foo"/> |
| <transform><constant>Bye World</constant></transform> |
| </route> |
| |
| </camelContext> |
| ---- |
| |
| [[DynamicRouter-DynamicRouterannotation]] |
| == @DynamicRouter annotation |
| |
| You can also use the `@DynamicRouter` annotation. The `route` method would |
| then be invoked repeatedly as the message is processed dynamically. The |
| idea is to return the next endpoint uri where to go. Return `null` to |
| indicate the end. You can return multiple endpoints if you like, just as |
| the Routing Slip, where each endpoint is |
| separated by a delimiter. |
| |
| [source,java] |
| ---- |
| public class MyDynamicRouter { |
| |
| @Consume(uri = "activemq:foo") |
| @DynamicRouter |
| public String route(@XPath("/customer/id") String customerId, @Header("Location") String location, Document body) { |
| // query a database to find the best match of the endpoint based on the input parameteres |
| // return the next endpoint uri, where to go. Return null to indicate the end. |
| } |
| } |
| ---- |
| |
| In the above we can use the |
| Parameter Binding Annotations |
| to bind different parts of the Message to method |
| parameters or use an Expression such as using |
| xref:components::xpath-language.adoc[XPath] or xref:components::xpath-language.adoc[XQuery]. |
| |
| The method can be invoked in a number of ways as described in the |
| Bean Integration such as |
| |
| * POJO Producing |
| * Spring Remoting |
| * xref:components::bean-component.adoc[Bean] component |
| |