Apache Camel - Guida rapida

Considera una situazione in cui un grande negozio di alimentari online nella tua città come il Bigbasket in India ti invita a progettare una soluzione IT per loro. La soluzione stabile e scalabile li aiuterà a superare i problemi di manutenzione del software che devono affrontare oggi. Questo negozio online gestisce la sua attività negli ultimi dieci anni. Il negozio accetta ordini online per diverse categorie di prodotti dai propri clienti e li distribuisce ai rispettivi fornitori. Ad esempio, supponiamo di ordinare alcuni saponi, olio e latte; questi tre articoli saranno distribuiti ai tre rispettivi fornitori. I tre fornitori invieranno quindi le loro forniture a un punto di distribuzione comune da cui l'intero ordine verrà evaso dal centro di consegna. Ora, esaminiamo il problema che stanno affrontando oggi.

Quando questo negozio ha iniziato la sua attività, accettava ordini in un file di testo semplice separato da virgole. Per un periodo di tempo, il negozio è passato al posizionamento degli ordini basato sui messaggi. Successivamente, alcuni sviluppatori di software hanno suggerito un posizionamento di ordini basato su XML. Alla fine, il negozio ha persino adattato un'interfaccia del servizio web. Ora, ecco che arriva il vero problema. Gli ordini ora sono disponibili in diversi formati. Ovviamente, ogni volta che l'azienda aggiornava il formato di accettazione dell'ordine, non voleva rompere l'interfaccia precedentemente implementata per non creare confusione nella mente del cliente.

Parallelamente, mentre l'attività continuava a crescere, il negozio periodicamente aggiungeva nuovi fornitori al proprio repertorio. Ciascuno di questi fornitori aveva il proprio protocollo per accettare gli ordini. Ancora una volta, affrontiamo il problema dell'integrazione; la nostra architettura applicativa deve essere scalabile per accogliere nuovi fornitori con il loro meccanismo di posizionamento degli ordini unico.

L'intera situazione è mostrata nella figura seguente:

Ora, vediamo come Apache Camel può venire in tuo soccorso per fornire un'architettura di soluzione elegante, gestibile e scalabile per lo scenario descritto.

Prima di procedere con la soluzione, dobbiamo fare una piccola ipotesi. Per tutte le discussioni in questo tutorial, assumeremo che gli ordini online siano inseriti in formato XML. Un formato tipico per il file dell'ordine che utilizzeremo durante le nostre discussioni è mostrato qui:

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

Useremo il modello XML sopra per illustrare gli esempi di Camel in questo tutorial.

Il cammello è una scatola nera che riceve messaggi da un endpoint e li invia a un altro. All'interno della scatola nera, i messaggi possono essere elaborati o semplicemente reindirizzati.

Allora perché avere un framework per questo? In situazioni pratiche, come si è visto nel caso di studio introduttivo, potrebbero esserci molti mittenti e molti destinatari ciascuno seguendo il proprio protocollo come ftp, http e jms. Il sistema potrebbe richiedere molte regole complesse, ad esempio il messaggio del mittente A deve essere consegnato solo a B&C. In alcune situazioni, potrebbe essere necessario tradurre il messaggio in un altro formato previsto dal destinatario. Questa traduzione può essere soggetta a determinate condizioni in base al contenuto del messaggio. Quindi in sostanza potrebbe essere necessario tradurre tra protocolli, incollare i componenti insieme, definire regole di instradamento e fornire filtri in base al contenuto del messaggio. Ciò è illustrato nella figura seguente:

Per soddisfare i requisiti di cui sopra e progettare un'architettura software adeguata per molte di queste situazioni, gli Enterprise Integration Patterns ( EIP ) sono stati documentati da Gregor Hohpe e Bobby Woolf nel 2003. Apache Camel fornisce l'implementazione di questi modelli e lo scopo di questo tutorial è insegnare come usare Camel in situazioni come quella descritta nell'introduzione.

Apache Camel è un framework open source. È un middleware orientato ai messaggi che fornisce un motore di mediazione e routing basato su regole. È possibile definire regole come se si tratta di un ordine "latte" reindirizzarlo a un fornitore di latte e se si tratta di un ordine "olio" reindirizzarlo a un venditore di petrolio e così via. Utilizzando Camel, sarai in grado di implementare queste regole e di eseguire il routing in un codice Java familiare. Significa che è possibile utilizzare il familiare IDE Java per definire queste regole in un ambiente indipendente dai tipi. Non è necessario utilizzare file di configurazione XML, che in genere tendono ad essere ingombranti. Camel supporta la configurazione XML tramite il framework Spring, se si preferisce utilizzare XML per la configurazione delle regole. Puoi anche utilizzare i file di configurazione XML Blueprint e persino un DSL di Scala, se sei un amante di Scala. Significa anche che puoi usare il tuo Java preferito, l'IDE Scala o anche un semplice editor XML per configurare le regole.

L'input a questo motore può essere un file di testo delimitato da virgole, un POJO (Plain Old Java Object), XML sono uno dei tanti altri formati supportati da Camel. Allo stesso modo, l'output del motore può essere reindirizzato a un file, a una coda di messaggi o persino allo schermo del monitor per visualizzare gli ordini inviati ai rispettivi fornitori. Questi sono chiamati endpoint e Camel supporta il pattern EIP di Message Endpoint . Gli endpoint Camel vengono discussi più avanti nel capitolo Endpoint.

Camel viene tipicamente utilizzato con Apache ServiceMix , Apache ActiveMQ e Apache CXF per implementare architetture orientate ai servizi.

Dopo aver visto una panoramica di Apache Camel, esaminiamo ora le sue caratteristiche per vedere cosa offre. Sappiamo già che Apache Camel è un framework Java open source che essenzialmente fornisce un'implementazione di vari EIP. Camel semplifica l'integrazione fornendo connettività a un'ampia varietà di trasporti e API. Ad esempio, puoi facilmente instradare JMS a JSON, JSON a JMS, HTTP a JMS, FTP a JMS, persino HTTP a HTTP e connettività a Microservices. Devi semplicemente fornire endpoint appropriati a entrambe le estremità. Camel è estensibile e quindi in futuro più endpoint potranno essere aggiunti facilmente al framework.

Per collegare tra loro EIP e trasporti, si utilizzano DSL (Domain Specific Languages) come Java, Scala e Groovy. Una tipica regola di routing Java può essere simile a:

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

Questa regola di instradamento carica i file da order directory, crea un messaggio JMS con il contenuto del file e invia quel messaggio a una coda chiamata orderQueue.

Ecco alcune delle caratteristiche più importanti di Camel che potresti trovare utili nello sviluppo di applicazioni Camel:

  • Camel supporta formati di dati collegabili e convertitori di tipi per tali trasformazioni di messaggi, in modo che in futuro possano essere aggiunti nuovi formati e convertitori. Attualmente supporta diversi formati e convertitori popolari; per citarne alcuni: CSV, EDI, JAXB, JSON, XmlBeans, XStream, Flatpack, Zip.

  • Camel supporta linguaggi collegabili per scrivere predicati in DSL. Alcuni dei linguaggi supportati includono JavaScript, Groovy, Python, PHP, Ruby, SQL, XPath, XQuery.

  • Camel supporta il modello POJO in modo da poter collegare Javabeans in vari punti.

  • Camel semplifica i test di sistemi così grandi distribuiti e asincroni utilizzando la messaggistica.

Vediamo ora di capire l'architettura di Camel e vedere come vengono implementate le varie funzionalità.

L'architettura Camel è composta da tre componenti: motore di integrazione e router, processori e componenti. Ciò è illustrato nella figura seguente:

Lo stesso nucleo Camel è molto piccolo e contiene 13 componenti essenziali. Gli altri 80 componenti sono fuori dal nucleo. Questo aiuta a mantenere una bassa dipendenza da dove viene distribuito e promuove le estensioni in futuro. IlComponents il modulo fornisce un file Endpointinterfaccia con il mondo esterno. Gli endpoint sono specificati da URI, comefile:/order e jms:orderQueue che hai visto nell'ultimo capitolo.

Il Processorsviene utilizzato per manipolare e mediare i messaggi tra gli endpoint. Gli EIP che ho citato prima sono implementati in questo modulo. Attualmente supporta oltre 40 modelli come documentato nel libro EIP e altre unità di elaborazione utili.

Il Processors e Endpoints sono collegati insieme in Integration Engine and Routermodulo utilizzando DSL. Durante il cablaggio, è possibile utilizzare filtri per filtrare i messaggi in base a criteri definiti dall'utente. Come accennato in precedenza, hai diverse opzioni per scrivere queste regole. Puoi usare Java, Scala, Groovy o persino XML per questo.

Veniamo ora al componente più importante di Camel, che può essere considerato il nucleo: il CamelContext.

CamelContext fornisce l'accesso a tutti gli altri servizi in Camel come mostrato nella figura seguente:

Vediamo i vari servizi. IlRegistryPer impostazione predefinita, il modulo è un registro JNDI, che contiene il nome dei vari Javabeans utilizzati dall'applicazione. Se usi Camel con la primavera, questa sarà la primaveraApplicationContext. Se usi Camel nel contenitore OSGI, questo saràOSGI registry. IlType converterscome suggerisce il nome contiene i vari convertitori di tipi caricati, che convertono il tuo input da un formato all'altro. È possibile utilizzare i convertitori di tipi incorporati o fornire il proprio meccanismo di conversione. IlComponentsIl modulo contiene i componenti utilizzati dall'applicazione. I componenti vengono caricati tramite rilevamento automatico suclasspathche specifichi. Nel caso del contenitore OSGI, questi vengono caricati ogni volta che viene attivato un nuovo bundle. Abbiamo già discusso diEndpoints e Routesnei capitoli precedenti. IlData formats il modulo contiene i formati di dati caricati e infine il file Languages il modulo rappresenta le lingue caricate.

Lo snippet di codice qui ti darà un'idea di come un file CamelContext viene creato in un'applicazione Camel -

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

Il DefaultCamelContext class fornisce un'implementazione concreta di CamelContext. NeladdRoutes metodo, creiamo un'istanza anonima di RouteBuilder. Puoi creare più fileRouteBuilderistanze per definire più di un instradamento. Ogni route nello stesso contesto deve avere un ID univoco. I percorsi possono essere aggiunti dinamicamente in fase di esecuzione. Una rotta con l'ID uguale a quella definita in precedenza sostituirà la rotta precedente.

Cosa va dentro il RouteBuilder istanza è descritta di seguito.

Itinerari

Il router definisce la regola per spostare il messaggio from ad un toPosizione. UsateRouteBuilderper definire un percorso in Java DSL. Si crea un percorso estendendo il file built-inRouteBuilderclasse. Il percorso inizia con afromendpoint e termina in uno o più endpoint. Tra i due, si implementa la logica di elaborazione. È possibile configurare un numero qualsiasi di percorsi all'interno di un singolo fileconfigure metodo.

Ecco un tipico esempio di come viene creato il percorso:

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

Sostituiamo il metodo di configurazione di RouteBuilderclass e implementare il nostro meccanismo di routing e filtro in esso. Nel caso corrente, reindirizziamo l'input ricevuto dall'endpointDistributeOrderDSL alla console, che è specificata dall'endpoint stream:out.

Scelta della lingua

Puoi creare i percorsi in diverse lingue. Ecco alcuni esempi di come lo stesso percorso è definito in tre lingue diverse:

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"

Filtri

Utilizzare il filtro per selezionare una parte del contenuto di input. Per impostare un filtro, utilizzare qualsiasi implementazione di Predicate arbitraria . L'input filtrato viene quindi inviato all'endpoint di destinazione desiderato. In questo esempio, filtriamo tutti gli ordini per il sapone in modo che possano essere inviati collettivamente a un fornitore di sapone.

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

Nell'esempio abbiamo usato xpathpredicato per il filtraggio. Se preferisci utilizzare la classe Java per il filtraggio, utilizza il codice seguente:

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

Il Order è la tua classe Java personalizzata con il tuo meccanismo di filtraggio.

Puoi combinare più predicati in un unico instradamento come qui -

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

Quindi ora tutti gli ordini di "petrolio" andranno al venditore di petrolio, gli ordini di "latte" andranno al venditore di latte e il resto a un pool comune.

Processore personalizzato

Puoi anche utilizzare l'elaborazione personalizzata. L'esempio seguente crea un processore personalizzato chiamatomyCustomProcessor e lo utilizza nel generatore di percorsi.

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);
   }
};

Puoi utilizzare processori personalizzati insieme alla scelta e al filtro per ottenere un controllo migliore sulla mediazione e sul routing -

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

Utilizzando XML

Le rotte possono essere definite in XML più voluminoso, se lo preferisci. Il seguente frammento XML mostra come creare un percorso insieme ad alcuni filtri tramite 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>

Dopo aver visto come vengono costruite le rotte, vedremo ora le varie tecniche di creazione degli Endpoint.

Abbiamo appreso come appaiono gli endpoint nel nostro codice di integrazione. Le espressioni che abbiamo usato finora comefile:/order, jms:orderQueue, direct:distributeOrderDSLsono gli endpoint. Come puoi vedere, seguono i formati delle specifiche URI. Durante la valutazione di questo URI, ilCamelContext crea il file Endpointesempio; non devi preoccuparti di creare un'istanzaEndpoint implementazione nel tuo DSL.

Prendendo i nostri esempi precedenti, specifichi gli endpoint in Java DSL come qui -

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

E in primavera come qui -

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

In entrambi i casi, l'endpoint è una stringa costante. In alcuni casi, potresti voler costruire questa stringa in fase di esecuzione. Puoi farlo usando JavaStringmetodi di formattazione. Camel fornisce un altro approccio più semplice per creare queste stringhe URI in fase di esecuzione. A tal fine, Camel forniscefromF e toFmetodi che accettano gli argomenti con i parametri specificati dall'utente. La seguente dichiarazione illustra l'uso ditoF metodo -

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

A causa di questi metodi, la necessità di utilizzare Java integrato String metodi di formattazione è ovviata.

Camel utilizza il linguaggio semplice per impostazione predefinita per calcolare l'espressione dell'endpoint. IlSimple il linguaggio è stato progettato principalmente per valutare Expressions e Predicatessenza preoccuparsi molto delle complessità di XPath. Per valutare i predicati, puoi combinare un'altra lingua comexpath con il valore predefinito Simplelinguaggio. Questo viene fatto usando il segno più per separare l'altra lingua. Lo snippet di codice qui mostra come concatenarexpath stringa all'espressione scritta in Simple.

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

Nel Spring, puoi ottenere lo stesso risultato qui -

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

Puoi concatenare tutte le lingue che desideri, ciascuna separata con un segno più dalla precedente. L'elenco delle lingue supportate può essere trovato qui .

Camel fornisce diversi componenti predefiniti.

In questo capitolo, discuteremo alcuni importanti componenti di camel-core modulo.

Fagiolo

Il Beanil componente lega i bean agli scambi di messaggi Camel. L'URI per creare un endpoint è specificato comebean:beanID, dove beanID è il nome del bean come specificato in 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");
   }
});

Nota come viene specificato l'endpoint utilizzando il bean:protocollo. Opzionalmente è possibile specificare il metodo bean che deve essere invocato; in questo caso, il metodo chiamatoplaceOrderverrà richiamato durante la valutazione dell'espressione Endpoint. IlMilkOrder è un nome JNDI per MilkOrderProcessorJavabean come registrato nelle prime due righe dello snippet di codice. La definizione diMilkOrderProcessor stesso è qui omesso per brevità.

Diretto

Avrai notato l'uso di Directnei nostri esempi precedenti. Per inviare un ordine a un venditore di petrolio, abbiamo utilizzatodirect:oilnella specifica Endpoint. L'impiego diDirectconsente di richiamare in modo sincrono un endpoint. I seguenti due frammenti di codice dei nostri esempi precedenti illustrano l'uso diDirect -

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

E,

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

File

Il Filecomponente fornisce l'accesso al file system sulla macchina. Utilizzando questo componente, sarai in grado di salvare i messaggi di altri componenti su un disco locale. Inoltre, consente ad altri componenti Camel di elaborare i file locali. Puoi usare entrambifile:directoryName[?options] o file://directoryName[?options]come formato URI durante l'utilizzo del componente File. Hai già visto l'uso di questo componente:

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

Nota che il Fileil componente per impostazione predefinita prende il nome della directory. Pertanto, il contenuto della directory dell'ordine verrà considerato come contenuto di input. Per specificare un particolare file nel fileorder directory, utilizzerai la seguente dichiarazione:

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

Log

Il Logcomponente consente di registrare i messaggi nel meccanismo di registrazione sottostante. Camel utilizza Simple Logging Facade for Java (SLF4J) come astrazione per vari framework di registrazione. Puoi usarejava.util.logging, logback, log4jper la registrazione. Questo frammento di codice illustra l'uso diLog componente -

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

SEDA

Il SEDA component ti consente di chiamare in modo asincrono un altro endpoint nello stesso CamelContext. Se vuoi chiamare attraverso le istanze di CamelContext, devi usareVMcomponente. L'utilizzo di SEDA è illustrato qui -

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

In questo percorso, indirizzeremo semplicemente gli ordini a nextOrdercoda asincrona. Un client che si è iscritto a questa coda raccoglierà i messaggi da questa coda.

Timer

Il Timerviene utilizzato per inviare messaggi a intervalli regolari e può quindi essere molto utile durante il test delle applicazioni Camel. Lo snippet di codice qui invia un messaggio di prova alla console ogni due secondi:

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

La maggior parte dei progetti di integrazione utilizza la messaggistica in quanto aiuta a creare un'architettura applicativa liberamente accoppiata. La messaggistica può essere sincrona o asincrona. JMS supporta entrambipoint-to-point e publish-subscribeModelli. Usi un fileQueue per punto a punto e Topicper un modello di pubblicazione-sottoscrizione. Su una piattaforma Java, JMS - Java Messaging Service fornisce un'interfaccia a un server di messaggistica. Apache activeMQ è uno di questi provider JMS open source. Camel non viene spedito con un provider JMS; tuttavia, può essere configurato per utilizzare activeMQ. Per utilizzare questo componente, devi includere i seguenti barattoli nel tuo progetto: activemq, camel-spring e camel-jms.

Il seguente frammento di codice mostra come configurare Camel per 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>

Qui, l'applicazione Camel inizierà ad ascoltare una coda chiamata orderQueue. La coda stessa viene configurata nel server di messaggistica activeMQ in esecuzione sull'host locale e viene elencata sulla porta 61000. Una volta eseguita questa operazione, l'applicazione può inviare o ricevere messaggi a questa coda da uno qualsiasi degli endpoint definiti nell'applicazione.

Infine, è giunto il momento di mettere tutto insieme in un progetto per ottenere una comprensione più profonda di come vengono create le applicazioni Camel.

Useremo Maven per costruire un progetto Camel. Tuttavia, è preferibile utilizzare IntelliJ IDE per lo sviluppo. Puoi usare qualsiasi IDE di tua scelta per questo progetto.

Creazione di un nuovo progetto

Crea un nuovo file Maven progetto e specificare quanto segue:

GroupId: Basket
ArtifactId: Basket

Seleziona la posizione predefinita per il tuo progetto o, se preferisci, specifica la directory di tua scelta.

Aggiunta di dipendenze

È necessario aggiungere alcune dipendenze per utilizzare Camel. Le dipendenze vengono aggiuntepom.xml. Quindi apri pom.xml e aggiungi le seguenti due dipendenze:

<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- Abbiamo bisogno delle dipendenze minime per la nostra applicazione. Man mano che utilizzi più componenti Camel dalle sue librerie, dovrai aggiungere le dipendenze corrispondenti in questo file pom.xml.

Creazione di Java DSL

