[[camel]]
= Apache Camel Support

Spring Integration provides an API and configuration to communicate with https://camel.apache.org[Apache Camel] endpoints declared in the same application context.

You need to include this dependency into your project:

[tabs]
======
Maven::
+
[source, xml, subs="normal", role="primary"]
----
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-camel</artifactId>
    <version>{project-version}</version>
</dependency>
----

Gradle::
+
[source, groovy, subs="normal", role="secondary"]
----
compile "org.springframework.integration:spring-integration-camel:{project-version}"
----
======

Spring Integration and Apache Camel implement Enterprise Integration Patterns and provide a convenient way to compose them, but the projects use a different approach for their API and abstractions implementation.
Spring Integration fully relies on a dependency injection container from Spring Core.
It uses many other Spring projects (Spring Data, Spring AMQP, Spring for Apache Kafka etc.) for its channel adapter implementations.
It also uses the `MessageChannel` abstraction as a first class citizen of which developers need to be aware of, when composing their integration flows.
Apache Camel, on the other hand, does not provide a first class citizen abstraction of a message channel and proposes to compose its routes via internal exchanges, hidden from the API.
In addition, it requires some extra https://camel.apache.org/components/3.18.x/spring-summary.html[dependencies and configurations] for it to be used in a Spring application.

Even if it doesn't matter for the final enterprise integration solution how its parts are implemented, a developer experience and high productivity are taken into account.
Therefore, developers may choose one framework over another for many reasons, or both if there is a gap in some target systems support.
Spring Integration and Apache Camel applications can interact with each other through many external protocols for which they implement channel adapters.
For example, a Spring Integration flow may publish a record to an Apache Kafka topic which is consumed by an Apache Camel endpoint on the consumer side.
Or, an Apache Camel route may write data into an SFTP file the directory, which is polled by a SFTP Inbound Channel Adapter from Spring Integration.
Or, within the same Spring application context they can communicate via an `ApplicationEvent` https://camel.apache.org/components/3.18.x/spring-event-component.html[abstraction].

To make a development process easier, and to avoid unnecessary network hops, Apache Camel provides a https://camel.apache.org/components/3.18.x/spring-integration-component.html[module] to communicate with Spring Integration via message channels.
All that is needed is a reference to a `MessageChannel` from the application context, to send or consume messages.
This works well when Apache Camel routes are initiators of the message flow and Spring Integration plays only a supporting role as a part of the solution.

For a similar developer experience, Spring Integration now provides a channel adapter to call an Apache Camel endpoint and, optionally, wait for a reply.
There is no inbound channel adapter because subscribing to a `MessageChannel` for consuming Apache Camel messages is enough from the Spring Integration API and abstractions perspective.

[[camel-channel-adapter]]
== Outbound Channel Adapter for Apache Camel

The `CamelMessageHandler` is an `AbstractReplyProducingMessageHandler` implementation and can work in both one-way (default) and request-reply modes.
It uses an `org.apache.camel.ProducerTemplate` to send (or send and receive) into an `org.apache.camel.Endpoint`.
An interaction mode can be controlled by the `ExchangePattern` option (which can be evaluated at runtime against the request message via a SpEL expression).
The target Apache Camel endpoint can be configured explicitly or as a SpEL expression to be evaluated at runtime.
Otherwise, it falls back to the `defaultEndpoint` provided on the `ProducerTemplate`.
Instead of specifying the endpoint, an in-line, explicit `LambdaRouteBuilder` can be provided, for example to make a call into an Apache Camel component for which there is no channel adapter support in Spring Integration.

In addition, a `HeaderMapper<org.apache.camel.Message>` (the `CamelHeaderMapper` is a default implementation) can be provided, to determine which headers to map between the Spring Integration and Apache Camel messages.
By default, all headers are mapped.

The `CamelMessageHandler` supports an `async` mode calling `ProducerTemplate.asyncSend()` and producing a `CompletableFuture` for reply processing (if any).

The `exchangeProperties` can be customized via a SpEL expression, which must evaluate to a `Map`.

If a `ProducerTemplate` is not provided, it is created via a `CamelContext` bean resolved from the application context.

[source, java]
----
@Bean
@ServiceActivator(inputChannel = "sendToCamel")
CamelMessageHandler camelService(ProducerTemplate producerTemplate) {
    CamelHeaderMapper headerMapper = new CamelHeaderMapper();
    headerMapper.setOutboundHeaderNames("");
    headerMapper.setInboundHeaderNames("testHeader");

    CamelMessageHandler camelMessageHandler = new CamelMessageHandler(producerTemplate);
    camelMessageHandler.setEndpointUri("direct:simple");
    camelMessageHandler.setExchangePatternExpression(spelExpressionParser.parseExpression("headers.exchangePattern"));
    camelMessageHandler.setHeaderMapper(headerMapper);
    return camelMessageHandler;
}
----

For Java DSL flow definitions this channel adapter can be configured with a few variants provided by the `Camel` factory:

[source, java]
----
@Bean
IntegrationFlow camelFlow() {
    return f -> f
            .handle(Camel.gateway().endpointUri("direct:simple"))
            .handle(Camel.route(this::camelRoute))
            .handle(Camel.handler().endpointUri("log:com.mycompany.order?level=WARN"));
}

private void camelRoute(RouteBuilder routeBuilder) {
    routeBuilder.from("direct:inbound").transform(routeBuilder.simple("${body.toUpperCase()}"));
}
----
