Introducción a JMS

11
Introducción a JMS (Java Message Service) 1 . Introducción 2 . Arquitectura de JMS 3 . Aplicaciones punto a punto 4 . Ejemplo de una comunicación punto a punto 5 . Aplicaciones orientadas a suscripción 6 . Ejemplo de una comunicacion orientada a la suscripción 7 . Características mas avanzadas 8 . Mas características avanzadas 9 . JMS en EJB's: Message Driven Bean 10 . Enlaces Introducción JMS es la solución de Sun para los sistemas de mensajes, empecemos por saber que es un sistema de mensajes empresarial: En las comunicaciones cliente servidor, los datos que se intercambian entre las dos partes necesitan de una comunicación sincrona, es decir, que las dos partes esten presentes en el momento de la comunicación. Los sistemas de mensajes aportan una serie de mejoras a la comunicación entre aplicaciones que no tienen por que residir en la misma máquina. JMS se situa como middleware en medio de la comunicación de dos aplicaciones. En entornos cliente servidor, cuando la aplicación A quiere comunicarse con la Aplicación B, necesita saber donde esta B (su IP por ejemplo) y que B esté escuchando en ese momento. Cuando se usa JMS (o cualquier otro sistema de mensajes), la aplicación A envía un mensaje, el sistema de mensajes lo recibe y se lo envía a B cuando se conecte al servicio. De esta manera se consigue una comunicación asíncrona entre A y B, es decir no hace falta que B este presente en el momento del envío del mensaje, y no por ello va a dejar de recibirlo. La anterior es una de las ventajas de JMS, pero no la única. La comunicación anterior tiene dos extremos, el productor (A) y el consumidor (B). JMS soporta otro tipo de comunicaciones que Sun denomina Publisher/Subscriber, traducido seria Publicador (Publicante)/Suscriptor. En este tipo de comunicación, la aplicación A publica su mensaje en el servicio JMS y lo reciben todas las aplicaciones que esten suscritas al servicio JMS al que se envió el mensaje, esta forma de comunicación es exactamente igual que la que se produce el los chats del IRC. Otra de las ventajas de usar JMS (o cualquier otro sistema de mensajes) es que las aplicaciones se pueden cambiar simplemente asegurándose que la nueva aplicación entiende los mensajes que se intercambian. NOTA: Los ejemplos de este artículo han sido probados con JDK 1.3.1 y J2EE 1.3.01, no se asegura que funcionen en otras versiones, sobre todo inferiores. Arquitectura de JMS Una aplicación JMS consta de los siguientes elementos: Clientes JMS Aplicaciones que envian o reciben mensajes a través de JMS Mensajes Los mensajes que se intercambian Objetos administrados Los objetos JMS a los que se dirigen las comunicaciones Objetos administrados Los objetos administrados son el punto al que se comunican los clientes JMS para enviar o recibir mensajes, se denominan objetos administrados por que los crea el administrador (en la implementación de referencia mediante j2eeadmin). Implementan las interfaces JMS y se sitúan en el espacio de nombres de JNDI (Java Naming and Directory Interface) para que los clientes puedan solicitarlos. Hay dos tipos de objetos administrados en JMS: ConnectionFactory: Se usa para crear una conexión al proveedor del sistema de mensajes. Destination: Son los destinos de los mensajes que se envían y el recipiente de los mensajes que se reciben.

Transcript of Introducción a JMS

Introducción a JMS (Java Message Service)1 . Introducción2 . Arquitectura de JMS3 . Aplicaciones punto a punto4 . Ejemplo de una comunicación punto a punto5 . Aplicaciones orientadas a suscripción6 . Ejemplo de una comunicacion orientada a la suscripción7 . Características mas avanzadas8 . Mas características avanzadas9 . JMS en EJB's: Message Driven Bean10 . Enlaces

IntroducciónJMS es la solución de Sun para los sistemas de mensajes, empecemos por saber que es un sistema de mensajes empresarial:En las comunicaciones cliente servidor, los datos que se intercambian entre las dos partes necesitan de una comunicación sincrona, es decir, que las dos partes esten presentes en el momento de la comunicación. Los sistemas de mensajes aportan una serie de mejoras a la comunicación entre aplicaciones que no tienen por que residir en la misma máquina.JMS se situa como middleware en medio de la comunicación de dos aplicaciones. En entornos cliente servidor, cuando la aplicación A quiere comunicarse con la Aplicación B, necesita saber donde esta B (su IP por ejemplo) y que B esté escuchando en ese momento. Cuando se usa JMS (o cualquier otro sistema de mensajes), la aplicación A envía un mensaje, el sistema de mensajes lo recibe y se lo envía a B cuando se conecte al servicio. De esta manera se consigue una comunicación asíncrona entre A y B, es decir no hace falta que B este presente en el momento del envío del mensaje, y no por ello va a dejar de recibirlo.La anterior es una de las ventajas de JMS, pero no la única. La comunicación anterior tiene dos extremos, el productor (A) y el consumidor (B). JMS soporta otro tipo de comunicaciones que Sun denomina Publisher/Subscriber, traducido seria Publicador (Publicante)/Suscriptor. En este tipo de comunicación, la aplicación A publica su mensaje en el servicio JMS y lo reciben todas las aplicaciones que esten suscritas al servicio JMS al que se envió el mensaje, esta forma de comunicación es exactamente igual que la que se produce el los chats del IRC.Otra de las ventajas de usar JMS (o cualquier otro sistema de mensajes) es que las aplicaciones se pueden cambiar simplemente asegurándose que la nueva aplicación entiende los mensajes que se intercambian.NOTA: Los ejemplos de este artículo han sido probados con JDK 1.3.1 y J2EE 1.3.01, no se asegura que funcionen en otras versiones, sobre todo inferiores.

Arquitectura de JMSUna aplicación JMS consta de los siguientes elementos:Clientes JMS Aplicaciones que envian o reciben mensajes a través de JMSMensajes Los mensajes que se intercambianObjetos administrados Los objetos JMS a los que se dirigen las comunicaciones

Objetos administradosLos objetos administrados son el punto al que se comunican los clientes JMS para enviar o recibir mensajes, se denominan objetos administrados por que los crea el administrador (en la implementación de referencia mediante j2eeadmin). Implementan las interfaces JMS y se sitúan en el espacio de nombres de JNDI (Java Naming and Directory Interface) para que los clientes puedan solicitarlos.Hay dos tipos de objetos administrados en JMS:ConnectionFactory: Se usa para crear una conexión al proveedor del sistema de mensajes.

Destination: Son los destinos de los mensajes que se envían y el recipiente de los mensajes que se reciben.

MensajesEs el corazón del sistema de mensajes. Estan formados por tres elementos:

Header: Es la cabecera del mensaje, contiene una serie de campos que le sirven a los clientes y proveedores a identificar a los mensajes. Aquí tines la lista de campos completa :

CampoTipo de

DatoDescripcion

JMSMessageID StringUn numero que identifica univocamente al mensaje. Solo se puede consultar una vez que esta enviado el mensaje.

JMSDestination Destination El destino a donde se envia el mensaje.JMSDeliveryMode int Puede ser de tipo PERSISTENT, entonces se envia una

unica vez, o de tipo NON_PERSISTEN, de manera que se envia como mucho una vez, lo cual incluye tambien que no sea enviado nunca. PERSISTENT y NON_PERSISTENT estan definidas como constantes.

JMSTimestamp long Pues eso, la hora a la que se envio el mensaje.

JMSExpiration longLa hora hasta la cual el mensaje es valido, si es 0 quiere decir que no caduca nunca.

JMSPriority int Prioridad del mensaje de 0 a 9, siendo 0 la mas baja.

JMSCorrelationID StringEste campo se usa para relaccionar una respuesta a un mensaje, se copia aqui el id de mensaje del mensaje al que se esta respondiendo.

JMSReplyTo DestinationEspecifica el lugar a donde se deben enviar las respuestas al mensaje actual.

JMSType StringEste campo lo puede usar el programa de mensajeria para almacenar el tipo del mensaje.

JMSRedelivered booleanIndica que el mensaje ha sido enviado con anterioridad pero el destino no lo ha procesado, por lo que se reenvia.

Properties: Son propiedades personalizadas para un mensaje en particular. Aquí tienes la lista completa:

PropiedadTipo de

DatoDescripcion

JMSXUserID String El usuario que envia el mensaje.JMSXApplID String La aplicacion que envia el mensaje.

JMSXDeliveryCount intEl numero de veces que se ha intentado enviar el mensaje

JMSXGroupID StringIdentificador del grupo al que pertenece el mensaje.

JMSXGroupSeq intNumero de secuencia en el grupo de mensajes.

JMSXRcvTimestamp longLa hora a la que JMS le entrego el mensaje al/los destinatario/s.

JMSXState int Para uso del proveedor de mensajeria.

JMSX_<nombre_del_proveedor> -Reservado para propiedades particulares del proveedor.

Body: Es el mensaje en si, hay distintos tipos:

StreamMessage: Contiene un stream de datos que se escriben y leen de manera secuencial.

MapMessage: Contiene pares nombre-valor.

TextMessage: Contiene un String.

ObjectMessage: Contiene un objeto que implemente la interfaz Serializable.

BytesMessage: Contiene un stream de bytes.

Clientes JMSSon clientes de JMS tanto el que suministra mensajes como el que los recibe. Todos tienen una serie de pasos en común antes de lograr enviar o recibir un mensaje: Conseguir un objeto ConnectionFactory a través de JNDI.

Conseguir un destino, mediante el objeto Destination a través de JNDI.

Usar ConnectionFactory para conseguir un objeto Connection Usar Destination para crear un objeto Session.

Aplicaciones punto a puntoEn las conexiones punto a punto, es decir, con solo dos extremos en la comunicación, el que envía y el que recibe, el destino en el que se reciben los mensajes enviados y de donde se recogen los mensajes recibidos recibe el nombre de Cola de mensajes (en inglés Queue) y actúa como una cola FIFO (el primer mensaje que llega es el primer mensaje que se recoge).Vamos a seguir los pasos que necesita un cliente JMS para conseguir una conexión a una cola de mensajes.

Primero debemos crear un contexto inicial para JNDI:

InitialContext contextoInicial = new InitialContext(); Recuperamos de este contexto el objeto QueueConnectionFactory

QueueConnectionFactory factory =

(QueueConnectionFactory)contextoInicial.lookup("QueueConnectionFactory"); Recuperamos de la JNDI la cola de mensajes

Queue cola = (Queue)contextoInicial.lookup("Cola"); Mediante el metodo createQueueConnection() de factory conseguimos un

objetoQueueConnection.

QueueConnection conexion = factory.createQueueConnection(); El objeto anterior nos sirve ahora para crear una sesión, los parámetros los comentaremos mas tarde:

QueueSession sesion =

conexion.createQueueSession(false,sesion.AUTO_ACKNOWLEDGE);A partir de ahora ya podriamos crear mensajes y enviarlos. Vamos a ver un ejemplo sencillo de una comunicación punto a punto.

Ejemplo de una comunicación punto a puntoPara poder probar los ejemplos, necesitamos tener instalada la J2EE 1.3 o superior (es donde viene la api JMS, en el paquete javax.jms) y el classpath debe incluir a j2ee.jar. Esto será requisito previo para la compilación y ejecución de todos los ejemplos.Antes de compilar y ejecutar los ejemplos, debemos crear los objetos administrados que usaremos en los ejemplos: Ejecutamos el servidor J2EE: j2ee -verbose. Entre el montón de mensajes que imprime, divisamos QueueConnectionFactory, es el

ConnectionFactory por defecto. Crearemos un destino para nuestros mensajes: j2eeadmin -addJmsDestination Cola

queue Esto crea un Destination llamado Cola del tipo queue, comprobamos que esta creado:j2eeadmin

-listJmsDestinationEsta es la clase que envía mensajes a la cola EnviaCola.java:import javax.jms.*;import javax.naming.*;

public class EnviaCola{public static void main (String args[]){

InitialContext contextoInicial = null;QueueSession sesion = null;try {

// Conseguimos de la JNDI los objetos administrados

contextoInicial = new InitialContext();QueueConnectionFactory factory =

(QueueConnectionFactory)contextoInicial.lookup("QueueConnectionFactory");

Queue cola = (Queue)contextoInicial.lookup("Cola");

// Creamos la conexion y la sesionQueueConnection conexion =

factory.createQueueConnection();sesion =

conexion.createQueueSession(false,sesion.AUTO_ACKNOWLEDGE);// Creamos una sesion de envioQueueSender enviaACola =

sesion.createSender(cola);

// Creamos un mensajeTextMessage mensaje =

sesion.createTextMessage();mensaje.setText("Esto es un mensaje");// Lo enviamosenviaACola.send(mensaje);System.out.println("Mensaje enviado: " +

mensaje.getText());// Cerramos la conexionconexion.close();

} catch (NamingException e){e.printStackTrace();

} catch (JMSException e) {e.printStackTrace();

}}

}Esta es la clase que recibe los mensajes de la cola RecibeCola.java:import javax.jms.*;import javax.naming.*;

public class RecibeCola{public static void main (String args[]){

InitialContext contextoInicial = null;QueueSession sesion = null;try {

// Conseguimos de la JNDI los objetos administrados

contextoInicial = new InitialContext();QueueConnectionFactory factory =

(QueueConnectionFactory)contextoInicial.lookup("QueueConnectionFactory");

Queue cola = (Queue)contextoInicial.lookup("Cola");

// Creamos la conexion y la sesionQueueConnection conexion =

factory.createQueueConnection();sesion =

conexion.createQueueSession(false,sesion.AUTO_ACKNOWLEDGE);// Creamos una sesion de recepcionQueueReceiver recibeDeCola =

sesion.createReceiver(cola);// Iniciamos la recepcion de mensajesconexion.start();while (true) {

// Cogemos un mensaje de la cola, el 1 indica que esperara 1 milisegundo

Message mensaje= recibeDeCola.receive(1);

if (mensaje != null){if (mensaje instanceof

TextMessage){// Lo mostramosTextMessage m =

(TextMessage)mensaje;

System.out.println("Recibido mensaje: " + m.getText());}

} else {

// No hay mas mensajesbreak;

}}// Cerramos la conexionconexion.close();

} catch (NamingException e){e.printStackTrace();

} catch (JMSException e) {e.printStackTrace();

}}

}Ahora ya podemos compilar los ejemplos: EnviaCola.java, RecibeCola.java:

javac EnviaCola.javajavac RecibeCola.java

Y ejecutarlos. Primero enviamos un mensaje:java EnviaCola

Y luego recogemos los mensajes de la cola:java RecibeCola

Aplicaciones orientadas a suscripciónEste el otro tipo de aplicaciones que maneja el API JMS. Aqui ya no hay una aplicación que envía y otra que recibe, sino que son varias las aplicaciones que reciben los mensajes, en concreto aquellas que este suscritas a la cola a la que se envian los mensajes.La primera parte de toda aplicación que use JMS es igual, hay que recoger los objetos administrados y crear los objetos de JMS: Primero debemos crear un contexto inicial para JNDI:

InitialContext contextoInicial = new InitialContext(); Recuperamos de este contexto el objeto TopicConnectionFactory

TopicConnectionFactory factory =

(TopicConnectionFactory)contextoInicial.lookup("TopicConnectionFactory"); Recuperamos de la JNDI la cola de mensajes a la que nos suscribiremos:

Topic asunto = (Topic)contextoInicial.lookup("asunto"); Mediante el metodo createQueueConnection() de factory conseguimos un

objetoQueueConnection.

TopicConnection conexion = factory.createTopicConnection(); El objeto anterior nos sirve ahora para crear una sesión, los parámetros los comentaremos mas tarde:

TopicSession sesion =

conexion.createTopicSession(false,sesion.AUTO_ACKNOWLEDGE);Podemos observar que practicamente solo hay que sustituir Queue por Topic.

Ejemplo de una comunicacion orientada a la suscripciónPrimero crearemos los objetos distribuidos que usaremos en los ejemplos. Suponiendo que el servidor J2EE ya esta iniciado:

j2eeadmin -addJmsDestination asunto topicY comprobamos que esta creada:

j2eeadmin -listJmsDestinationEsta es la clase que envia mensajes al asunto EnviaAsunto.java, vemos que es practicamente igual a EnviaCola.java:import javax.jms.*;import javax.naming.*;

public class EnviaAsunto{public static void main (String args[]){

InitialContext contextoInicial = null;TopicSession sesion = null;try {

// Conseguimos de la JNDI los objetos administrados

contextoInicial = new InitialContext();TopicConnectionFactory factory =

(TopicConnectionFactory)contextoInicial.lookup("TopicConnectionFactory");

Topic asunto = (Topic)contextoInicial.lookup("asunto");

// Creamos la conexion y la sesionTopicConnection conexion =

factory.createTopicConnection();sesion =

conexion.createTopicSession(false,sesion.AUTO_ACKNOWLEDGE);// Creamos una sesion de envioTopicPublisher enviaAAsunto =

sesion.createPublisher(asunto);// Creamos un mensajeTextMessage mensaje =

sesion.createTextMessage();mensaje.setText("Esto es un mensaje");// Lo enviamosenviaAAsunto.publish(mensaje);System.out.println("Mensaje enviado: " +

mensaje.getText());// Cerramos la conexionconexion.close();

} catch (NamingException e){e.printStackTrace();

} catch (JMSException e) {e.printStackTrace();

}}

}Esta es la clase que recibe los mensajes del asunto RecibeAsunto.java:import javax.jms.*;import javax.naming.*;

public class RecibeAsunto implements MessageListener{public static void main (String args[]){

new RecibeAsunto().suscribe();}public void suscribe(){

InitialContext contextoInicial = null;TopicSession sesion = null;try {

// Conseguimos de la JNDI los objetos administrados

contextoInicial = new InitialContext();TopicConnectionFactory factory =

(TopicConnectionFactory)contextoInicial.lookup("TopicConnectionFactory");

Topic asunto = (Topic)contextoInicial.lookup("asunto");

// Creamos la conexion y la sesionTopicConnection conexion =

factory.createTopicConnection();

sesion = conexion.createTopicSession(false,sesion.AUTO_ACKNOWLEDGE);

// Creamos una sesion de suscripcionTopicSubscriber suscrito =

sesion.createSubscriber(asunto);// Añadimos nuestro listener para recibir

mensajessuscrito.setMessageListener(this);// Iniciamos la recepcionconexion.start();

} catch (NamingException e){e.printStackTrace();

} catch (JMSException e) {e.printStackTrace();

}}public void onMessage(Message mensaje){

// Se recibe un mensajetry{

// Si es un mensaje de texto, lo mostramosif (mensaje instanceof TextMessage){

TextMessage m = (TextMessage)mensaje;System.out.println("Mensaje recibido: "

+ m.getText());}

} catch (JMSException e){e.printStackTrace();

}}

}Esta clase es un poco diferente al ejemplo anterior. La diferencia mas importante es que esta clase implementa la interfaz MessageListener, que tiene un método (public void onMessage(Message mensaje) que hay que sobreescribir con el codigo que queremos que se ejecute al recibir un mensaje. El resto del codigo es practicamente igual, a excepción de que antes de iniciar la descarga de mensajes con el método start(), debemos indicarle la clase que implementa MessageListener mediante el

método setMessageListener() del objetoTopicSubscriber.

Características mas avanzadasVamos a entrar ahora en características un poco mas avanzadas, la primera es el reconocimiento de mensajes o en inglés Message Acknowledgment. Mediante esta característica un mensaje enviado no se elimina de donde lo tenga guardado la JMS hasta que no sea reconocido por el consumidor de los mensajes. Este reconocimiento se realiza llamando al método acknowledge()del mensaje. Para que sea el cliente el que reconozca los mensajes y no la JMS, hay que crear una sesión con la constante CLIENT_AKNOWLEDGE, como parámetro.Para comprobar esto, podemos enviar mensajes a nuestra cola con el ejemplo anterior,EnviaCola. Y los recogeremos en este caso con RecibeColaReconocimiento.java.Compilamos con javac RecibeColaReconocimiento.java, enviamos un mensaje a la colajava EnviaCola y recibimos varias veces el mensaje con java RecibeColaReconocimiento. Como podemos ver, el mensaje no se elimina de la cola por que no lo estamos reconociendo, para hacer esto ejecutamos java RecibeColaReconocimiento reconoce, de manera que reconocemos el mensaje recibido y las siguientes ejecuciones no recibirán ningun mensaje (ya no existe en la cola) hasta que no se envíe otro.Otra característica avanzada es la capacidad de establecer niveles de prioridad. Para establecer los niveles de prioridad de los mensajes hay dos maneras, invocando el método setPriority de la

interfaz MessageProducer (que la implementan los objetos QueueSender y TopicPublisher) o

invocar la forma larga de los métodos send() y publish() según la conexión sea punto a punto o orientada a la suscripción. Para ver esto, tenemos una clase (EnviaColaPrioridad.java) que envia 10 mensajes a una cola con prioridad aumentando de menor(0) a mayor(9), una vez compilada la clase y enviados los mensajes, podemos ejecutar RecibeCola (invocando java RecibeCola) y ver que se reciben en orden inverso a como se enviaron en correspondencia con los niveles de prioridad asignados.Vamos con otra característica mas, que hemos visto implícitamente en el ejemplo anterior, laduración de los mensajes. A los mensajes se les puede establecer una duración a partir de la cual los mensajes dejan de ser válidos. Para esto podemos usar el método setTimeToLive() de la interfaz MessageProducer o

podemos especificarlo en el método send() o publish()dependiendo del tipo de servicio. Podemos modificar el ejemplo anterior sustituyendo:

enviaACola.send(mensaje,DeliveryMode.NON_PERSISTENT,i,0);por

enviaACola.send(mensaje,DeliveryMode.NON_PERSISTENT,i,1000);De esta manera conseguimos que los mensajes caduquen (y por lo tanto no se distribuyan) si no se solicitan antes de un segundo. El valor del TimeToLive (tiempo de caducidad) se expresa en milisegundos, un valor igual a 0 indica que el mensaje no caduca nunca.En los dos últimos ejemplos anteriores, en el método send() hemos estado usando una constante de la que

no hemos definido su uso, DeliveryMode.NON_PERSISTENT. Pues bien esta constante establece la persistencia del mensaje, hay dos valores posibles,DeliveryMode.NON_PERSISTENT y DeliveryMode.PERSISTENT, que indican si el proveedor de los servicios JMS asegura que el mensaje no se perderá en caso de que falle el servicio. El valorPERSISTENT asegura que el mensaje sera almacenado de una manera estable para poder recuperarse a fallos. Y los NON_PERSISTENT no garantizan esto último. Puede modificar el codigo de los ejemplos anteriores y tomar las medidas oportunas (apagar el servidor de JMS, etc..) para comprobarlo.

Mas características avanzadasEn esta sección vamos a ver dos características mas de JMS, las suscripciones persistentes y lastransacciones.Empezamos por las suscripciones persistentes. Mediante este método conseguimos la versatilidad de las colas en los entornos orientados a la suscripción, conseguimos que alguien suscrito a un asunto en particular, reciba los mensajes enviados mientras no estaba conectado. Para demostar este comportamiento, tenemos cinco clases (cuyo origen no quiero recordar, :)), en todo caso no las he hecho yo), DurableSubscriber.java, es el suscriptor,MultiplePublisher.java, publica los mensajes, TextListener.java, implementa la interfaz MessageListener y sera la que trate los mensajesMonitor.java, monitoriza que el listener no este ocupadoDurableSubscriberExample.java, ejecuta al resto de clases, tiene el método main. La clase principal es DurableSubscriberExample, que invoca al resto de clases. Para poder probar esto, debemos definir un destino para la suscripción persistente: j2eeadmin -addJmsFactory TopicDurable topic -props clientID=MyID.Al compilar las cinco clases y ejecutarDurableSubscriberExample, primero activa el suscriptor, envía 3 mensajes y se reciben, luego desactiva al suscriptor y envía otros 3 mensajes, activa el suscriptor y automáticamente se reciben los mensajes recibidos mientras el suscriptor estaba desconectado.Las Transacciones son un mecanismo por el cual una serie de operaciones se consideran como un todo, lo que quiere decir que o se ejecutan todas correctamente, o no se ejecuta ninguna. Un ejemplo típico de uso de transacciones son las bases de datos de los bancos, cuando se hace un ingreso hay que actualizar varias tablas correctamente o si no la informacion contenida en ellas no sera consistente, imaginemos un traspaso de una cuenta a otra, hay dos operaciones básicas, sacar de una cuenta e ingresar el dinero en otra, si se saca de una cuenta y no se llega a meter en otra tenemos un problema ( y un cliente cabreado ), por lo que el traspaso se considera como una transacción, o se completan todos los pasos con exito o se vuelve atrás, al punto donde se inició la transacción. Las transacciones tienen dos operaciones basicas, commit, que crea una nueva transacción (y termina correctamente la anterior), y rollback, que anula una transacción y deshace las operaciones realizadas durante la misma. Pues bien, en JMS tambien existen transacciones, recordemos como creabamos una sesión:

sesion = conexion.createTopicSession(false,sesion.AUTO_ACKNOWLEDGE);el primer parámetro le indica a JMS que la sesion no soportara transacciones (en realidad cada una de las operaciones es una transicion aceptada). Para que nuestras sesiones con la JMS sean transaccionales llamaremos a este metodo con el primer parámetro a true. Todas las sesiones de JMS, el que envia a una cola, el que recibe de una cola, y sus homólogos en suscripciones, se pueden declarar para que soporten transacciones. Iniciaremos una transacción (y validaremos la anterior) invocando al método commit() de la

interfaz Session y usaremos el métodorollback() de la misma interfaz para deshacer una transaccion.Las clase EnviaColaTrans.java demuestra el uso de transacciones en una cola. Esta clase enviará cuatro mensajes, de los cuales solo deben llegar 2. Podemos recibir los mensajes enviados, con la clase RecibeCola de uno de los ejemplos anteriores.

JMS en EJB's: Message Driven BeanLa especificación 2.0 de EJB introdujo un nuevo tipo de Enterprise Java Bean, el Message Driven Bean. Hasta ahora, para integrar una aplicación J2EE con JMS habia que programar un consumidor de mensajes que hiciese llegar los mensajes que recibiese a un Session Bean, y que fuese este el que los tratase. Esta solución, aparte de añadir una capa mas, no era la mas correcta. Con la inclusión del nuevo tipo de EJB, se consigue que la aplicacion J2EE sea capaz de recibir mensajes JMS y de tratarlos por si misma (con los beneficios que esto conlleva, seguridad, transacciones dentro del servidor de aplicaciones, etc..). Este nuevo tipo de beans, se comporta como un bean de sesión sin estado.Los MDB's (Message Driven Beans), al contrario que los otros tipos de EJB, no tienen implementar ninguna interfaz remota, pues no van a ser utilizados desde fuera del servidor de aplicaciones, por lo que solo hace falta programar el Bean propiamente dicho. Todos los MDB's implementan dos interfaces, MessageDrivenBean, que nos obliga a sobreescribir los

métodos ejbCreate(),ejbRemove() y setMessageDrivenContext. La otra interfaz a

implementar es la ya conocidaMessageListener, teniendo que sobreescribir el metodo onMessage().El enterprise bean se comporta de la misma manera que un cliente normal que recoja mensajes en el servicio JMS, la diferencia es que no tendremos que preocuparnos de conseguir las interfaces de la JNDI, pues de eso ya se encarga el servidor de aplicaciones ( nosostros le indicamos cual sera la factory y el asunto o la cola de la que debe recibir mensajes). El archivoMensajeBeanCola.java contiene un MDB que consulta la cola que hemos

estado usando hasta ahora y si tiene mensajes, imprime su contenido en pantalla. Puede observar que solo se ha escrito codigo para el metodo onMessage(), es el que nos interesa.Una vez compilada la clase, tenemos que hacer el deploy del EJB en el servidor de aplicaciones, yo he escogido la implementacion de refrencia de Sun, el J2EE, los pasos son los siguientes (previamente tenemos que tener iniciado el servidor J2EE, j2ee -verbose:

Ejecutar el deploytool: <ruta a j2ee>indeploytool Cree una aplicación nueva, o añada un nuevo ejb a una aplicación que ya tuviese creada En la ventana New Enterprise Bean Wizard dele un nombre a su ejb (MessageBean esta

bien) y añada la clase compilada pulsando en el botón edit... Pulse Next y en la ventana que le aparece, indique que es un Message Driven Bean y seleccione la

clase que añadió anteriormente de la lista desplegable Enterprise Bean Class Pulse Next e indique que la persistencia será proporcionada por el bean, Bean Managed Persistence Pulse Next, y marque la casilla Queue y seleccione en las listas desplegables, Cola,

QueueConnectionFactory y AUTO_ACKNOWLEDGE. Pulse Next varias veces hasta que llegue a la ventana de seguridad, aqui seleccione Use Caller ID,

pulse Next y Finish. Ya ha añadido un MDB al servidor. Solo queda hacer el deploy, pulse tools-deploy. No necesita que le devuelva un jar de cliente.Si todo ha ido bien, ya tiene su MDB dispuesto a recibir mensajes. Para esto ejecute una de las primeras clases que hemos programado, EnviaCola, para enviar mensajes a la cola, y compruebe (en la consola donde ejecuto j2ee -verbose) que se muestran los mensajes recibidos.Si en lugar de recibir mensajes de una cola, los quisiesemos recuperar de un asunto (con una suscripción) solo tenemos que indicarlo en el deploy.

EnlacesArchivo zip con los fuentes de los ejemplos: ejemplos_jms.zipEspecificación de Java Message Service de Sun: http://java.sun.com/products/jms/jms1_0_2-spec.pdfLibro sobre JMS de Richard Monson-Haefel: http://www.store.yahoo.com/titan-books/javmesser.htmlJava Enterprise Edition, J2EE: http://java.sun.com/j2ee/