[[DynamicRouter-DynamicRouter]]
== Dynamic Router

The
http://www.enterpriseintegrationpatterns.com/DynamicRouter.html[Dynamic
Router] from the link:enterprise-integration-patterns.html[EIP patterns]
allows you to route messages while avoiding the dependency of the router
on all possible destinations while maintaining its efficiency.

image:http://www.enterpriseintegrationpatterns.com/img/DynamicRouter.gif[image]

In *Camel 2.5* we introduced a `dynamicRouter` in the DSL which is like
a dynamic link:routing-slip.html[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 link:expression.html[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` |*Camel 2.13.1/2.12.4:* 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

From Camel 2.5 the link:dynamic-router.html[Dynamic Router] will set a
property (Exchange.SLIP_ENDPOINT) on the link:exchange.html[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 link:dynamic-router.html[Dynamic Router] implementation is
based on top of link:routing-slip.html[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 link:bean.html[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 link:exchange.html[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
link:exchange.html[Exchange] are. Although there was a bug in the method
call expression, see the warning below.

WARNING:*Using beans to store state*
Mind that in Camel 2.9.2 or older, when using a link:bean.html[Bean] the
state is not propagated, so you will have to use a
link:processor.html[Processor] instead. This is fixed in Camel 2.9.3
onwards.

[[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, for example the Camel
2.4 example below could be written as follows. 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 link:routing-slip.html[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
link:parameter-binding-annotations.html[Parameter Binding Annotations]
to bind different parts of the link:message.html[Message] to method
parameters or use an link:expression.html[Expression] such as using
link:xpath.html[XPath] or link:xquery.html[XQuery].

The method can be invoked in a number of ways as described in the
link:bean-integration.html[Bean Integration] such as

* link:pojo-producing.html[POJO Producing]
* link:spring-remoting.html[Spring Remoting]
* link:bean.html[Bean] component

