Howard Paget
Projects
About

Apache Camel: Basic Example

Jul 02, 2023
apache-camel java

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:

  1. Read files from the directory “numbers”.
    • move=archive/...
    • moveFailed=error/...
  2. Parses the file contents to an object called Numbers which looks like { "numbers": [1,2,3] }.
  3. Calculates the total of the numbers.
  4. Serialises the total to JSON.
  5. 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();
  }
}