Sunday, September 13, 2015

Apache Camel - Simple Routing Example

This post is continuation of the previous post Apache Camel overview. In this post, we will see how to define a sample route using Apache Camel (with Spring Integration).

Dependencies

Apache Camel can work easily with Spring. The following dependencies are required to make Apache Camel to work with Spring.
  <dependency>
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-core</artifactId>
       <version>2.15.3</version>
  </dependency>
  <dependency>
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-spring</artifactId>
       <version>2.15.3</version>
  </dependency>
camel-core is the actual dependency and camel-spring is required for the spring integration.

Spring Configuration

To add camel to Spring Configuration, add the following

Namespace

xmlns:camel="http://camel.apache.org/schema/spring"

Schema Location

xsi:schemaLocation="http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd"

Combined Spring XML

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:camel="http://camel.apache.org/schema/spring"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://camel.apache.org/schema/spring 
              http://camel.apache.org/schema/spring/camel-spring.xsd">

</beans>         

Camel Context and Route

Camel context is the camel runtime. In Spring, we need to define the Camel Context to define the Route. Within the context, route must be defined.
Problem Statement: Read a file from a directory, process it and copy the processed file to a destination folder.

Define the Processor

package com.test.camel.processor;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SampleProcessor implements Processor
{
    private static final Logger LOG = LoggerFactory.getLogger(SampleProcessor.class);

    public void process(Exchange exchange) throws Exception
    {
        LOG.info("Input is "+exchange.getIn().getBody());
        //Processing goes here. Set the output to same as input. (Dummy Processing) 
        exchange.setOut(exchange.getIn());
    }

}

Points to be noted:

  • Processor is a class which implements org.apache.camel.Processor. 
  • Processor implements a method which takes only one argument (Exchange) - which consists of three messages (in, out and exception) and few other properties related to the route and it's camel context.

Define the Bean

     <bean id="processor" class="com.test.camel.processor.SampleProcessor" />

Define the Route

 <camel:camelContext id="camelContext">
      <camel:route id="file-route">
            <camel:from uri="file:/tmp/input.test" />
            <camel:process ref="processor" />
            <camel:to uri="file:/tmp/output.test" />
      </camel:route>
  </camel:camelContext>

Points to be noted:

  • Route is defined inside the Spring Config (using DSL). It also be defined using RouteBuilder. (We will concentrate only on DSL).
  • Define the route inside the Camel Context 
  • A very basic route consists of From (Where to fetch from), Processor (Which processor the input) and To (Where to write the processed input). 
  • Processor is optional - if we don't want to do any processing. 
  • Here in this route (file-route), files will be read from directory /tmp/input.test, and will be written into /tmp/output.test directory after processing.
  • Camel Context and Route(s) will be automatically started once the spring application context is loaded and started. So, once spring configuration file is loaded, camel looks for the files in the input directory. 
  • Camel Context and Route(s) will be shutdown once the application context is closed.

Exception Handling

Apache Camel provides try, catch and finally (optional) blocks to be defined within a route to handle the exceptions while routing or processing. The above route can be re-defined with try-catch blocks to check for Exception 
 <camel:camelContext id="camelContext">
      <camel:route id="file-route">
            <camel:from uri="file:/tmp/input.test" />
            <camel:doTry>
                 <camel:process ref="processor" />
                 <camel:to uri="file:/tmp/output.test" />
                 <camel:doCatch>
                      <camel:exception>java.lang.Exception</camel:exception>
                      <camel:log message="Exception while processing "></camel:log>
                      <camel:to uri="file:/tmp/error.test" />
                 </camel:doCatch>
            </camel:doTry>
      </camel:route>
  </camel:camelContext>
In the above case, if an exception is occurred while routing/processing, the exception will be caught, a log will be written and the file will be moved to another directory /tmp/output.test.

Full Spring Configuration

Complete spring configuration file is as below
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:camel="http://camel.apache.org/schema/spring" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://camel.apache.org/schema/spring 
           http://camel.apache.org/schema/spring/camel-spring.xsd">

     <bean id="processor" class="com.test.camel.processor.SampleProcessor" />

     <camel:camelContext id="camelContext">
         <camel:route id="file-route">
              <camel:from uri="file:/tmp/input.test" />
              <camel:doTry>
                   <camel:process ref="processor" />
                   <camel:to uri="file:/tmp/output.test" />
                   <camel:doCatch>
                        <camel:exception>java.io.IOException</camel:exception>
                        <camel:log message="Exception while processing "></camel:log>
                        <camel:to uri="file:/tmp/error.test" />
                   </camel:doCatch>
              </camel:doTry>
         </camel:route>
     </camel:camelContext>
</beans>
         
In the next post, we will see more details about routing. Happy Learning!!!!