Mejoras en la Versión 2.1 de la Especificación EJB

En esta página:


El Bean Dirigido a Mensaje Mejorado

Introducción

El bean dirigido a mensaje ha experimentado algunas mejora importantes que lo hacen más útil y flexible que lo era en EJB 2.0. Esto es decir mucho, porque como un tiempo de bean enterprise el bean dirigido a mensaje podría ser uno de los componentes más importantes de la plataforma J2EE. Los beans dirigidos a mensaje permite a los programadores procesar mensajes asíncronos de forma eficiente, y estos actúan como un gateway de mensajería para la plataforma J2EE. En un momento en que la mensajería asíncrona está ganando reconocimiento como un paradigma de programación poderoso, la expansión de MDB a nuestro tipos de sistemas de mensajería es saludable.

Esta página cubre el nuevo MDB (Message-Driven Bean) basado en conector, que nos permite usar MDBs con cualquier tipo de sistema de mensajería, no sólo JMS. Además cubre las propiedades de activación-configuración usadas en el despliegue de MDBs, así como las nuevas facilidades en enlaces de mensajes de EJB 2.1.

Beans Dirigidos a Mensaje Basados en Connector

El bean dirigido a mensaje se presentó en EJB 2.0 para soportar el procesamiento de mensajes asíncronos desde un proveedor Java Message Service (JMS). EJB 2.1 amplía la definición de bean dirigido a mensaje para que pueda soportar cualquier tipo de mensajería, no sólo JMS. Esta sección examina el soporte que proporciona la arquitectura Connector de J2EE para varios proveedores de JMS así como para sistemas de mensajería no-JMS.

Aunque el MDB basado en JMS de EJB 2.0 había resultado muy útil, tenía limitaciones. Quizás la mayor era que los vendedores de EJB sólo soportaban un pequeño número de proveedores JMS (normalmente sólo uno). De hecho, muchos vendedores EJB 2.0 sólo soportaban su propio proveedor JMS, y no los de otros, lo que limitaba severamente las elecciones. Si, por ejemplo, nuestra compañía o una compañía amiga usa un proveedor de JMS que no puede soportar nuestro vendedor EJB, no podremos procesar los mensajes de ese proveedor.

La raíz del problema es compleja y requiere un entendimiento profundo del control de transacciones. En resumidas cuentas, la entrega del mensaje por el proveedor JMS al MDB, y todo el trabajo realizado por el MDB (usar JDBC, llamar a métodos de otros beans, etc.), debe ser parte de la misma transacción. Como el contenedor EJB inicia la transacción, debe tener un conocimiento previo de que la entrega del mensaje es inminente, para que la transacción se puede empezar antes que el mensaje llegue realmente. Desafortunadamente, el API JMS no soporta este tipo de funcionalidades, por eso, en EJB 2.0, se necesita código personalizado para coordinar las transacciones entre cada proveedor JMS y cada sistema contenedor EJB 2.0. Los vendedores se enfrentaron con un conjunto de problemas MxN: Debían crear costoso código de integración para cada proveedor de JMS que querían integrar. Como resultado, elegían integrar sólo unos pocos proveedores JMS.

Otra limitación de los MDBs de EJB 2.0 era que no sólo soportaban el modelo de programación JMS para mensajería asíncrona. Aunque JMS es muy útil, y es el estándar J2EE para mensajería asíncrona, no es el único sistema de mensajería asíncrona disponible hoy en día.

Dos nuevas características permiten a los desarrolladores de EJB 2.1 soportar varios proveedores de JMS así como sistemas de mensajería no-JMS: la definición ampliada de bean dirigido a mensaje, y la J2EE Connector Architecture 1.5.

EJB 2.1 soporta una definición más abierta de los beans dirigidos a mensaje que les permite manejar casi cualquier tipo de sistema de mensajería de cualquier vendedor. Los vendedores de EJB 2.1 todavía tienen que soportar MDBs basados en JMS, pero no están limitados sólo a eso. Los vendedores de EJB 2.1 pueden soportar cualquier tipo de mensajería que quieran. El único requerimiento es que los nuevos tipos de beans dirigidos a mensaje implementen el interface javax.ejb.MessageDrivenBean y se adhieran al ciclo de vida de un bean dirigido a mensaje. Aunque los vendedores de EJB 2.1 pueden construir código personalizado para soportar nuevos sistemas de mensajería (distintos a JMS) también deben soportar cualquier tipo de bean dirigido a mensaje que esté basado en la J2EE Connector Architecture 1.5.

