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.
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.
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.