Nesse artigo vamos explorar o framework Apache Camel, abordando um pouco da sua história, uma visão geral do seu propósito e um exemplo do que ele é capaz.

O Apache Camel é um framework de integração baseado em padrões empresariais de integração (EIP). Traduzindo em termos simples, ele pretende simplificar a integração entre sistemas. O fato de ser baseado em padrões é o que o torna uma das melhores opções do mercado. Padrões, como sabemos, representam as melhores práticas ou a melhor forma de se fazer alguma coisa. Padrões também facilitam a comunicação entre as pessoas e, além disso, são reaproveitáveis, trazendo maior produtividade e diminuindo o custo de propriedade.

Independente de todo esse discurso empresarial chato, desenvolver com Apache Camel pode ser extremamente divertido. Com poucas linhas de código ou configuração, podemos processar arquivos, processá-los em paralelo, invocar Web Services, publicar eventos em uma fila JMS e muito mais.

Criado em 2007 por James Strachan, o Apache Camel já tem cinco anos de idade e está crescendo firme e forte. Hoje ele é parte de produtos como Apache ServiceMix, Fuse ESB e Jboss Application Server. Esse framework é adaptável a diversas situações pois sua arquitetura permite que você utilize apenas os componentes necessários para o seu projeto. Além disso, o Apache Camel tem um suporte fantástico para construção de testes unitários e mocks.

Livro clássico sobre EIP escrito por Gregor Hohpe e Bobby Woolf

Figura 1: Livro clássico sobre EIP escrito por Gregor Hohpe e Bobby Woolf

Para demonstrar um pouco do que o Apache Camel é capaz, vamos ao código:

Listagem 1: Arquivo pom.xml do projeto


<?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/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <artifactId>introducao-camel</artifactId>
    <groupId>devmedia</groupId>
    <packaging>jar</packaging>
    <version>0.0.1</version>
    <name>IntroCamel</name>
    <description>Introducao Apache Camel</description>

    <dependencies>
        <dependency>
	  <groupId>org.apache.camel</groupId>            
            <artifactId>camel-core</artifactId>
            <version>2.10.2</version>
        </dependency>
        <dependency>
	  <groupId>org.apache.camel</groupId>            
            <artifactId>camel-http</artifactId>
            <version>2.10.2</version>
        </dependency>
        <dependency>
	  <groupId>org.apache.camel</groupId>            
            <artifactId>camel-jetty</artifactId>
            <version>2.10.2</version>
        </dependency>        
        <dependency>
	  <groupId>org.apache.camel</groupId>            
            <artifactId>camel-test</artifactId>
            <version>2.10.2</version>
        </dependency>
        <dependency>
	  <groupId>ch.qos.logback</groupId>
	  <artifactId>logback-core</artifactId>
	  <version>1.0.7</version>
        </dependency>
	  <dependency>
	  <groupId>ch.qos.logback</groupId>
	  <artifactId>logback-classic</artifactId>
	  <version>1.0.7</version>
        </dependency>
    </dependencies>
</project>

No arquivo de projeto maven (pom.xml) temos tudo o que é necessário para o nosso pequeno teste. Os artefatos listados são:

  • camel-core: componente principal da arquitetura do Apache Camel. Nesse jar temos as classes principais para construção das aplicações.
  • Camel-http, camel-jetty, camel-test: como dito, adicionamos apenas artefatos que precisamos. Nesse caso, adicionamos o cliente http, o servidor http Jetty e o suporte a testes unitários.
  • Logback-core e logback-classic: para quem não conhece, esses dois artefatos são implementações da API do SLF4J, que é o mecanismo de logging utilizado pelo Apache Camel.

Para criação dos descritores para o IDE Eclipse, executamos o comando

Listagem 2: Comando do maven


mvn eclipse:eclipse

Se você não conhece o maven, lembre-se de visitar http://maven.apache.org.

Agora examinaremos um pequeno teste unitário que cria e inicia um servidor Jetty. Dois métodos de teste foram criados. O primeiro chamado “testEnvioSimples” submete ao servidor um xml e aguarda o retorno de apenas 1 (uma) mensagem. Em seguida examina o conteúdo da mensagem retornada. O segundo teste chamado “testEnvioSimplesNaoSuportado” manda um xml levemente modificado. Como o valor “2” no conteúdo do XML não é aceito, nenhuma mensagem será retornada. Vamos à listagem:

Listagem 3: Classe de teste


package br.com.devmedia.introcamel;

import java.util.List;

import org.apache.camel.EndpointInject;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Assert;
import org.junit.Test;

public class CamelTest extends CamelTestSupport {

	@Produce(uri = "http://localhost:9898/test" )
    protected ProducerTemplate template;
	
	@EndpointInject(uri = "mock:end")
	protected MockEndpoint mockEndpoint;
	
	@Test
	public void testEnvioSimples() throws Exception {
		template.sendBody("<doc><param>1</param></doc>");
		mockEndpoint.expectedMessageCount(1);
		mockEndpoint.assertIsSatisfied();
		List<Exchange> exchanges = mockEndpoint.getExchanges();
		Assert.assertTrue("Mensagem Inspecionada",exchanges.get(0).getIn().getHeader("OK",Boolean.class));;
	}
	
	@Test
	public void testEnvioSimplesNaoSuportado() throws Exception {
		template.sendBody("<doc><param>2</param></doc>");
		mockEndpoint.expectedMessageCount(0);
		mockEndpoint.assertIsSatisfied();
	}
	
	protected RouteBuilder createRouteBuilder() {
		return new RouteBuilder() {

	@Override
	public void configure() throws Exception {
             from("jetty://http://localhost:9898/test")
             .filter()
             .xpath("/doc/param='1'").process(new Processor() {					         
                public void process(Exchange exchange) 
                throws Exception {
	            exchange.getIn().setHeader("OK", Boolean.TRUE);
                }
					
		}).to("mock:end").end();
	}
			
};
}
}

Alguns fatos importantes sobre essa classe:

  • Ela estende org.apache.camel.test.junit4.CamelTestSupport. Essa é apenas uma das formas de se testar integrações no Camel. Dê uma boa olhada em http://camel.apache.org/testing.html.
  • Ela sobrescreve o método createRouteBuilder. Um RouteBuilder é um construtor de rotas. Uma rota representa uma mensagem indo de um lugar para outro. Normalmente envolve um produtor (from) e um consumidor (to). No exemplo, o produtor é o jetty://http://localhost:9898/test ou seja, alguma mensagem será produzida por esse endereço ou URI. Iremos capturar essa mensagem e tratá-la no nosso processador. Aliás, esse endereço jetty é chamado de endpoint e só funciona se o camel-jetty fizer parte do nosso projeto. Para mais exemplos: http://camel.apache.org/jetty.html.
  • Implementamos um processador. Processadores são classes que processam mensagens conhecidas por Exchange. Um Exchange encapsula todo tipo de informação que trafega nas rotas. Veja mais em http://camel.apache.org/exchange.html.
  • O nosso servidor http jetty não processará todo tipo de mensagem, apenas aquelas cujo conteúdo XML seja 1. Repare na expressão xpath /doc/param='1'. Ela é utilizada como filtro de mensagens. Filtro de mensagens é um padrão de intregração. Detalhes em http://camel.apache.org/message-filter.html.
  • Toda mensagem é direcionada o mock:end. Mock é um componente do core do Apache Camel. Ele deve ser usado apenas nos teste e serve para fazer assertivas quanto às mensagens.
  • Uso de anotações. Através delas, a classe de teste injeta o uma instância de ProducerTemplate. Essa classe é essencial para interação com as rotas e serve para enviar criar e enviar exchanges para os endpoints. No nosso exemplo, envia um XML para o servidor http. Também usamos anotações para obter referências para os endpoints como no caso do mock.
Pattern de Integração Message Filter

Figura 2: Pattern de Integração “Message Filter”

Reparem que com pouquíssimas linhas criamos um servidor HTTP que filtra mensagens e as processa. Com Apache Camel, seria muito fácil enviar esse xml para um arquivo, banco de dados, Web Service ou o que o Camel suportar através de seus componentes. A lista completa de componentes pode ser vista em http://camel.apache.org/components.html.

É isso pessoal. Finalizamos nossa breve visão do que é o framework Apache Camel. Experimentem alterar os testes e adicionar novos componentes, sempre acompanhando as mensagens que saem no console. Até a próxima.