La J2EE Connector Architecture (Connectors) proporciona un Service Provider Interface (SPI) estándar que permite que cualquier Enterprise Information System (EIS) se conecte directamente en cualquier sistema contenedor J2EE. En la versión 1.0 de Connectors esta conectividad se aplica a cualquier tipo de solicitud/respuesta de recurso en que el componente J2EE (EJB o Servlet/JSP) inicie la solicitud. J2EE 1.4, de la que forma parte EJB 2.1, use J2EE Connector Architecture versión 1.5, que mejora los tipos de EIS para incluir sistemas de mensajería asíncrona. En dichos sistemas, el componente espera a que llegue el mensaje en vez de iniciar una interacción con un EIS; el EIS inicia la interacción entregando un mensaje.

J2EE Connector Architecture 1.5 define un contrato de mensajería hecho a medida de los beans dirigidos a mensaje. Define los contratos entre un contenedor EJB y un Connector asíncrono para que los mensajes entrantes procedentes del EIS sean procesados automáticamente por el MDB dentro de una transacción iniciada por el contenedor EJB. Los MDBs que están basados en un Connector asíncrono implementaran el interface estándar javax.ejb.MessageDrivenBean así como un interface específico de la mensajería definido por el propio Connector. Por eso en lugar de implementar el interface javax.jms.MessageListener, el MDB implementará algún otro tipo de interface que sea específico del EIS.

Un hipotético Connector de email puede servir como ejemplo. El Connector de email permite que los MDBs procesen email de la misma forma que los MDBs basados en JMS procesan mensajes JMS. El Connector de email se lo compramos al vendedor X y nos lo entrega en un fichero JAR llamado un RAR (Resource ARchive). El RAR contiene el código del Connector y los descriptores de despliegue necesarios para conectarlo en el sistema del contenedor EJB. También define un interface de mensajería y un API de mensajería que el desarrollador usa para crear un MDB email. Aquí tenemos el hipotético interface de mensajería email que debería implementar un MDB email:

package com.vendorx.email;

public interface EmailListener {
    public void receiveMessage(javax.mail.Message message);
}

La clase bean que implementa este interface también implementa javax.ejb.MessageDrivenBean y será la responsable de procesar los mensajes de email que le entregará el Connector de email. El siguiente código muestra un MDB que implementa el interface EmailListener y procesa los mensajes de email:

package com.titan.email;
public class EmailBean implements javax.ejb.MessageDrivenBean, 
    com.vendorx.email.EmailListener {
      MessageDrivenContext ejbContext;
      public void setMessageDrivenContext(MessgeDrivenContext mdc){
             ejbContext = mdc;
      }
      public void ejbCreate(){}
      public void receiveMessage(javax.mail.Message message){
           javax.mail.internet.MimeMessage msg = 
               (javax.mail.internet.MimeMessage) message;
           Address [] addresses = msg.getFrom();
           //  continue processing Email message
      }
      public void ejbRemove(){}
}

El interface EmailListener entrega un mensaje en la forma de un Message JavaMail, un tipo que representa un mensaje de email que incluye attachments MIME. El API JavaMail es demasiado complicado para explicarlo en detalle para este sencillo ejemplo. Lo importante a llevarnos de este ejemplo es que los contenedores de EJB 2.1 pueden, y deben, soportar cualquier tipo de bean dirigido a mensaje para el cual haya una versión de Connector 1.5.

El interface de mensajería utilizado por el MDB basado en Connector podría declarar un método de procesamiento de mensaje que define un tipo de retorno. Por ejemplo, podríamos desarrollar un Connector que maneje mensajería al estilo solicitud/respuesta para SOAP, usando el ReqRepListener definido por el JAXM (Java API for XML Messaging), un API de mensajería SOAP definido por Sun Microsystems que no forma parte de la plataforma J2EE:

package javax.xml.messaging;
import javax.xml.soap.SOAPMessage;

public interface ReqRespListener {
    public SOAPMessage onMessage(SOAPMessage message);
}

Observa que aquí onMessage() tiene un tipo de retorno SOAPMessage. Un tipo de retorno requiere que el contenedor EJB y el Connector coordinen el mensaje de respuesta al emisor, o a algún otro destino definido en el descriptor de despliegue. Además de soportar diferentes firmas de métodos, el interface de mensajería podría tener varios métodos para procesar diferentes tipos de mensajes usando el mismo MDB. Los nuevos tipos de beans dirigidos a mensaje que pueden soportar los contenedores de EJB 2.1 no tienen límites, gracias a la definición ampliada de bean dirigido a mensaje y al requerimiento de soportar la nueva arquitectura de J2EE Connector 1.5.

