Apache Camel - Guia rápido

Considere uma situação em que um grande supermercado online em sua cidade, como o Bigbasket na Índia, o convida a projetar uma solução de TI para eles. A solução estável e escalável os ajudará a superar os problemas de manutenção de software que enfrentam hoje. Esta loja online administra seus negócios há uma década. A loja aceita pedidos online de diferentes categorias de produtos de seus clientes e os distribui aos respectivos fornecedores. Por exemplo, suponha que você peça sabonetes, óleo e leite; esses três itens serão distribuídos aos três respectivos fornecedores. Os três fornecedores enviarão seus suprimentos para um ponto de distribuição comum, de onde todo o pedido será atendido pelo centro de entrega. Agora, vejamos o problema que eles enfrentam hoje.

Quando esta loja iniciou seus negócios, ela estava aceitando pedidos em um arquivo de texto simples separado por vírgulas. Após um período de tempo, a loja mudou para a colocação de pedidos baseada em mensagens. Mais tarde, algum desenvolvedor de software sugeriu uma colocação de pedido baseada em XML. Eventualmente, a loja até adaptou uma interface de serviço da web. Agora, aí vem o verdadeiro problema. Os pedidos agora vêm em formatos diferentes. Obviamente, toda vez que a empresa atualizava o formato de aceitação do pedido, ela não queria quebrar a interface previamente implantada para não causar confusões na mente do cliente.

Ao mesmo tempo, com o crescimento do negócio, a loja agregava periodicamente novos fornecedores ao seu repertório. Cada um desses fornecedores tinha seu próprio protocolo para aceitar pedidos. Mais uma vez, enfrentamos o problema da integração; nossa arquitetura de aplicativo deve ser escalonável para acomodar novos fornecedores com seu mecanismo exclusivo de colocação de pedidos.

Toda a situação é mostrada na figura a seguir -

Agora, vamos ver como o Apache Camel pode vir em seu socorro para fornecer uma arquitetura de solução escalável, elegante e sustentável para o cenário descrito.

Antes de prosseguirmos com a solução, precisamos fazer uma pequena suposição. Para todas as discussões neste tutorial, assumiremos que os pedidos online são feitos no formato XML. Um formato típico para o arquivo de pedido que usaremos ao longo de nossas discussões é mostrado aqui -

<?xml version = "1.0" encoding = "UTF-8"?>
<OrderID Order = "001">
   <order product = "soaps">
      <items>
         <item>
            <Brand>Cinthol</Brand>
            <Type>Original</Type>
            <Quantity>4</Quantity>
            <Price>25</Price>
         </item>
         <item>
            <Brand>Cinthol</Brand>
            <Type>Lime</Type>
            <Quantity>6</Quantity>
            <Price>30</Price>
         </item>
      </items>
   </order>
   
   <order product = "Oil">
      <items>
         <item>
            <Brand>Saffola</Brand>
            <Type>Gold</Type>
            <Quantity>2</Quantity>
            <Price>649</Price>
         </item>
         <item>
            <Brand>Fortune</Brand>
            <Type>Sunlite</Type>
            <Quantity>1</Quantity>
            <Price>525</Price>
         </item>
      </items>
   </order>
   
   <order product = "Milk">
      <items>
         <item>
            <Product>Milk</Product>
            <Brand>Amul</Brand>
            <Type>Pure</Type>
            <Quantity>2</Quantity>
            <Price>60</Price>
         </item>
      </items>
   </order>
</OrderID>

Estaremos usando o modelo XML acima para ilustrar os exemplos do Camel neste tutorial.

Camel é uma caixa preta que recebe mensagens de algum endpoint e envia para outro. Na caixa preta, as mensagens podem ser processadas ou simplesmente redirecionadas.

Então, por que ter uma estrutura para isso? Em situações práticas, conforme visto no estudo de caso de introdução, pode haver muitos remetentes e muitos receptores, cada um seguindo seu próprio protocolo, como ftp, http e jms. O sistema pode exigir muitas regras complexas, como a mensagem do remetente A deve ser entregue apenas para B e C. Em algumas situações, pode ser necessário traduzir a mensagem para outro formato que o destinatário espera. Esta tradução pode estar sujeita a certas condições com base no conteúdo da mensagem. Então, essencialmente, você pode precisar traduzir entre protocolos, unir componentes, definir regras de roteamento e fornecer filtragem com base no conteúdo da mensagem. Isso é ilustrado na figura a seguir -

Para atender aos requisitos acima e projetar uma arquitetura de software adequada para muitas dessas situações, os Enterprise Integration Patterns ( EIP ) foram documentados por Gregor Hohpe e Bobby Woolf em 2003. Apache Camel fornece a implementação desses padrões e o objetivo deste tutorial é ensinar você como usar o Camel em situações como a descrita na introdução.

Apache Camel é uma estrutura de código aberto. É um middleware orientado a mensagens que fornece roteamento baseado em regras e mecanismo de mediação. Você pode definir regras como se for um pedido de “leite”, redirecioná-lo para um vendedor de leite e se for um pedido de “óleo”, redirecioná-lo para um vendedor de óleo e assim por diante. Usando o Camel, você será capaz de implementar essas regras e fazer o roteamento em um código Java familiar. Isso significa que você pode usar seu Java IDE familiar para definir essas regras em um ambiente de tipo seguro. Não precisamos usar arquivos de configuração XML, que normalmente tendem a ser volumosos. No entanto, o Camel oferece suporte à configuração XML por meio da estrutura Spring, se você preferir usar XML para configurar as regras. Você pode até usar arquivos de configuração XML do Blueprint e até mesmo um Scala DSL, se for um amante do Scala. Também significa que você pode usar seu Java, Scala IDE favorito ou até mesmo um editor XML simples para configurar as regras.

A entrada para este mecanismo pode ser um arquivo de texto delimitado por vírgulas, um POJO (Plain Old Java Object), XML são qualquer um dos vários outros formatos suportados pelo Camel. Da mesma forma, a saída do motor pode ser redirecionada para um arquivo, para uma fila de mensagens ou até mesmo para a tela do seu monitor para você visualizar os pedidos enviados aos respectivos fornecedores. Eles são chamados de endpoints e o Camel suporta o padrão Message Endpoint EIP. Os endpoints Camel são discutidos posteriormente no capítulo Endpoints.

Camel é normalmente usado com Apache ServiceMix , Apache ActiveMQ e Apache CXF para implementar arquiteturas orientadas a serviços.

Tendo visto uma visão geral do Apache Camel, vamos agora nos aprofundar em seus recursos para ver o que ele oferece. Já sabemos que o Apache Camel é uma estrutura Java de software livre que essencialmente fornece uma implementação de vários EIPs. O Camel torna a integração mais fácil, fornecendo conectividade a uma grande variedade de transportes e APIs. Por exemplo, você pode facilmente rotear JMS para JSON, JSON para JMS, HTTP para JMS, FTP para JMS, até mesmo HTTP para HTTP e conectividade para microsserviços. Você simplesmente precisa fornecer terminais apropriados em ambas as extremidades. O Camel é extensível e, portanto, no futuro, mais terminais podem ser adicionados facilmente à estrutura.

Para conectar EIPs e transportes, você usa DSLs (Domain Specific Languages), como Java, Scala e Groovy. Uma regra de roteamento Java típica pode ser semelhante a -

from ("file:/order").to("jms:orderQueue");

Esta regra de roteamento carrega os arquivos do order diretório, cria uma mensagem JMS com o conteúdo do arquivo e envia essa mensagem para uma fila chamada orderQueue.

Aqui estão alguns dos recursos mais importantes do Camel que você consideraria úteis no desenvolvimento de aplicativos do Camel -

  • O Camel oferece suporte a formatos de dados conectáveis e conversores de tipo para essas transformações de mensagens, portanto, novos formatos e conversores podem ser adicionados no futuro. Atualmente, ele suporta vários formatos e conversores populares; para citar alguns - CSV, EDI, JAXB, JSON, XmlBeans, XStream, Flatpack, Zip.

  • Camel suporta linguagens plugáveis para escrever predicados em DSL. Algumas das linguagens suportadas incluem JavaScript, Groovy, Python, PHP, Ruby, SQL, XPath, XQuery.

  • O Camel suporta o modelo POJO para que você possa conectar Javabeans em vários pontos.

  • O Camel facilita o teste de grandes sistemas distribuídos e assíncronos usando mensagens.

Vamos agora entender a arquitetura do Camel e ver como os vários recursos são implementados.

A arquitetura Camel consiste em três componentes - mecanismo de integração e roteador, processadores e componentes. Isso é ilustrado na figura a seguir -

O próprio núcleo do Camel é muito pequeno e contém 13 componentes essenciais. Os mais de 80 componentes restantes estão fora do núcleo. Isso ajuda a manter uma baixa dependência de onde ele é implantado e promove extensões no futuro. oComponents módulo fornece um Endpointinterface com o mundo externo. Os pontos de extremidade são especificados por URIs, comofile:/order e jms:orderQueue que você viu no último capítulo.

o Processorsmódulo é usado para manipular e mediar mensagens entre Endpoints. Os EIPs que mencionei anteriormente são implementados neste módulo. Atualmente, ele suporta mais de 40 padrões conforme documentado no livro EIP e outras unidades de processamento úteis.

o Processors e Endpoints estão ligados em Integration Engine and Routermódulo usando DSLs. Ao fazer a fiação, você pode usar filtros para filtrar mensagens com base em critérios definidos pelo usuário. Conforme mencionado anteriormente, você tem várias opções para escrever essas regras. Você pode usar Java, Scala, Groovy ou mesmo XML para isso.

Agora, chegamos ao componente mais importante do Camel, que pode ser considerado o núcleo - o CamelContext.

CamelContext fornece acesso a todos os outros serviços no Camel, conforme mostrado na figura a seguir -

Vejamos os vários serviços. oRegistrymódulo por padrão é um registro JNDI, que contém o nome dos vários Javabeans que seu aplicativo usa. Se você usar Camel com Spring, esta será a SpringApplicationContext. Se você usar Camel no contêiner OSGI, isso seráOSGI registry. oType converterscomo o nome sugere, contém os vários conversores de tipo carregados, que convertem sua entrada de um formato para outro. Você pode usar os conversores de tipo embutidos ou fornecer seu próprio mecanismo de conversão. oComponentsmódulo contém os componentes usados ​​por seu aplicativo. Os componentes são carregados por descoberta automática noclasspathque você especifica. No caso do container OSGI, estes são carregados sempre que um novo bundle é ativado. Já discutimos oEndpoints e Routesnos capítulos anteriores. oData formats módulo contém os formatos de dados carregados e, finalmente, o Languages módulo representa os idiomas carregados.

O trecho de código aqui lhe dará uma ideia de como um CamelContext é criado em um aplicativo Camel -

CamelContext context = new DefaultCamelContext();
try {
   context.addRoutes(new RouteBuilder() {
      // Configure filters and routes
   }
}
);

o DefaultCamelContext classe fornece uma implementação concreta de CamelContext. DentroaddRoutes método, criamos uma instância anônima de RouteBuilder. Você pode criar váriosRouteBuilderinstâncias para definir mais de um roteamento. Cada rota no mesmo contexto deve ter um ID exclusivo. As rotas podem ser adicionadas dinamicamente no tempo de execução. Uma rota com o mesmo ID que a definida anteriormente substituirá a rota mais antiga.

O que se passa dentro do RouteBuilder instância é descrita a seguir.

Rotas

O roteador define a regra para mover a mensagem from para um tolocalização. Você usaRouteBuilderpara definir uma rota em Java DSL. Você cria uma rota estendendo oRouteBuilderclasse. A rota começa com umfromponto final e termina em um ou mais pontos finais. Entre os dois, você implementa a lógica de processamento. Você pode configurar qualquer número de rotas em um únicoconfigure método.

