| [[toD-eip]] |
| = To D EIP |
| :page-source: core/camel-core-engine/src/main/docs/eips/toD-eip.adoc |
| |
| There is a new `.toD` / `<toD>` that allows to send a message to a dynamic |
| computed xref:endpoint.adoc[Endpoint] using one or |
| more xref:expression.adoc[Expression] that are concat together. By |
| default the xref:simple-language.adoc[Simple] language is used to compute |
| the endpoint. |
| |
| == Options |
| |
| // eip options: START |
| The To D EIP supports 5 options which are listed below: |
| |
| [width="100%",cols="2,5,^1,2",options="header"] |
| |=== |
| | Name | Description | Default | Type |
| | *uri* | *Required* The uri of the endpoint to send to. The uri can be dynamic computed using the org.apache.camel.language.simple.SimpleLanguage expression. | | String |
| | *pattern* | Sets the optional ExchangePattern used to invoke this endpoint | | ExchangePattern |
| | *cacheSize* | Sets the maximum size used by the org.apache.camel.spi.ConsumerCache which is used to cache and reuse producers. | | Integer |
| | *ignoreInvalidEndpoint* | Ignore the invalidate endpoint exception when try to create a producer with that endpoint | false | Boolean |
| | *allowOptimisedComponents* | Whether to allow components to optimise toD if they are org.apache.camel.spi.SendDynamicAware. | true | Boolean |
| |=== |
| // eip options: END |
| |
| == Samples |
| |
| For example to send a message to a endpoint defined by a |
| header you can do as shown below: |
| |
| [source,java] |
| ---- |
| from("direct:start") |
| .toD("${header.foo}"); |
| ---- |
| |
| And in XML: |
| |
| [source,xml] |
| ---- |
| <route> |
| <from uri="direct:start"/> |
| <toD uri="${header.foo}"/> |
| </route> |
| ---- |
| |
| You can also prefix the uri with a value because by default the uri is |
| evaluated using the xref:simple-language.adoc[Simple] language |
| |
| [source,java] |
| ---- |
| from("direct:start") |
| .toD("mock:${header.foo}"); |
| ---- |
| |
| And in XML: |
| |
| [source,xml] |
| ---- |
| <route> |
| <from uri="direct:start"/> |
| <toD uri="mock:${header.foo"/> |
| </route> |
| ---- |
| |
| In the example above we compute an endpoint that has prefix "mock:" and |
| then the header foo is appended. So for example if the header foo has |
| value order, then the endpoint is computed as "mock:order". |
| |
| You can also use other languages than xref:simple-language.adoc[Simple] such |
| as xref:components::xpath-language.adoc[XPath] - this requires to prefix with language: as |
| shown below (simple language is the default language). If you do not |
| specify language: then the endpoint is a component name. And in some |
| cases there is both a component and language with the same name such as |
| xquery. |
| |
| [source,xml] |
| ---- |
| <route> |
| <from uri="direct:start"/> |
| <toD uri="language:xpath:/order/@uri"/> |
| </route> |
| ---- |
| |
| This is done by specifying the name of the language followed by a colon. |
| |
| [source,java] |
| ---- |
| from("direct:start") |
| .toD("language:xpath:/order/@uri"); |
| ---- |
| |
| You can also concat multiple xref:components::language-component.adoc[Language](s) together |
| using the plus sign `+` such as shown below: |
| |
| [source,xml] |
| ---- |
| <route> |
| <from uri="direct:start"/> |
| <toD uri="jms:${header.base}+language:xpath:/order/@id"/> |
| </route> |
| ---- |
| |
| In the example above the uri is a combination |
| of xref:simple-language.adoc[Simple] language and xref:simple-language.adoc[XPath] where |
| the first part is simple (simple is default language). And then the plus |
| sign separate to another language, where we specify the language name |
| followed by a colon |
| |
| [source,java] |
| ---- |
| from("direct:start") |
| .toD("jms:${header.base}+language:xpath:/order/@id"); |
| ---- |
| |
| You can concat as many languages as you want, just separate them with |
| the plus sign |
| |
| == Avoid creating endless dynamic endpoints which takes up resources |
| |
| When using dynamic computed endpoints with `toD` then you may compute a lot of dynamic endpoints, |
| which results in an overhead of resources in use, by each dynamic endpoint uri, and its associated producer. |
| |
| For example HTTP based endpoints where you may have dynamic values in URI parameters when calling the HTTP service, such as: |
| |
| [source,java] |
| ---- |
| from("direct:login") |
| .toD("http:myloginserver:8080/login?userid=${header.userName}"); |
| ---- |
| |
| In the example above then the parameter `userid` is dynamic computed, and would result in one instance of endpoint and producer |
| for each different userid. To avoid having too many dynamic endpoints you can configure `toD` to reduce its cache size, for example: |
| |
| [source,java] |
| ---- |
| from("direct:login") |
| .toD("http:myloginserver:8080/login?cacheSize=10&userid=${header.userName}"); |
| ---- |
| |
| where the cache is 10. *Important* this will only reduce the endpoint cache of the `toD` that has a chance |
| of being reused in case a message is routed with the same `userName` header. Therefore reducing the cache size |
| will not solve the _endless dynamic endoints_ problem. Instead you should use static endpoints with `to` and |
| provide the dynamic parts in Camel message headers (if possible). |
| |
| === Using static endpoints |
| |
| In the example above then the parameter `userid` is dynamic computed, and would result in one instance of endpoint and producer |
| for each different userid. To avoid having too dynamic endpoints you use a single static endpoint and use headers to provide the dynamic parts: |
| |
| [source,java] |
| ---- |
| from("direct:login") |
| .setHeader(Exchange.HTTP_PATH, constant("/login")) |
| .setHeader(Exchange.HTTP_QUERY, simple("userid=${header.userName}")) |
| .toD("http:myloginserver:8080"); |
| ---- |
| |
| However, you can use its optimised components for `toD` that can _solve_ this out of the box, |
| as documented next. |
| |
| == Using optimised components |
| |
| But a better solution would be if the HTTP component could be optimised to handle the variations of dynamic computed endpoint uris. |
| This is with the following components, which have been optimised for `toD`: |
| |
| - camel-http |
| - camel-jetty |
| - camel-netty-http |
| - camel-undertow |
| |
| For the optimisation to work, then: |
| |
| 1. The optimisation is detected and activated during startup of the Camel routes with `toD`'s. |
| 2. The dynamic uri in `toD` must provide the component name as either static or resolved via property placeholders. |
| 3. The supported components must be on the classpath. |
| |
| The HTTP based components will be optimised to use the same hostname:port for each endpoint, and the dynamic values |
| for context-path and query parameters will be provided as headers: |
| |
| For example this route: |
| |
| [source,java] |
| ---- |
| from("direct:login") |
| .toD("http:myloginserver:8080/login?userid=${header.userName}"); |
| ---- |
| |
| will essentially be optimised to (pseudo route): |
| |
| [source,java] |
| ---- |
| from("direct:login") |
| .setHeader(Exchange.HTTP_PATH, expression("/login")) |
| .setHeader(Exchange.HTTP_QUERY, expression("userid=${header.userName}")) |
| .toD("http:myloginserver:8080") |
| .removeHeader(Exchange.HTTP_PATH) |
| .removeHeader(Exchange.HTTP_QUERY); |
| ---- |
| |
| Where _expression_ will be evaluated dynamically. Notice how the uri in `toD` is now static (`\http:myloginserver:8080`). |
| This optimisation allows Camel to reuse the same endpoint and its associated producer for all dynamic variations. |
| This yields much lower resource overhead as the same http producer will be used for all the different variations of userid's. |
| |
| NOTE: When the optimised component is in use, then you cannot use the headers `Exchange.HTTP_PATH` and `Exchange.HTTP_QUERY` |
| to provide dynamic values to override the uri in `toD`. If you want to use these headers, then use the plain `to` DSL instead. |
| In other words these headers are used internally by `toD` to carry the dynamic details of the endpoint. |
| |
| In case of problems then you can turn on DEBUG logging level on `org.apache.camel.processor.SendDynamicProcessor` which will log |
| during startup if `toD` was optimised, or if there was a failure loading the optimised component, with a stacktrace logged. |
| |
| [source,text] |
| ---- |
| Detected SendDynamicAware component: http optimising toD: http:myloginserver:8080/login?userid=${header.userName} |
| ---- |
| |
| |