Configuración de Activación para MDBs

Hay una diferencia importante en como se definen las propiedades de un MDB en el descriptor de despliegue en EJB 2.0 y en EJB 2.1. EJB 2.0 definía un par de elementos específicos de JMS, <message-selector> y <acknowledge-mode>, que han sido reemplazados en EJB 2.1 para que el descriptor de despliegue del MDB pueda representar tanto a MDBs basados en JMS como MDBs basados en Connector. Como los MDBs basados en Connector podrían no utilizar JMS como servicio de mensajería, se ha introducido un elemento agnóstico <activation-config>, para describir las propiedades de mensajería del MDB. Las propiedades Activation Configuration se pasarán al Connector cuando se despliegue el MDB. El Connector usará estas propiedades para configurar la forma en la que le entrega los mensajes al MDB.

El siguiente listado muestra los elementos <activation-config> - en negrita:

<enterprise-beans>
    ...
    <message-driven>
        <ejb-name>FooMDB EJB</ejb-name>
        <ejb-class>
            com.monsonhaefel.foo.FooBean
        </ejb-class>
        <messaging-type>javax.jms.MessageListener</messaging-type>
        <transaction-type>Container</transaction-type> 
        <message-destination-type>
            javax.jms.Queue
        </message-destination-type>  
        <activation-config>
           <activation-property>
               <activation-config-property-name>destinationType
               </activation-config-property-name>
               <activation-config-property-value>javax.jms.Queue
               </activation-config-property-value> 
           <activation-property> 
           <activation-property>
               <activation-config-property-name>messageSelector
               </activation-config-property-name>
               <activation-config-property-value>Color = 'Blue'
               </activation-config-property-value> 
           <activation-property> 
           <activation-property>
               <activation-config-property-name>acknowledgeMode
               </activation-config-property-name>
               <activation-config-property-value>Auto-acknowledge
               </activation-config-property-value> 
           <activation-property>        
        </activation-config>                
        <ejb-ref>
            ...
        </ejb-ref>
        <ejb-local-ref>
            ...
        </ejb-local-ref>
        <security-identity>
            <run-as>
                <role-name>everyone</role-name>
            </run-as>
        </security-identity>
        <resource-ref>
           ...
        </resource-ref>
    </message-driven>
    ...
</enterprise-beans>

Los nombres de las propiedades y los valores usados en el elemento <activation-config> para describir el servicio de mensajería variarán dependiendo del tipo del servicio de mensajes utilizado, pero EJB 2.1 define un conjunto de propiedades fijas para beans dirigidos a mensaje basados en JMS.

  • acknowledgeMode
  • messageSelector
  • destinationType
  • subscriptionDurablity

Estas propiedades de configuración de activación específicas de JMS reemplazan a los elementos con nombres similares usados en los MDBs de EJB 2.0. Otros MDBs, no-JMS usarán unas propiedades de configuración de activación completamente diferentes que son específicas del sistema de mensajería. Por ejemplo, el hipotético MDB de email podría usar un conjunto de propiedades de configuración de activación como estas:

<activation-config>
      <activation-property>
            <activation-config-property-name>mailServer
            </activation-config-property-name>
            <activation-config-property-value>mail.ispx.com
             </activation-config-property-value> 
      </activation-property> 
      <activation-property>
             <activation-config-property-name>serverType
             </activation-config-property-name>
             <activation-config-property-value>POP3
             </activation-config-property-value> 
      </activation-property> 
      <activation-property>
            <activation-config-property-name>messageFilter
            </activation-config-property-name>
            <activation-config-property-value>to='[email protected]'
            </activation-config-property-value> 
       </activation-property>
</activation-config>        

Además del nuevo elemento <activation-config>, EJB ha presentado los elementos <messaging-type> y <message-destination-type>.

<messaging-type>javax.jms.MessageListener</messaging-type>
... 
<message-destination-type>
            javax.jms.Queue
</message-destination-type>

El elemento <messaging-type> declara el interface de mensajería que utilizará el MDB. Para MDBs basados en JMS este interface siempre será javax.jms.MessageListener, pero para los MDBs basados en Connector podría ser algo completamente diferente. Si se omite el elemento <messaging-type>, se asume que el tipo es javax.jms.MessageListener.

El elemento <message-destination-type> designa el tipo de destino desde el que el MDB recibe los mensajes. Los valores permitidos para MDS basados en JMS son javax.jms.Queue y javax.jms.Topic. Un MDB basado en Connector podría usar algún otro tipo. Su valor debe ser siempre el nombre totalmente cualificado de la clase.