Aqui está um exemplo típico de como a rota é criada -

context.addRoutes(new RouteBuilder() {
   @Override
   public void configure() throws Exception {
      from("direct:DistributeOrderDSL")
      .to("stream:out");
   }
}

Substituímos o método de configuração de RouteBuilderclasse e implementar nosso mecanismo de roteamento e filtragem nela. No caso atual, redirecionamos a entrada recebida do EndpointDistributeOrderDSL para o console, que é especificado pelo Endpoint stream:out.

Escolha do idioma

Você pode criar as rotas em diferentes idiomas. Aqui estão alguns exemplos de como a mesma rota é definida em três idiomas diferentes -

Java DSL

from ("file:/order").to("jms:orderQueue");

Spring DSL

<route>
   <from uri = "file:/order"/>
   <to uri = "jms:orderQueue"/>
</route>

Scala DSL

from "file:/order" -> "jms:orderQueue"

Filtros

Você usa o filtro para selecionar uma parte do conteúdo de entrada. Para configurar um filtro, você usa qualquer implementação de Predicado arbitrária . A entrada filtrada é então enviada para o seu endpoint de destino desejado. Neste exemplo, filtramos todos os pedidos de sabonete para que possam ser enviados coletivamente a um fornecedor de sabonete.

from("direct:DistributeOrderDSL")
   .split(xpath("//order[@product = 'soaps']/items"))
      .to("stream:out");

No exemplo, usamos xpathpredicado para filtragem. Se você preferir usar a classe Java para filtragem, use o seguinte código -

from("direct:DistributeOrderDSL")
   .filter()
      .method(new Order(),"filter")
         .to("stream:out");

o Order é sua classe Java customizada com seu próprio mecanismo de filtragem.

Você pode combinar vários predicados em um único roteamento como aqui -

from("direct:DistributeOrderDSL")
   .choice()
      .when(header("order").isEqualTo("oil"))
         .to("direct:oil")
      .when(header("order").isEqualTo("milk"))
         .to("direct:milk")
      .otherwise()
         .to("direct:d");

Portanto, agora todos os pedidos de “óleo” irão para o vendedor de óleo, os pedidos de “leite” irão para o vendedor de leite e o restante para um pool comum.

Processador Personalizado

Você também pode usar o processamento personalizado. O exemplo abaixo cria um processador personalizado chamadomyCustomProcessor e o usa no construtor de rotas.

Processor myCustomProcessor = new Processor() {
   public void process(Exchange exchange) {
      // implement your custom processing
   }
};
RouteBuilder builder = new RouteBuilder() {
   public void configure() {
      from("direct:DistributeOrderDSL")
      .process(myProcessor);
   }
};

Você pode usar processadores personalizados junto com escolha e filtragem para obter um melhor controle sobre sua mediação e roteamento -

from("direct:DistributeOrderDSL")
   .filter(header("order").isEqualTo("milk"))
      .process(myProcessor);

Usando XML

As rotas podem ser definidas em XML mais volumoso, se você preferir. O seguinte snippet XML mostra como criar uma rota junto com alguma filtragem via Spring XML -

<camelContext xmlns = "http://camel.apache.org/schema/spring">
   <route>
      <from uri = "direct:DistributeOrderXML"/>
      <log message = "Split by Distribute Order"/>
      <split>
         <xpath>//order[@product = 'Oil']/items</xpath>
         <to uri = "file:src/main/resources/order/"/>
         <to uri = "stream:out"/>
      </split>
   </route>
</camelContext>

Tendo visto como as rotas são construídas, veremos agora as várias técnicas de criação de Endpoints.

Aprendemos como os terminais se parecem em nosso código de integração. As expressões que usamos até agora, comofile:/order, jms:orderQueue, direct:distributeOrderDSLsão os pontos finais. Como você pode ver, eles seguem os formatos de especificação de URI. Ao avaliar este URI, oCamelContext cria o Endpointinstância; você não precisa se preocupar em instanciarEndpoint implementação em seu DSL.

Pegando nossos exemplos anteriores, você especifica endpoints em Java DSL como aqui -

from ("file:/order").to("jms:orderQueue");

E na primavera como aqui -

<route>
   <from uri = "file:/order"/>
   <to uri = "jms:orderQueue"/>
</route>

Em ambos os casos, o ponto final é uma string constante. Em certos casos, você pode querer construir esta string em tempo de execução. Você pode fazer isso usando JavaStringmétodos do formatador. Camel fornece outra abordagem mais simples para criar essas strings URI em tempo de execução. Para isso, a Camel fornecefromF e toFmétodos que aceitam os argumentos com os parâmetros especificados pelo usuário. A seguinte declaração ilustra o uso detoF método -

from("direct:distributeOrderDSL”).toF("file://%s?fileName=%s", path, name);

Por causa desses métodos, a necessidade de usar o Java integrado String métodos do formatador são evitados.

O Camel usa linguagem simples por padrão para calcular a expressão do terminal. oSimple linguagem foi projetada principalmente para avaliar Expressions e Predicatessem se preocupar muito com as complexidades de XPath. Para avaliar predicados, você pode combinar outra linguagem, comoxpath com o padrão Simplelíngua. Isso é feito usando o sinal de mais para separar o outro idioma. O snippet de código aqui mostra como concatenarxpath string para a expressão escrita em Simple.

from("direct:start")
.toD("jms:${orderQueue}+language:xpath:/order/@id");

Dentro Spring, você pode conseguir o mesmo que aqui -

<route>
   <from uri = "direct:start"/>
   <toD uri = "jms:${orderQueue}+language:xpath:/order/@id"/>
</route>

Você pode concatenar quantos idiomas quiser, cada um separado por um sinal de mais do anterior. A lista de idiomas suportados pode ser encontrada aqui .

Camel fornece vários componentes pré-construídos.

Neste capítulo, discutiremos alguns componentes importantes do camel-core módulo.

Feijão

o Beancomponente vincula beans a trocas de mensagens Camel. O URI para criar um endpoint é especificado comobean:beanID, Onde beanID é o nome do bean conforme especificado no Registry.

JndiContext jndiContext = new JndiContext();
jndiContext.bind("MilkOrder", new MilkOrderProcessor());
CamelContext camelContext = new DefaultCamelContext(jndiContext);

camelContext.addRoutes(new RouteBuilder() {
   public void configure() {
      from("direct:bigBasket")
         .to("bean:MilkOrder?method=placeOrder");
   }
});

Observe como o endpoint é especificado usando o bean:protocolo. Você pode opcionalmente especificar o método de bean que deve ser chamado; neste caso, o método chamadoplaceOrderserá chamado durante a avaliação da expressão Endpoint. oMilkOrder é um nome JNDI para o MilkOrderProcessorJavabean conforme registrado nas duas primeiras linhas do trecho de código. A definição deMilkOrderProcessor em si é omitido aqui por brevidade.

Direto

Você deve ter notado o uso de Directem nossos exemplos anteriores. Para enviar um pedido a um fornecedor de óleo, usamosdirect:oilna especificação do Endpoint. O uso deDirectcomponente permite que você chame um ponto de extremidade de forma síncrona. Os dois trechos de código a seguir de nossos exemplos anteriores ilustram o uso deDirect -

.when(header("order").isEqualTo("oil"))
   .to("direct:oil")

E,

from("direct:DistributeOrderDSL")
   .process(myProcessor);

Arquivo

o Filecomponente fornece acesso ao sistema de arquivos em sua máquina. Usando este componente, você poderá salvar mensagens de outros componentes em um disco local. Além disso, permite que outros componentes do Camel processem os arquivos locais. Você pode usar qualquer umfile:directoryName[?options] ou file://directoryName[?options]como um formato URI ao usar o componente Arquivo. Você já viu o uso deste componente -

from ("file:/order").to("jms:orderQueue");

Observe que o Filecomponente, por padrão, leva o nome do diretório. Portanto, o conteúdo do diretório do pedido será considerado como conteúdo de entrada. Para especificar um determinado arquivo noorder diretório, você usará a seguinte instrução -

from ("file:/order?fileName = order.xml").to("jms:orderQueue");

Registro

o LogO componente permite que você registre mensagens no mecanismo de registro subjacente. Camel usa Simple Logging Facade for Java (SLF4J) como uma abstração para várias estruturas de registro. Você pode usarjava.util.logging, logback, log4jpara registro. Este snippet de código ilustra o uso doLog componente -

from("direct:DistributeOrderDSL")
   .to("bean:MilkOrder?method = placeOrder")
   .to("log:com.example.com?level = INFO&showBody = true");

SEDA

o SEDA componente permite que você chame de forma assíncrona outro endpoint no mesmo CamelContext. Se você deseja chamar através de instâncias CamelContext, você precisa usarVMcomponente. O uso de SEDA é ilustrado aqui -

from("direct:DistributeOrderDSL")
// send it to the seda queue that is async
   .to("seda:nextOrder")

Nesta rota, iremos simplesmente encaminhar os pedidos para nextOrderfila assíncrona. Um cliente que se inscreveu nesta fila selecionará as mensagens dessa fila.

Cronômetro

o TimerO componente é usado para enviar mensagens em intervalos regulares e, portanto, pode ser muito útil ao testar aplicativos Camel. O snippet de código aqui dispara uma mensagem de teste para o console a cada dois segundos -

from("timer://testTimer?period = 2000")
   .setBody()
   .simple("This is a test message ${header.timer}")
      .to("stream:out");

A maioria dos projetos de integração usa mensagens, pois ajuda na criação de uma arquitetura de aplicativo fracamente acoplada. As mensagens podem ser síncronas ou assíncronas. JMS suporta ambospoint-to-point e publish-subscribemodelos. Você usa umQueue para ponto a ponto e Topicpara um modelo publicar-assinar. Em uma plataforma Java, o JMS - Java Messaging Service fornece uma interface para um servidor de mensagens. O Apache activeMQ é um provedor JMS de código aberto. O Camel não é fornecido com um provedor JMS; no entanto, ele pode ser configurado para usar activeMQ. Para usar este componente, você precisa incluir os seguintes jars em seu projeto - activemq, camel-spring e camel-jms.

O seguinte trecho de código mostra como configurar o Camel para activeMQ.

<bean id = "jms" class = "org.apache.camel.component.jms.JmsComponent">
   <property name = "connectionFactory">
      <bean class="org.apache.activemq.ActiveMQConnectionFactory">
         <property name = "orderQueue" value = "tcp://localhost:61000" />
      </bean>
   </property>
</bean>

Aqui, o aplicativo Camel começará a escutar uma fila chamada orderQueue. A própria fila é configurada no servidor de mensagens activeMQ em execução no host local e listada na porta 61000. Assim que isso for feito, seu aplicativo pode enviar ou receber mensagens para esta fila de qualquer um dos terminais definidos em seu aplicativo.

Finalmente, é hora de colocar tudo junto em um projeto para obter uma compreensão mais profunda de como os aplicativos Camel são criados.

Usaremos o Maven para construir um projeto Camel. Embora seja preferível usar o IDE IntelliJ para desenvolvimento. Você pode usar qualquer IDE de sua escolha para este projeto.

Criando Novo Projeto

Crie um novo Maven projeto e especifique o seguinte -

GroupId: Basket
ArtifactId: Basket

Selecione o local padrão para o seu projeto ou, se preferir, especifique o diretório de sua escolha.

Adicionando Dependências

Você precisa adicionar algumas dependências para usar o Camel. As dependências são adicionadas empom.xml. Portanto, abra pom.xml e adicione as seguintes duas dependências -

<dependencies>
   <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-core</artifactId>
      <version>2.20.0</version>
   </dependency>
   <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-stream</artifactId>
      <version>2.20.0</version>
   </dependency>
</dependencies>

Note- Precisamos das dependências mínimas para nosso aplicativo. À medida que você usa mais componentes Camel de suas bibliotecas, você precisará adicionar as dependências correspondentes neste arquivo pom.xml.

Criação de Java DSL

A seguir, você escreverá seu código de filtragem e roteamento em uma DSL Java. Crie uma nova classe Java chamadaDistributeOrderDSL. Adicione o seguinte código a ele -

public class DistributeOrderDSL {
   public static void main(String[] args) throws Exception {
      CamelContext context = new DefaultCamelContext();
      try {
         context.addRoutes(new RouteBuilder() {
            @Override
            public void configure() throws Exception {
               from("direct:DistributeOrderDSL")
                  .split(xpath("//order[@product='soaps']/items")).to("stream:out");
               
               // .to("file:src/main/resources/order/");
            }
         });
         context.start();
         ProducerTemplate orderProducerTemplate = context.createProducerTemplate();
         InputStream orderInputStream = new FileInputStream(ClassLoader.getSystemClassLoader()
            .getResource("order.xml").getFile());
         orderProducerTemplate.sendBody("direct:DistributeOrderDSL", orderInputStream);
      } finally {
         context.stop();
      }
   }
}

No main método, primeiro criamos CamelContext instanciando uma implementação padrão fornecida em DefaultCamelContext classe.

CamelContext context = new DefaultCamelContext();

Em seguida, adicionamos uma rota criando um anônimo RouteBuilder instância -

context.addRoutes(new RouteBuilder() {

Nós substituímos o configure método para adicionar uma rota de um URI direto DistributeOrderDSLpara o console do sistema. Fornecemos alguma filtragem usando a consulta xpath.

public void configure() throws Exception {
   from("direct:DistributeOrderDSL")
      .split(xpath("//order[@product = 'soaps']/items")).to("stream:out");
   // .to("file:src/main/resources/order/");
}

Depois de adicionar a rota, iniciamos o contexto -

context.start();

Em seguida, adicionamos o código para criar nosso URI direto - DistributeOrderDSL.

ProducerTemplate orderProducerTemplate = context.createProducerTemplate();
InputStream orderInputStream = new FileInputStream(ClassLoader.getSystemClassLoader()
   .getResource("order.xml").getFile());

Finalmente, começamos o processamento -

orderProducerTemplate.sendBody("direct:DistributeOrderDSL", orderInputStream);

Agora, quando seu código Java DSL é concluído, a única coisa que resta antes de testar o aplicativo é adicionar o order.xmlarquivo para o seu projeto. Você pode usar o XML de amostra mostrado no capítulo Introdução para esse propósito.

Resultado dos testes

Ao executar o aplicativo, você verá a seguinte saída -

<items>
   <item>
      <Brand>Cinthol</Brand>
      <Type>Original</Type>
      <Quantity>4</Quantity>
      <Price>25</Price>
   </item>
   <item>
      <Brand>Cinthol</Brand>
      <Type>Lime</Type>
      <Quantity>6</Quantity>
      <Price>30</Price>
   </item>
</items>

Observe que apenas pedidos de sabonetes estão listados aqui. Se você deseja armazenar isso em um arquivo local, basta comentar ostream.out linha e descomente a seguinte linha em seu configure método -

// .to("file:src/main/resources/order/");

Em nossa seção subsequente, aprenderemos como usar Camel com Spring.

Agora vamos recriar o aplicativo do capítulo anterior usando Spring. Isso nos dará uma ideia de como criar o roteamento Camel em XML em vez de DSL.

Criando Novo Projeto

Crie um novo Maven projeto e especifique o seguinte -

GroupId: BasketWithSpring
ArtifactId: BasketWithSpring

Selecione o local padrão para o seu projeto ou, se preferir, especifique o diretório de sua escolha.

Adicionando Dependências

Além das dependências principais que você usou no aplicativo anterior, você precisa adicionar mais algumas dependências para usar o Spring. As dependências são adicionadas em pom.xml. Agora, abra pom.xml e adicione as seguintes dependências -

<dependencies>
   ...
   <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.1.3.RELEASE</version>
   </dependency>
   
   <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-pool</artifactId>
      <version>5.15.2</version>
   </dependency>
   
   <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-pool</artifactId>
      <version>5.15.1</version>
   </dependency>
   
   <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-spring</artifactId>
      <version>2.15.1</version>
   </dependency>
</dependencies>

Criação de Java DSL para Spring

Vamos agora criar uma nova classe Java chamada DistributeOrderXML. Adicione o seguinte código a ele -

public class DistributeOrderXML {
   public static void main(String[] args) throws Exception {
      ApplicationContext appContext = new ClassPathXmlApplicationContext(
         "SpringRouteContext.xml");
      CamelContext camelContext = SpringCamelContext.springCamelContext(appContext, false);
      try {
         camelContext.start();
         ProducerTemplate orderProducerTemplate = camelContext.createProducerTemplate();
         InputStream orderInputStream = new FileInputStream(ClassLoader.getSystemClassLoader()
            .getResource("order.xml").getFile());
         
         orderProducerTemplate.sendBody("direct:DistributeOrderXML", orderInputStream);
      } finally {
         camelContext.stop();
      }
   }
}

No main método, primeiro criamos uma instância de ApplicationContext, que é a interface central em um aplicativo Spring. Em seu construtor, especificamos o nome do arquivo XML que contém nossas informações de roteamento e filtragem.

ApplicationContext appContext = new ClassPathXmlApplicationContext(
   "SpringRouteContext.xml");

Em seguida, criamos CamelContext especificando o criado acima ApplicationContext em seu parâmetro.

CamelContext camelContext = SpringCamelContext.springCamelContext(appContext, false);

Neste ponto, nosso roteamento e filtragem estão configurados. Portanto, começamos oCamelContext usando seu startmétodo. Como no caso anterior, definimos o Endpoint para carregar o arquivo order.xml e iniciar o processamento. Agora, vamos entender como o roteamento é definido em XML.

Criando o contexto do aplicativo

Adicione um novo arquivo XML ao projeto e chame-o SpringRouteContext.xml. Recorte e cole o seguinte conteúdo neste arquivo.

<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
   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 ">
   <camelContext xmlns = "http://camel.apache.org/schema/spring">
      <route>
         <from uri = "direct:DistributeOrderXML"/>
         <log message = "Split by Distribute Order"/>
         <split>
            <xpath>//order[@product = 'Oil']/items</xpath>
            <to uri = "file:src/main/resources/order/"/>
            <to uri = "stream:out"/>
         </split>
      </route>
   </camelContext>
</beans>

Aqui, definimos a consulta xpath da seguinte forma, observe que agora selecionamos todos os pedidos de “óleo”.

<xpath>//order[@product = 'Oil']/items</xpath>

Os pontos de extremidade de saída são múltiplos. O primeiro endpoint especifica oorder pasta e a segunda especifica o console.

<to uri = "file:src/main/resources/order/"/>
<to uri = "stream:out"/>

Execute o aplicativo.

Resultado dos testes

Ao executar o aplicativo, você verá a seguinte saída na tela.

<items>
   <item>
      <Brand>Cinthol</Brand>
      <Type>Original</Type>
      <Quantity>4</Quantity>
      <Price>25</Price>
   </item>
   <item>
      <Brand>Cinthol</Brand>
      <Type>Lime</Type>
      <Quantity>6</Quantity>
      <Price>30</Price>
   </item>
</items>

Confira o orderpasta no caminho especificado por você. Você encontrará um arquivo recém-criado que contém o código XML acima.

Conclusão

Camel fornece uma estrutura pronta para uso que implementa EIPs para facilitar seus projetos de integração. Ele oferece suporte à codificação em linguagens de domínio específico e também ao uso de XML.