Ejemplo De JMS

De Dos Ideas.
Revisión del 18:17 31 jul 2008 de Admin (discusión | contribuciones) (Ahora cocinamos las tostadas)
Saltar a: navegación, buscar

Haciendo tostadas

Vamos entonces a hacer que nuestras aplicaciones Dib y Gaz se comuniquen con una cola de mensajes. Lo que haremos a continuación será:

  • Crear una cola en WebLogic (la heladera para pegar los mensajes)
  • Crear una aplicación que publique mensajes en la cola (Dib)
  • Crear un EJB que consuma los mensajes de la cola (Gaz)

Creando la cola en WebLogic 8.1

Lo primero entonces será de crear la cola para que nuestras aplicaciones pueda interactuar. Para esto crearemos la cola propiamente dicho, y un factory que se conecte a la misma. Todo esto se realiza desde la consola de WebLogic. Creando el Connection Factory

  1. Abran la consola de WebLogic
  2. Vayan a Services -> JMS -> Connection Factories
  3. Click en el link "Configure a new JMS Connection Factory..."
  4. En el campo Name ponemos "Heladera Connection Factory"
  5. En el campo JNDI Name ponemos "HeladeraCF".
  6. Click en el botón "Create"

Con esto tenemos creado un Connection Factory bajo el nombre JNDI de HeladeraCF. El publicador (Dib) utilizará este Connection Factory para tener acceso a la cola y poder publicar mensajes. Creando la cola

  1. Vayan a Services -> JMS -> Servers
  2. Abrir el nodo con el nombre similar a "WSStoreForwardInternalJMSServermyserver"
  3. Click en el nodo "Destinations"
  4. Click en "Configure a new JMS Queue..."
  5. En el campo Name ponemos "Heladera Queue"
  6. En el campo JNDI Name ponemos "HeladeraQueue"
  7. Click en el botón "Create"

Con esto tendremos creada la cola de mensajes bajo el nombre JNDI !HeladeraQueue. Así, Dib podrá publicar mensajes aquí, que luego serán tomados por Gaz.

Dib pega mensajitos en la Heladera

... o lo que es lo mismo, vamos a crear una aplicación que se conecte a la cola y postee mensajes.

Vamos entonces a hacer una clase muy simple que tenga un método "pedirTostadas" que se conecte a la cola y envie un mensaje de texto indicando cuantas tostadas queremos.

 import javax.jms.*;

 public class Dib {
     public final static String JNDI_FACTORY="weblogic.jndi.WLInitialContextFactory";
     public final static String PROVIDER_URL="t3://localhost";

     public final static String JMS_FACTORY="!HeladeraCF";
     public final static String QUEUE="HeladeraQueue";

     public void pedirTostadas() {
         //Obtenemos el InitialContext
         Hashtable env = new Hashtable();
         env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
         env.put(Context.PROVIDER_URL, PROVIDER_URL);
         InitialContext ctx = new InitialContext(env);

          //Buscamos el factory y la conexion a la cola
          QueueConnectionFactory qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);
          QueueConnection qcon = qconFactory.createQueueConnection();
 
          //Buscamos la cola
          QueueSession qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
          Queue queue = (Queue) ctx.lookup(QUEUE);

          //Creamos el mensaje
          TextMessage msg = qsession.createTextMessage();
          msg.setText("Gaz, quiero 4 tostadas");

          //Enviamos el mensaje
          QueueSender qsender = qsession.createSender(queue);
          qsender.send(msg);

          //somos prolijos y cerramos todo
          qsender.close();
          qsession.close();
          qcon.close();
     }
 }

Para enviar mensajes a la cola, basta con ejecutar:

Dib dib = new Dib();
dib.pedirTostadas();

Con esto, Dib enviará un mensaje a la cola (HeladeraQueue). Ahora, no hay nadie consumiendo de dicha cola, por lo cual los mensajes se iran acumulando. Así que vayamos a despertar a Gaz para que pueda ayudar a su hermano... Gaz hace las tostadas

Nos queda entonces consumir los mensajes de una cola. La manera más facil de consumir mensajes es a través de un EJB MDB (Message-Driven Bean). Los EJB MDB son un tipo especial de EJB que cumplen con un único método: onMessage(Message msg)

El método onMessage se invoca cada vez que hay algún mensaje para atender. En la configuración del EJB (los queridos descriptores) se le indica a qué cola está asociado el EJB.

Crearemos entonces a Gaz como un EJB MDB. Para esto podremos usar algún módulo EJB de Bacabs.

Creando nuestro Bean MDB

Un EJB MDB está compuesto por una única clase que implementa las interfaces MessageDrivenBean y MessageListener. Creemos entonces nuestro EJB:

 public class GazMDBBean implements MessageDrivenBean, MessageListener {

     public void setMessageDrivenContext(MessageDrivenContext aContext) {
         context = aContext;
     }

     public void ejbCreate() { }
     public void ejbRemove() { }

     public void onMessage(Message aMessage) {
          !TestMessage txtMessage = (!TextMessage) aMessage;
          String mensajeDeDib = txtMessage.getText();
          System.out.println(mensajeDeDib);
     }
 }

Y esto es todo lo que programaremos para atender el mensaje. Simple, no? Bueno, en realidad falta la magia de los XML.

Creando el ejb-jar.xml

Como todo EJB2, necesita de su descriptor correspondiente. El mismo es bastante simple:

 <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd">

 <ejb-jar>
     <display-name>Gaz MDB</display-name>

     <enterprise-beans>
         <message-driven>
             <ejb-name>GazMDBBean</ejb-name>
             <ejb-class>com.zim.mdb.GazMDBBean</ejb-class>
             <transaction-type>Container</transaction-type>
             <message-driven-destination>
                 <destination-type>javax.jms.Queue</destination-type>
             </message-driven-destination>
         </message-driven>
     </enterprise-beans>

     <assembly-descriptor>
         <container-transaction>
             <method>
                 <ejb-name>GazMDBBean</ejb-name>
                 <method-name>*</method-name>
             </method>
             <trans-attribute>Required</trans-attribute>
         </container-transaction>
     </assembly-descriptor>
 </ejb-jar>

Creando el weblogic-ejb-jar.xml

Y como todo EJB que hacemos para WebLogic, este es el descriptor hermanito del anterior. Contiene configuración propia para WebLogic, y los datos de la cola de la cual consumirá mensajes nuestro EJB MDB. El archivo es muy simple:

 <?xml version="1.0"?>
 <!DOCTYPE weblogic-ejb-jar PUBLIC "-//BEA Systems, Inc.//DTD WebLogic 8.1.0 EJB//EN" "http://www.bea.com/servers/wls810/dtd/weblogic-ejb-jar.dtd">

 <weblogic-ejb-jar>
     <weblogic-enterprise-bean>
         <ejb-name>GazMDBBean</ejb-name>
             <message-driven-descriptor>
                 <pool>
                     <max-beans-in-free-pool>200</max-beans-in-free-pool>
                     <initial-beans-in-free-pool>20</initial-beans-in-free-pool>
                 </pool>
                 <destination-jndi-name>!HeladeraQueue</destination-jndi-name>
             </message-driven-descriptor>
             <enable-call-by-reference>True</enable-call-by-reference>
     </weblogic-enterprise-bean>

 </weblogic-ejb-jar>

En el tag destination-jndi-name indicamos la cola de la cual consumirá mensajes nuestro EJB.

Probando (finalmente)

Empaquetamos y hacemos un deploy de nuestro EJB en WebLogic, y el mismo comenzará a consumir los mensajes de la cola automágicamente.

No solo consumirá los mensajes nuevos, sino también todos aquellos que hayan quedado encolados sin procesar.

Prueben generar muchos mensajes con Dib, y vean como se van procesando. O hagan un stop de Gaz, y vean como al volver a levantarlo procesa todos los mensajes que fueron encolado.

Consumiendo mensajes con JMS

El API de JMS nos da tambien las herramientas para consumir los mensajes de dicha cola. A continuación un ejemplo sencillo de como hacerlo.

Ahora cocinamos las tostadas

Vamos a seguir con el ejemplo dado anteriormente

Se quiere cocinar las tostadas que pidio Dib, sin utilizar a Gaz (EJB) dado a que no las prepara del todo bien (amarretea con la mermelada). El competidor para cocinar es Tak (tuve que buscar personajes de la serie). Con un código similar al que Dib utilizaba para pedir las tostadas, aca esta el ejemplo:

 import javax.jms.*;

 public class Tak {

     public final static String JNDI_FACTORY = "weblogic.jndi.WLInitialContextFactory";
     public final static String PROVIDER_URL = "t3://localhost:7001";
     public final static String JMS_FACTORY = "HeladeraCF";
     public final static String QUEUE = "HeladeraQueue";

     public TextMessage cocinarTostadas() throws NamingException, JMSException {
         // Obtenemos el InitialContext
         Hashtable env = new Hashtable();
         env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
         env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
         env.put(Context.PROVIDER_URL, PROVIDER_URL);
         InitialContext ctx = new !nitialContext(env);

         // Buscamos el factory y la conexion a la cola
         QueueConnectionFactory qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);
         QueueConnection qcon = qconFactory.createQueueConnection();

         // Buscamos la cola
         QueueSession qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
         Queue queue = (Queue) ctx.lookup(AUTO_ACKNOWLEDGE);
         Queue queue = (Queue) ctx.lookup(QUEUE);

         QueueReceiver qreceiver = qsession.createReceiver(queue);

         //"Inicio" la QueueConnection
         qcon.start();
         TextMessage msg = (TextMessage) qreceiver.receive();

         qreceiver.close();
         qsession.close();
         qcon.close();
         return msg;
     }
 }


La unica diferencia con Dib es que se crea un Receiver, que va a ir a buscar los mensajes a la cola. Y ademas hay que darle un start a la QueueConnection.

Testear la coccion de tostadas

Para testear la coccion de tostadas:

 public void testCocinarTostada() throws NamingException, JMSException{

     Tak tak = new Tak();
     TextMessage txtMessage = tak.cocinarTostadas();

     String mensajeDeDib;

     try {
         mensajeDeDib = txtMessage.getText();
         System.out.println(mensajeDeDib);
         txtMessage.acknowledge();
     } catch (JMSException e) {
            e.printStackTrace();
     }
 }

Claro que antes de correr el test, la cola debe tener algun mensaje, sino se va a quedar esperando en el receive() hasta que la cola tenga alguno. Esto se puede evitar usando:

  • receive(long i) : Espera por un mensaje i milisegundos.
  • receiveNotWait() : Si no hay mensajes, no se queda esperando.

Y un agregado mas: En el caso de que hayan probado hacer el EJB para consumir la cola, tengan el detalle de bajarlo del server, porque si no cuando subamos un mensaje a la cola, probablemente se lo lleve el EJB antes que Tak.


Ver también