Podrías haber observado que las propiedades <message-destination-type> y destinationType especifican la misma cosa. Esto es redundante para MDBs basados en JMS pero no para MDBs no-JMS, que no definen una propiedad destinationType. Las propiedades de configuración de activación para MDBs basados en Connector, serán complemente diferentes de aquellos MDBs basados en JMS. Es importante que se especifique el <message-destination-type> tanto para MDBs basados en JMS como para MDBs basados en Connector.

Enlace de Mensajes

El enlace de mensajes es una característica, nueva en EJB 2.1, que permite enrutar mensajes enviados por cualquier bean enterprise (sin estado, con estado, de entidad o dirigido a mensaje) a un bean dirigido a mensaje en el mismo despliegue. La ventaja es que el desarrollador puede orquestar un flujo de mensajes entre componentes de la misma aplicación.

Para enlazar los mensajes salientes enviados por un EJB con los mensajes de entrada consumidos y procesados por un MDB, necesitamos definir elementos <message-destination-link> en el descriptor de despliegue de ambos EJB (emisor y receptor). El destino identificado por el elemento <message-destination-link> corresponde con un destino lógico definido en el <assembly-descriptor> de los beans.

Por ejemplo, abajo podemos ver la declaración del elemento <message-destination-link> de un bean de sesión que envía un mensaje JMS. El emisor declara el elemento <message-destination-link> bajo el elemento <message-destination-ref>:

<ejb-jar ...>

  <enterprise-beans>
    ...
    <session>
        <ejb-name>SendingEJB</ejb-name>
        ...
        <resource-ref>
            <res-ref-name>jms/TopicFactory</res-ref-name>
            <res-type>javax.jms.TopicConnectionFactory</res-type>
            <res-auth>Container</res-auth>
        </resource-ref>
        <message-destination-ref>
            <message-destination-ref-name>
                  jms/Topic
            </message-destination-ref-name>
            <message-destination-type>javax.jms.Topic</message-destination-type>
            <message-destination-usage>Produces</message-destination-usage>
            <message-destination-link>
                 DestinationA
            </message-destination-link>
        </message-destination-ref>
        ...
    </session>
    ...
  </enterprise-beans>
  ...
</ejb-jar>

El elemento <message-destination-ref> es nuevo en EJB 2.1 y declara el destino al que el bean enterprise envía mensajes. Cuando <message-destination-ref> incluye un elemento <message-destination-link>, se enviarán los mensajes a ese destino, que en este caso es DestinationA. Este nombre de destino debe corresponder con el nombre de un destino definido por un elemento <message-destination> en el descriptor de ensamblaje.

El código de abajo especifica el mismo destino en el elemento <message-destination> del <assembly-descriptor> .

<ejb-jar ...>
   <assembly-descriptor>
    ...
    <message-destination>
       <message-destination-name>DestinationA</message-destination-name>
    </message-destination>
    ...  
  </assembly-descriptor>
</ejb-jar>

Para poder hacer que el MDB consuma los mensajes enviados a DestinationA, necesitamos declarar un elemento <message-destination-link> en el descriptor de despliegue que declare DestinationA. El código de abajo apunta el <message-destination-link> del MDB receptor al mismo destino: el elemento <message-destination> especificado en el <assembly-descriptor>:

<ejb-jar ...>
    ...     
    <message-driven>
        <ejb-name>Receiving MDB</ejb-name>
        ...
        <messaging-type>javax.jms.MessageListener</messaging-type>
        <transaction-type>Container</transaction-type> 
        <message-destination-type>
            javax.jms.Topic
        </message-destination-type>  
        <message-destination-link>
            DestinationA
        </message-destination-link>
        ...
    </message-driven>
    ...
  </enterprise-beans>
  ...
</ejb-jar>

Los EJBs emisor y receptor ahora están enlazados. Especificando el mismo destino en el bean de sesión, en el bean dirigido a mensaje, y en el descriptor de ensamblaje aseguramos que los mensajes enviados por el bean de sesión irán al MDB.

En tiempo de despliegue cada uno de los elementos <message-destination> en el <assembly-discriptor> es mapeado al destino de mensajería real en el entorno destino. En la mayoría de los casos, será un tópico proveedor JMS, pero podría un destino proporcionado por otro tipo de sistema de mensajería.

Aunque cualquier bean enterprise puede tanto consumir (recibir) mensajes desde un destino lógico como producir (enviar) mensajes, se recomienda que sólo los MDBs consuman mensajes.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR