Apache Camel, primeros pasos

7
50725

Apache Camel, primeros pasos

Lo primero, os dejo el enlace a los: fuentes de este tutorial

0. Índice de contenidos.

1­. Introducción

Si hay algo manido, tratado, documentado y reinventado en el mundo de la informática es todo lo relacionado con la integración de aplicaciones.
Si le pegas una patada a una piedra elegida aleatoriamente, probablemente saldrán un par de libros que hablan acerca de este tema. Por eso no me voy a extender demasiado en explicaciones teóricas, y voy a tratar de pasar a la acción lo antes posible.

He tenido la fortuna de elegir «Apache Camel» para un proyecto en el que estado involucrado en estos últimos meses, y la verdad es que ha resultado todo un éxito su elección, y como suelo decir siempre (sin dejar de sorprenderme), completamente «gratis».
Como agradecimiento a los desarrolladores de este framework (y a todos aquellos que hacen software libre) escribo este tutorial (por sirve de algo).
También agradezco a Carlos León que en una charla de café me dijese: «¡ Anda !, para eso que quieres hacer a lo mejor te viene bien Camel (tenía razón).»

2.­ ¿Qué es Apache Camel?

Los que saben explicarlo bien, son los que lo han construido: Web de Apache Camel. No obstante, me voy a atrever a
explicar en pocas palabras lo que es y sus características principales:

  • Framework Java que implementa los principales Patrones EIP (Enterprise Integration Patterns)
  • Muy sencillo de comprender y de utilizar (si conoces Spring, mucho mejor), y muy versátil
  • Incorpora un gran soporte para pruebas automáticas (lo que es de agradecer en este tipo de frameworks)
  • Contiene una gran cantidad de componentes «de serie» y una gran cantidad de «conectores» o «transport» (en dialecto camel)
  • Puede ser un componente muy útil dentro de una arquitectura SOA (como parte del ESB), como mediador entre aplicaciones, o enrutador o … . Algunos ESBs lo incluyen como parte de su core (como por ejemplo ServiceMix)

3.­ Instalando Apache Camel

Error!! No hay nada que instalar. No es una aplicación, sino que es un framework que se integra en cualquier aplicación (web, standalone …).

4.­ Planteando el problema

Para tratar de entender cuales son las capacidades de Apache Camel, os voy a proponer un problema que trataremos de resolver usando este framework.

Resulta que estamos trabajando para una empresa que vende cacharricos electrónicos por Internet usando para ello una pasarela de pago contra «Acme». Cada vez que se realiza un pago, «Acme» envía un mensaje de confirmación del pago o una notificación de error, si se ha producido un error en el proceso.

Nuestro objetivo, es recoger estos mensajes y procesarlos de la siguiente manera:

  • Si el mensaje es una notificación de pago correcto, nuestro objetivo será hacerle llegar el pago al departamento financiero, así como registrar la venta.
  • Si el mensaje es una notificación de pago incorrecto, nuestro objetivo será notificar el error al departamento de atención al cliente, y enviar un correo al
    usuario indicándole el problema que se ha producido.

5.­ Al lío

Vamos a suponer que las notificaciones de ACME nos vienen a través de un POST http, enviando únicamente dos datos: El identificador del usuario, el identificador de la transacción y el resultado de la operación (recordad que es únicamente un ejemplo).
Vamos a crear una aplicación Web (estoy usando Tomcat 7) donde embeberemos toda esta funcionalidad (usando camel), y una jsp que nos servirá para enviar notificaciones de venta.

También vamos a usar colas jms como mecanismo de comunicación. Yo tengo instalado Apache ActiveMQ 5.5.0. Si no queréis usar un gestor de colas, podéis usar el componente SEDA de Camel (son colas en memoria. Bueno, es algo más que eso, pero para el caso es suficiente).

Lo primero es mostraros el pom.xml (únicamente lo interesante…):

	...
	
		
			org.apache.camel
			camel-core
			${camel.version}
		

		
			org.apache.camel
			camel-spring
			${camel.version}
		

		
			org.apache.camel
			camel-servlet
			${camel.version}
		

		
			org.apache.camel
			camel-velocity
			${camel.version}
		
		
		
			org.apache.camel
			camel-mail
			${camel.version}
		
		...
		
		
			org.apache.activemq
			activemq-camel
			5.5.0
		
		...

El web.xml:




  Archetype Created Web Application
  
  
    contextConfigLocation
    classpath:camel-context-tutorial.xml
  

  
  
    org.springframework.web.context.ContextLoaderListener
  

  
  
    CamelServlet
    org.apache.camel.component.servlet.CamelHttpTransportServlet
    1
  

  
  
    CamelServlet
    /camel/*
  
  

El jsp (index.jsp):


	
		

Notifications Generator


Resultado(OK o ERROR):
User:
Transacción:

Y lo realmente importante, el fichero de configuración de camel (si se parece sospechosamente a un fichero de spring, y es porque es un fichero de configuración de Spring, aunque esta no es la única manera de configurar camel). Mostramos lo más interesante unicamente:

	...
	
	
		
		
		
		
	


	
	
		
		
		
         
            com.autentia.tutorial.camel.entity.Payment
         
      
		
		
			
				org.hibernate.dialect.MySQLInnoDBDialect
				true
				create		
			
		
	

	
	
		
	
	
	
		
	
	
	
		
			
			
			
				
					/sale/result = 'OK'
					
				
				
					/sale/result = 'ERROR'
					
				
				
					
				
			
		
	
	...

Básicamente, lo que acabamos de crear es nuestra primera «ruta» (route). La verdad es que se explica por si sola, pero por si acaso:

  • from: ¿ Donde escucha esta ruta ? Pues hemos usado el componente servlet de camel. Básicamente, cada vez que llegue una petición HTTP al servlet, comenzará la ruta.
  • to: Lo primero que hacemos con los mensajes que llegan, es convertirlos a XML. Para esa conversión estamos usando un «transformer» que se basa en plantillas de velocity. Este transformador, recogerá los parámetros del POST y conformará un mensaje XML. Esta es la plantilla de velocity que estamos usando:
  • 
    
    	${headers.result}
    	${headers.user}
    	${headers.transaction}
    
    	
  • to: A continuación, estamos usando un «Content Based Router» usando XPath, es decir, en función de la información del mensaje lo enviaremos a un sitio o a otro.
    En este caso, si el mensaje es de un pago correcto (result=OK), entonces, enviaremos el mensaje a la cola de ActiveMQ «SALES.OK». Si el mensaje es de un pago incorrecto, enviaremos el mensaje a la cola de ActiveMQ «SALES.ERROR». En el caso de que llegue un mensaje sin «result», entonces, escribiremos un fichero en la ruta indicada (tutorial/unknown). InOnly significa que no esperamos respuesta.

Vamos a comprobar que esto funciona.
Arrancamos la aplicación y nos vamos al index.jsp para enviar notificaciones de prueba:

Comprobamos la cola SALES.OK usando la consola de Apache ActiveMQ y vemos que efectivamente ha llegado un mensaje y además, con el formato indicado en la plantilla de velocity (mola!!):

Probemos un mensaje de error:



Comprobamos la cola SALES.ERROR usando la consola de Apache ActiveMQ y vemos que efectivamente ha llegado un mensaje:

Si probáis un mensaje con result diferente a OK o ERROR, veréis que se escribe un fichero en la ruta especificada.

Bueno, no está mal por ahora. Sin pagar un duro y sin «tirar» ni una línea de código, ya tenemos hecho la mitad de lo que nos han pedido.

Sigamos ahora con nuestro negocio. Empecemos por los pagos correctos. Esto es lo que nos dijeron:
«Si el mensaje es una notificación de pago correcto, nuestro objetivo será hacerle llegar el pago al departamento financiero, así como registrar la venta».

Tras hablar con el departamento financiero, ellos necesitan que les notifiquemos vía correo electrónico (cutre, pero es un ejemplo).
Por otro lado, registrar la venta es guardar un registro en una base de datos…

Vamos a añadir una nueva ruta para configurar lo que necesitamos.

...

	
	
		/sale/user
	
	
		/sale/transaction
	
	
		
			
		
		
			
			
		
	

...

Vamos a explicar esta nueva ruta:

  • From: Escucharemos los mensajes que lleguen a la cola SALES.OK
  • A continuación, usando XPath, recogeremos los valores del XML que nos interesan (user y transaction) y los guardaremos como cabeceras
    del mensaje (paymentUser y paymentTransaction). Estas cabeceras permaneceran en el mensaje durante toda la ruta.
  • Multicast: Usamos un enrutador multicast para:
    1. Almacenar en base de datos el registro de la venta. Para eso usaremos un POJO configurado con Spring (paymentRegister)
    2. Enviar un correo electrónico al departamento financiero. Pero antes usaremos velocity como plantilla del correo.

Para almacenar en Base de Datos el pago, he usado hibernate:

La entidad:

@Entity
public class Payment implements Serializable {
	
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue
	private Long id;
	
	private String user;
	private String transaction;
	
	public Payment() {
		// TODO Auto-generated constructor stub
	}
	
	public Payment(String user, String transaction) {
		this.user = user;
		this.transaction = transaction;
	}
	
	
	public Long getId() {
		return id;
	}
	public String getUser() {
		return user;
	}
	public String getTransaction() {
		return transaction;
	}
	
}

El DAO:

public interface PaymentDao {

	@Transactional
	public abstract void storePayment(Payment paymentToStore);

}
@Repository
public class PaymentDaoHibernateImpl extends HibernateDaoSupport implements PaymentDao {
	
	@Autowired
	public PaymentDaoHibernateImpl(SessionFactory sessionFactory) {
		super.setSessionFactory(sessionFactory);
	}
	
	
	@Override
	@Transactional
	public void storePayment(Payment paymentToStore) {
		getHibernateTemplate().save(paymentToStore);
	}
		
}

Y ahora, el componente que registra el Pago:

import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.autentia.tutorial.camel.dao.PaymentDao;
import com.autentia.tutorial.camel.entity.Payment;

@Service
public class PaymentRegister implements Processor {
	
	private final PaymentDao paymentDao;
	
	@Autowired
	public PaymentRegister(PaymentDao paymentDao) {
		this.paymentDao = paymentDao;
	}
	
	@Override
	public void process(Exchange exchange) throws Exception {
			
		final String user = (String) exchange.getIn().getHeader("paymentUser");
		final String transaction = (String) exchange.getIn().getHeader("paymentTransaction");
				
		paymentDao.storePayment(new Payment(user, transaction));
		
	}
	
}

Para enviar el correo, primero usamos velocity para generarlos usando la plantilla:

Dear Financial Department. This is a new Payment:
User: ${headers.paymentUser}
Transaction: ${headers.paymentTransaction}


Best Regards

Si lanzamos un nuevo ejemplo, podéis comprobar como se registra el pago y se envía el correo (siempre y cuando esté todo bien configurado).

El tratamiento de los pagos erróneos os lo dejo a vosotros.

6.­ Conclusiones

Espero que este tutorial os haya servido para comprender un poco que es esto de Camel y donde podría encajar. Mi experiencia personal con Camel ha sido muy buena.
En mi caso, se ha utilizado para la catalogación masiva de ficheros y metainformación asociada a esos ficheros.
Los ficheros y su metainformación se recogía vía FTP. Todos los ficheros y su metainformación eran validados y cargados en distintos repositorios de información, haciendoles pasar un workflow basado en rutas de camel (y hasta ahí puedo leer).

7 COMENTARIOS

  1. Muy interesante. En mi centro estamos trabajando con el ESB de WSO2 para hacer cosas similares, y para el uso de los EAI. Comenzaré un estudio sobre este framework. Gracias.

  2. Como siempre, excelente tutorial!! Felicitaciones!
    En mis proyectos estoy usando JBoss ESB. Es muy completo, pero a veces se queda corto con algunas cosas. Hace tiempo que tengo ganas de probar Apache Camel; el mismo JBoss ESB trae conectores para Camel. Además, a veces hay proyectos en los que no se justifica la implantación de un ESB completo, y Apache Camel parece una solución más liviana.
    Saludos!

  3. Excelente Tutorial, ahora te hago una consulta estoy desarrollando un Servicio Web que va a tener mucha demanda y uno de los requerimientos es que no se puede perder ningún request ya que es un sistema de ventas, Camel me serviría para estos requerimientos?
    Muchas Gracias!!

  4. Está muy bien y el ejemplo es muy didáctico, si lo pudieras poner el código para descargar estaría estupendo.

    Gracias de todas formas

  5. El código hace que el tomcat no arranque. Estoy usando un Tomcat 7 tal y como dice el tutorial, lo despliego en Tomcat pero me lo detiene. ¿Qué puede estar pasando?

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad