July 1, 2010

Getting Started with Apache Camel and Prepare for Apache ServiceMix Deployment

Apache Camel is dream framework for any developers that is confronting with any type of integration task. What makes Apache Camel so great is:
  • Testability. It is design from the beginning to be a framework that going to support Test Driven Development. With this follows a fast development cycle, since all code can be debugged and executed from a simple JUnit test case.
  • Solves the two foremost problem that an integrator faces:
  • Seamless protocol crossing, i.e. no coding for fetching data from e.g. HTTP and forwarding it to JMS.
  • Default implementation of Enterprise Integration Pattern (http://www.eaipatterns.com/toc.html) that is easy to extend and configure. If you are not familiar with EIP, I recommend you to take the time and read the EIP homepage or if you do not want to miss a thing read the complete book written by Hophe and Woolf (http://www.amazon.com/Enterprise-Integration-Patterns-Designing-Deploying/dp/0321200683).

The next best thing is that Apache Camel is a POJO based solution, which means that it can be deployed and ran in any deployment environment:
  • Standalone Java Application
  • Web Container
  • J2EE Container

When talking of deployment and integration the most common question is. What about ESB? And this is also when Apache Camel shines. Apache Camel is fully supported by Apache Camel parent project Apache ServiceMix, that supports the industry standard Java Business Integration standard. The JBI specification has been criticized about being a slow way of developing integration software and in many aspect that is true, but with Apache Camel as core developing framework that is no longer true.

The reason to select an ESB platform to deploy your integration software is:
  • Management. The ESB platform is specially design to manage integration programs.
  • Redundancy and Scalability. A good ESB platform is specifically design to handle these issues when the load and uptime requirements increases.

But one thing, that in my opinion, the Apache Camel homepage lack is good starting example of showing the above strength. So lets get started with NOT writing a production code example, but instead lets write a JUnit test case that you can debug, then you can continue of writing your production code.

In the below example I will also take into account that one day, you might want or NOT take the next step and move your Apache Camel code into a full blown ESB environment.

Lets first look at your Maven pom.xml.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>se.msc.example</groupId>
 <artifactId>camel</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>
 <!-- <packaging>jbi-service-unit</packaging> -->
 <name>MSC Example :: Camel</name>
 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <servicemix-version>4.2.0</servicemix-version>
  <!--
   servicemix 4.2.0 ships with 'servicemix-camel', thats support camel
   2.2.0
  -->
  <camel-version>2.2.0</camel-version>
  <!--
   'servicemix-camel' has a deviating version compared with 'camel-core'
  -->
  <servicemix-camel-version>2010.01</servicemix-camel-version>
  <!-- supported version for tooling in servicemix 4.2.0 -->
  <servicemix-jbi-plugin-version>4.3</servicemix-jbi-plugin-version>
 </properties>
 <build>
  <pluginManagement>
   <plugins>
    <!-- to compile with JDK 1.6 -->
    <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-compiler-plugin</artifactId>
     <!--
      Use version
      $M2_HOME/lib/maven-<version>-uber.jar/org/apache/maven/project/pom-4.0.0.xml
     -->
     <configuration>
      <source>1.6</source>
      <target>1.6</target>
      <!-- Plugin ignores default value 'project.build.sourceEncoding' -->
      <encoding>${project.build.sourceEncoding}</encoding>
     </configuration>
    </plugin>
    <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-jar-plugin</artifactId>
     <!--
      Use version
      $M2_HOME/lib/maven-<version>-uber.jar/org/apache/maven/project/pom-4.0.0.xml
     -->
     <configuration>
      <archive>
       <manifest>
        <!-- To include versionnumber in MANIFEST.MF -->
        <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
       </manifest>
      </archive>
     </configuration>
    </plugin>
   </plugins>
  </pluginManagement>
  <plugins>
   <!--
    creates the JBI deployment unit <plugin>
    <groupId>org.apache.servicemix.tooling</groupId>
    <artifactId>jbi-maven-plugin</artifactId>
    <version>${servicemix-jbi-plugin-version}</version>
    <extensions>true</extensions> </plugin>
   -->
  </plugins>
 </build>
 <dependencies>
  <!-- servicemix camel core -->
  <dependency>
   <groupId>org.apache.servicemix</groupId>
   <artifactId>servicemix-camel</artifactId>
   <version>${servicemix-camel-version}</version>
   <scope>provided</scope>
  </dependency>
  <!-- optional camel components -->
  <dependency>
   <groupId>org.apache.camel</groupId>
   <artifactId>camel-http</artifactId>
   <version>${camel-version}</version>
  </dependency>
  <!-- test support -->
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <!-- version inherited from 'camel-core' -->
   <version>3.8.2</version>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>org.apache.camel</groupId>
   <artifactId>camel-core</artifactId>
   <version>${camel-version}</version>
   <type>test-jar</type>
   <scope>test</scope>
  </dependency>
 </dependencies>
</project>


package se.msc.example.camel;

import org.apache.camel.ContextTestSupport;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;

public class MyFirstCamelTest extends ContextTestSupport {

 @Override
 protected RouteBuilder createRouteBuilder() {
  return new RouteBuilder() {
   public void configure() {
    from("direct:start").to("file:///tmp?fileName=foo.txt").to("mock:result");
    // another example, without mocking start endpoint
    // from("http://camel.apache.org/http.html").to("file:///tmp?fileName=foo.txt").to("mock:result");
   }
  };
 }

 public void test_OK() throws Exception {
  MockEndpoint result = resolveMandatoryEndpoint("mock:result", MockEndpoint.class);
  result.expectedMessageCount(1);
  // send somtething from 'direct:start'
  String ls = System.getProperty("line.separator");
  String txt = "Dummy Body åäö";
  template.sendBody("direct:start", txt + ls + txt + ls + txt + ls);
  // execute and assert above 'result.expectedMessageCount(1);'
  result.assertIsSatisfied();
 }

}


To read more about all configuration options for the above endpoints, see http://camel.apache.org/components.html

An Apache Camel route can also be configured in a XML file, which is the natural choice since you want  things to configurable and not static defined in a Java class, but more about in my next blog.

No comments: