cerrar-sesion editar-perfil marker video calendario monitor periodico fax rss twitter facebook google-plus linkedin alarma circulo-derecha abajo derecha izquierda mover-vertical candado usuario email lupa exito mapa email2 telefono etiqueta

400510303. Servicio de Mensajes en Java

Escrito por Redacción en Secciones
no hay comentarios Haz tu comentario
Imagen de logotipo de facebook Imagen de logotipo de Twitter Imagen de Logotipo de Google+ Imagen de logotipo de Linkedin

En la computación distribuida, muchos componentes de software en un sistema en funcionamiento pueden estar separados geográficamente. La necesidad de comunicación entre estos componentes es obvia y esa necesidad guía muchas de las decisiones en materia de diseño del software. Por ejemplo, podemos elegir usar CORBA, SOAP o middleware orientado a mensajes para la comunicación entre componentes.

El desarrollo de servicios SOAP basados en web continúa creciendo, y usa XML y HTTP para eliminar los detalles de implementación de las invocaciones remotas a procedimientos. Pero aunque SOAP ha abierto nuevas perspectivas a la computación distribuida, el middleware orientado a los mensajes, como Java Message Service (JMS) sigue siendo mi herramienta preferida cuando mis principales prioridades son la fiabilidad, la funcionalidad y la seguridad.

((Todo sistema de mensajería consiste en un componente intermediario que es el responsable de hacer llegar los mensajes entre los distintos componentes))

JMS es una especificación (java.sun.com/products/jms) que describe las propiedades y el comportamiento de un conducto de información para el software Java. También describe cómo las aplicaciones cliente de Java interactúan con el conducto de información. En el presente artículo, voy a examinar conceptos de mensajería y a implementar una aplicación JMS.

¿Qué es la mensajería?

El concepto de mensajería comienza con el objetivo de hacer llegar datos. La mensajería empresarial forma la base de una infraestructura dedicada a la comunicación entre componentes dispares de sistemas de software distribuidos. Los componentes importantes en los sistemas de mensajería –productores, consumidores y los mensajes mismos– se compendian mediante interfaces.

El resultado es un conjunto de componentes ligeramente emparejados que forman parte de un sistema cohesivo de software. Los componentes que están ligeramente emparejados tienen las mínimas interacciones posibles entre ellos.

Este aislamiento lleva a un software más sólido, ya que los cambios que se realizan en una parte del sistema no se deslizan a otras partes. Un buen sistema de mensajería hace este aislamiento compendiando los componentes de uno a otro dentro del sistema. (Para más información, véase mi libro Java Messaging, Delmar-Thomson Learning Inc., 2006.)

Todo sistema de mensajería consiste en un componente intermediario que es el responsable de hacer llegar los mensajes entre los distintos componentes, interactuando con el sistema de mensajería. Los intermediarios de mensajería normalmente tratan a los mensajes como algo opaco, lo que significa que tienden a ignorar el contenido del mensaje.

De hecho, un intermediario no necesita saber el propósito o el contenido de un mensaje para hacerlo llegar. Por su parte, los componentes de software que envían/reciben los mensajes no necesitan saber cómo se hace llegar el mensaje, o qué componentes los envían. Lo importante es que se envíen y se reciban con fiabilidad.

Paradigmas de mensajes JMS

JMS da soporte a dos paradigmas principales de mensajes:
– Mensajería de punto a punto (o basada en cola)
– Mensajería de publicación y suscripción (o basada en tema)
JMS puede dar soporte al concepto de mensajería de “solicitud y respuesta” a través de estos dos dominios de mensajería.

((La clase EmailSender inicializa la sesión JMS en su constructor, y contiene un método adicional))

La mensajería de “solicitud y respuesta” es una forma frecuente de comunicación entre cliente y servidor, en la que un cliente hace una solicitud al servidor, y el servidor envía de vuelta una respuesta.

Una de las implementaciones más conocidas de este paradigma es la comunicación entre un navegador web y un servidor web; véase la Figura 1. En este intercambio, el cliente envía una solicitud al servidor, y el servidor responde con los datos solicitados.

Mensajería basada en cola

El dominio punto a punto de JMS, también conocido como mensajería basada en cola, o “almacenar y enviar”, se usa normalmente cuando se necesita procesar mensajes sin conexión. El ejemplo clásico es un sistema de correo electrónico.

Si estamos conectados y llega un correo, lo vemos inmediatamente y lo podemos leer. Si cerramos el sistema, nuestro correo se almacena con total seguridad y fiabilidad para que lo veamos más tarde (véase la Figura 2).

Cuando la aplicación lector de correos no está en funcionamiento, los mensajes de correo enviados se almacenan con total seguridad. Una vez que se inicia la aplicación lector de correos, se hacen llegar los mensajes.

La bandeja de entrada de correos es, básicamente, una cola. Cuando los usuarios inician la aplicación lector de correos, se entregan los mensajes que se habían guardado en la cola. La presentación visual de la aplicación de correos debería indicar que hay nuevos mensajes, y los usuarios los pueden ver (véase la Figura 3).

Una vez entregado, el mensaje se elimina de la cola de “bandeja de entrada”. Puede ser colocado en otra cola que contenga mensajes ya leídos, o puede ser totalmente eliminado. Esa decisión es específica de la aplicación, aunque los mecanismos de la cola son los mismos para todas las aplicaciones.

En JMS, una cola se representa con una interfaz javax.jms.Queue, que extiende la interfaz Destination y, o bien está definida por un administrador o por la aplicación cliente en el tiempo de ejecución. Uno o más productores de mensajes pueden colocar mensajes en la misma cola, y uno o más consumidores de mensajes pueden conectar a una cola para recibir mensajes.

Sin embargo, cada mensaje se entrega a un solo consumidor. Tener a múltiples consumidores conectados a la misma cola contribuye a equilibrar la carga de procesado de mensajes, o garantiza que si falla un consumidor, hay otro allí para continuar procesando los mensajes y sacándolos de la cola. En cualquier caso, el comportamiento es el mismo, cada mensaje en la cola se procesa exactamente una vez.

Una cola tiene la ventaja añadida de que almacena mensajes incluso cuando no hay disponible ningún consumidor pendiente de su recepción. Esta característica, combinada con el comportamiento de procesado de exactamente una vez que tiene la cola, hace que JMS sea la elección frecuente cuando se quiere una mensajería eficiente de punto a punto en los sistemas de software distribuidos.

Muestra de aplicación remitente de correo

La aplicación de cola que presento aquí incluye dos aplicaciones de cliente JMS – una que envía mensajes de correo simulados a una bandeja de entrada de correos, y otra que lee los mensajes de correo y los saca de la cola.

La clase EmailSender del Listado número 1 es un productor de mensajes que envía mensajes a una bandeja de entrada de correos simulada, que es sencillamente una cola JMS, que es leída por la aplicación lector de correos en un momento posterior. (El código fuente completo para la aplicación remitente/lector está disponible online; véase www.ddj.com/code/.)
La clase EmailSender inicializa la sesión JMS en su constructor, y contiene un método adicional que permite al invocador enviar mensajes de correo a la cola que representa la bandeja de entrada de correo simulada.

En el constructor, el primer paso es usar Java Naming and Directory Interface (java.sun.com/products/jndi) para obtener acceso al objeto javax.jms.ConnectionFactory del proveedor de JMS. Los detalles JNDI específicos del proveedor normalmente están colocados dentro de un fichero de configuración denominado jndi.properties. La Java VM automáticamente busca la presencia de este fichero cuando instanciamos la clase InitialContext.

Una vez que se obtiene el objeto ConnectionFactory, una invocación a su método createConnection retorna un objeto javax.jms.Connection de JMS. Este objeto representa una conexión real con el proveedor de JMS.

Como está a prueba de hilos y consume una importante cantidad de recursos del sistema para su mantenimiento, nuestra aplicación sólo debería necesitar un objeto Connection activo durante su ciclo de vida. La apertura de múltiples conexiones a un proveedor de JMS es normalmente innecesario y un desperdicio de recursos.

[(

Listado 1


package emaildemo;

import javax.jms.*;

import javax.naming.*;

public class EmailSender

private Connection connection = null;

private Session session = null;

private MessageProducer prod = null;

public EmailSender()

try
InitialContext jndi = new InitialContext();
// Lookup a JMS connection factory
ConnectionFactory conFactory =
(ConnectionFactory)jndi.lookup("ConnectionFactory");
// Create a JMS connection
connection = conFactory.createConnection("","");
// Create a JMS session object
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Get the JMS queue that represents the simulated inbox
Destination inbox = (Destination)jndi.lookup("Inbox");
if ( inbox == null )
inbox = session.createQueue("Inbox");
// Create a producer to place messages into the inbox
prod = session.createProducer(inbox);
// The Connection must be started for messages to fly
connection.start();

catch ( Exception e )
e.printStackTrace();


public void sendEmail(String subject, String body) throws Exception
...
public static void main(String() args)
...

)]

A continuación, mediante una invocación al método createSession del objeto Connection, el código crea un objeto javax.jms.Session. Un objeto Session representa una sesión de mensajes en funcionamiento, y sólo puede ser utilizada por un hilo a la vez dentro de nuestro código.

Por lo tanto, deberíamos crear un objeto Session en nuestra aplicación para cada hilo productor y consumidor de mensajes. El objeto Session se utiliza como una fábrica para crear objetos javax.jms.Destination, javax.jms.Producer, javax.jms.Consumer, y javax.jms.Message.

El objeto Session se utiliza para crear una referencia a la cola de la “Bandeja de Entrada” buscándola mediante JNDI y la crea en tiempo real si no la encuentra. A continuación, se crea un productor de mensajes para la cola de la “Bandeja de Entrada”, que se utiliza para enviar mensajes de correo simulados. Por último, se hace una invocación al método start del objeto Connection para que inicie el flujo de mensajes para la cola (y todos los destinos creados mediante esta conexión JMS).

La aplicación ejemplo instancia la clase EmailSender (disponible online) e invoca su método sendEmail para simular el envío de dos mensajes de correo individuales a la cola de la “Bandeja de Entrada”. El método sendEmail primero crea un objeto tradicional de Java (POJO) que representa al mensaje de correo, de la clase Email.

A continuación, se usa el objeto Session (que se creó en el constructor) para crear un objeto javax.jms.ObjectMessage que a su vez se usa para encapsular el Email POJO. Por último, el mensaje JMS se envía de verdad mediante una invocación al método send que está en el objeto Producer de la cola.

Al ejecutar la aplicación de envío de mensaje se obtiene el resultado que aparece en la Figura 4. Como la bandeja de entrada simulada se implementa como una cola JMS, la aplicación del lector no necesita estar funcionando al mismo tiempo que el remitente.

Todos los mensajes enviados a la cola permanecerán en la cola hasta que la aplicación lector los ejecute y elimine.

Muestra de aplicación lector de correo

La aplicación del lector realiza muchos de los pasos que realiza el remitente en términos de inicializar su conexión y sesión JMS. Las diferencias están en que:
– El constructor crea un objeto javax.jms.MessageConsumer para la cola de la “Bandeja de Entrada” porque su propósito es recibir, o consumir, mensajes.
– La aplicación lector implementa la interfaz javax.jms.MessageListener y le da el objeto resultante al proveedor de JMS mediante una invocación al método setMessageListener del objeto MessageConsumer.

Una vez inicializado, la aplicación es libre de continuar con su propio procesado. En el caso de una aplicación real de cliente de correo, esto puede implicar el permitir que los usuarios compongan nuevos mensajes de correo, que organicen el correo existente en carpetas, etc.

El proveedor, al cabo de un tiempo, invoca de nuevo al objeto MessageListener de la aplicación cuando llega un nuevo mensaje. Esta es la forma en la que JMS implementa la mensajería asíncrona, que permite que la aplicación cliente realice otras tareas mientras espera que lleguen los mensajes.

((En el caso de una aplicación real de cliente de correo, esto puede implicar el permitir que los usuarios compongan nuevos mensajes de correo, que organicen el correo existente en carpetas))

JMS también da soporte a la mensajería sincrónica, que necesita que la aplicación del cliente (o uno de sus hilos hijo) se bloquee hasta que llegue el mensaje. Este tipo de aplicación es estrictamente una aplicación controlada por eventos, lo que quiere decir que no puede hacer nada a no ser que se produzcan determinados eventos; en este caso, la llegada de un mensaje JMS. Este tipo de aplicación se puede desarrollar para que responda de manera distinta a distintos mensajes recibidos, y puede, de hecho, ser controlada de forma remota mediante el envío de los mensajes adecuados en el orden adecuado.

Una vez más, se invocó el método setMessageListener con una referencia a un objeto que implementa la interfaz MessageListener. Debido a ello, una vez que se inicia la conexión JMS, el proveedor invoca de forma asíncrona el método onMessage de la aplicación cliente cuando llega el mensaje para el destino en el que está el consumidor esperando; véase la implementación onMessage de la clase EmailReader (disponible online).

Se proporciona el objeto javax.jms.Message como parámetro para el método onMessage, que representa el mensaje JMS recibido. Una vez se asigna el mensaje a un objeto javax.jms.ObjectMessage, se extrae el Email POJO mediante una invocación getObject. Sólo con fines ilustrativos, el resto del código simplemente imprime el asunto y el cuerpo del correo.

Cuando se ejecuta esta aplicación, recibe, uno a uno, todos los mensajes que fueron colocados con anterioridad en la cola por una aplicación remitente de correos. Una vez se han recibido todos los mensajes, la aplicación simplemente espera a ser notificada de que se ha colocado otro mensaje en la cola.

Conclusión

La escritura de aplicaciones cliente JMS es sencilla una vez que entendemos sus fundamentos. El poder de JMS reside en su capacidad para potenciar la gestión de las transacciones insertadas y la entrega eficiente de mensajes, sin tener que saber mucho más que los fundamentos. DDJ

Etiquetas

Noticias relacionadas

Comentarios

No hay comentarios.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

Debes haber iniciado sesión para comentar una noticia.