Apache Camel: Basic Example
In this article, we’ll create a simple Apache Camel application that reads JSON files from a directory, processes them, and writes the result to a file.
Apache Camel is a framework for building message-based integration applications. It provides implementations of the Enterprise Integration Patterns, a set of patterns for solving common integration challenges. Apache Camel has many built-in components for interacting with systems or protocols e.g. HTTP, JMS, FTP, File, etc - Apache Camel components.
You can check out a complete example on GitHub: https://github.com/howardpaget/camel-basic-example.
Required Dependencies
We’ll need the following dependencies:
camel-spring-boot-starter
: simplifies getting Spring Boot and Apache Camel to work together.camel-jackson
: provides integration with Jackson for handling JSON.camel-test-spring-junit5
: simplifies testing of Apache Camel routes.
implementation 'org.apache.camel.springboot:camel-spring-boot-starter:4.0.0-M3'
implementation 'org.apache.camel:camel-jackson:4.0.0-M3'
testImplementation 'org.apache.camel:camel-test-spring-junit5:3.15.0'
Route Definition
In Apache Camel, a route is a path that messages take from an input component, through any processors, and out to an endpoint. Every route starts with an input source specified using from(uri)
where uri
is a string determining the type of endpoint and any options. The middle of the route contains a set of steps to process the message e.g. unmarshalling, transformation using a custom processor, etc. Optionally, a route can end with a to(uri)
to route the message to anythong endpoint.
from("file:numbers?move=archive/${file:name}-${date:now:yyyyMMddHHmmssSSS}.json&moveFailed=error/${file:name}-${date:now:yyyyMMddHHmmssSSS}.json")
.id("totalRoute")
.unmarshal().json(Numbers.class)
.process(totalProcessor)
.marshal().json()
.to("file:numbers/total?fileName=${file:name}-${date:now:yyyyMMddHHmmssSSS}.json");
The above route definition:
- Read files from the directory “numbers”.
move=archive/...
moveFailed=error/...
- Parses the file contents to an object called
Numbers
which looks like{ "numbers": [1,2,3] }
. - Calculates the total of the numbers.
- Serialises the total to JSON.
- Writes the file to the directory “numbers/total” appending the datetime to the file name.
Route Builder
The route Routes are created inside the configure
method of a RouteBuilder
.
@Component
public class TotalRoute extends RouteBuilder {
private final TotalProcessor totalProcessor;
public TotalRoute(TotalProcessor totalProcessor) {
this.totalProcessor = totalProcessor;
}
@Override
public void configure() {
// insert route definition here
}
}
Testing Routes using Mocked Endpoints
Apache Camel and JUnit5 make testing routes simple by providing a way to mock endpoints and make assertions about the messages received by the endpoints.
In the test below we:
- Use
AdviceWith.adviceWith
to replace the output endpoint with a mocked endpoint. - Send a message to the route via the injected
ProducerTemplate
. - Assert that the message processed message has the expected content.
@CamelSpringBootTest
@SpringBootTest
class TotalApplicationTests {
@Autowired
private CamelContext camelContext;
@Autowired
private ProducerTemplate template;
@EndpointInject("mock:file:numbers/total")
private MockEndpoint mock;
@BeforeEach
void setUp() throws Exception {
AdviceWith.adviceWith(camelContext, "totalRoute", AdviceWithRouteBuilder::mockEndpoints);
}
@Test
void numbers_in_body_are_totaled_and_sent_to_the_output_endpoint() throws Exception {
mock.expectedBodiesReceived("{\"total\":55}");
template.sendBody("file:numbers", "{\"numbers\": [1,2,3,4,5,6,7,8,9,10]}");
mock.assertIsSatisfied();
}
}