Successivamente, scriverai il tuo codice di filtraggio e instradamento in un DSL Java. Crea una nuova classe Java chiamataDistributeOrderDSL. Aggiungi il seguente codice ad esso -

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();
      }
   }
}

Nel main metodo, prima creiamo CamelContext istanziando un'implementazione predefinita fornita in DefaultCamelContext classe.

CamelContext context = new DefaultCamelContext();

Successivamente, aggiungiamo un percorso creando un file anonymous RouteBuilder istanza -

context.addRoutes(new RouteBuilder() {

Ignoriamo il configure metodo per aggiungere una rotta da un URI diretto DistributeOrderDSLalla console di sistema. Forniamo alcuni filtri utilizzando la query xpath.

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

Dopo aver aggiunto il percorso, iniziamo il contesto:

context.start();

Successivamente, aggiungiamo il codice per creare il nostro URI diretto - DistributeOrderDSL.

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

Infine, iniziamo l'elaborazione -

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

Ora, quando il codice Java DSL è completato, l'unica cosa che rimane prima di testare l'applicazione è aggiungere il file order.xmlfile al tuo progetto. A tale scopo è possibile utilizzare l'XML di esempio mostrato nel capitolo Introduzione.

Risultati del test

Quando esegui l'applicazione, vedrai il seguente output:

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

Nota che qui sono elencati solo gli ordini per i saponi. Se desideri salvarlo in un file locale, commenta semplicemente il filestream.out riga e rimuovere il commento dalla riga seguente nel file configure metodo -

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

Nella nostra sezione successiva, impareremo come usare Camel with Spring.

Ricreeremo ora l'applicazione del capitolo precedente usando Spring. Questo ci darà un'idea di come creare il routing Camel in XML piuttosto che in un DSL.

Creazione di un nuovo progetto

Crea un nuovo file Maven progetto e specificare quanto segue:

GroupId: BasketWithSpring
ArtifactId: BasketWithSpring

Seleziona la posizione predefinita per il tuo progetto o, se preferisci, specifica la directory di tua scelta.

Aggiunta di dipendenze

Oltre alle dipendenze principali utilizzate nell'applicazione precedente, è necessario aggiungere alcune altre dipendenze per utilizzare Spring. Le dipendenze vengono aggiunte in pom.xml. Ora apri pom.xml e aggiungi le seguenti dipendenze:

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

Creazione di Java DSL per la primavera

Creiamo ora una nuova classe Java chiamata DistributeOrderXML. Aggiungi il seguente codice ad esso -

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();
      }
   }
}

Nel main metodo, prima creiamo un'istanza di ApplicationContext, che è l'interfaccia centrale all'interno di un'applicazione Spring. Nel suo costruttore, specifichiamo il nome del file XML che contiene le nostre informazioni di instradamento e filtraggio.

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

Successivamente, creiamo CamelContext specificando quanto sopra creato ApplicationContext nel suo parametro.

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

A questo punto, il nostro routing e filtro è impostato. Pertanto, iniziamo il fileCamelContext usando il suo startmetodo. Come nel caso precedente, definiamo l'endpoint per caricare il file order.xml e avviare l'elaborazione. Ora, vediamo come viene definito il routing in XML.

Creazione del contesto dell'applicazione

Aggiungi un nuovo file XML al progetto e chiamalo SpringRouteContext.xml. Taglia e incolla i seguenti contenuti in questo file.

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

Qui, definiamo la query xpath come segue, nota che ora selezioniamo tutti gli ordini per "oil".

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

Gli endpoint di output sono multipli. Il primo endpoint specifica il fileorder cartella e la seconda specifica la console.

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

Esegui l'applicazione.

Risultati del test

Quando esegui l'applicazione, vedrai il seguente output sullo schermo.

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

Controlla il ordercartella nel percorso specificato dall'utente. Troverai un file appena creato che contiene il codice XML sopra.

Conclusione

Camel fornisce un framework pronto per l'uso che implementa gli EIP per facilitare i tuoi progetti di integrazione. Supporta la codifica in linguaggi specifici del dominio e anche l'uso di XML.