Service Integration Bus - Guía de inicio para el desarrollo de aplicaciones JMS con IBM WebSphere Application Server

...

En esta publicación realizaremos la configuración de un bus de integración de servicios o SIB (Service Integration Bus) dentro de un servidor IBM WebSphere Application Server y verificaremos su funcionamiento desarrollando una aplicación de ejemplo para enviar y recibir mensajes JMS utilizando el motor de mensajería interno del servidor.

Introducción

El servidor IBM WebSphere Application Server soporta mensajería asincrónica basada en Java Messaging Services (JMS). La implementación de las API de JMS para acceder a una infraestructura de mensajería o MOM (Message Oriented Middleware) es lo que denominamos proveedor de mensajería JMS (o JMS messaging provider).

    Dentro del servidor IBM WebSphere Application Server es posible configurar tres tipos de proveedores de mensajería JMS:
    • el proveedor de mensajería por omisión del servidor IBM WebSphere Application Server que utiliza el bus de integración de servicios interno del servidor o SIB (Service Integration Bus).
    • el proveedor de mensajería para acceder a infraestructuras IBM WebSphere MQ.
    • el proveedor de mensajería para acceder a infraestructuras de mensajería JMS correspondientes a implementaciones de otros fabricantes (ej: ActiveMQ).
    En este artículo utilizaremos el proveedor de servicios por omisión y por ello conviene conocer algunos componentes y características de la infraestructura de mensajería interna del servidor IBM WebSphere Application Server:
    • Buses de integración de servicios. Un bus de integración de servicios o SIB (Service Integration Bus) agrupa y comunica múltiples motores de mensajería corriendo dentro de servidores IBM WebSphere Application Server. Múltiples servidores y clusters pueden ser parte de un SIB, y las aplicaciones se conectan al mismo a través de un motor de mensajería.
    • Motores de mensajería. Cada servidor o cluster -cuando es miembro de un SIB- contiene un componente denominado motor de mensajería (o messaging engine) encargado de realizar los envíos de mensajes, procesar los requerimientos y alojar los destinos (colas y tópicos). Estos motores se administran utilizando el mismo marco administrativo que utiliza el resto de los componentes y servicios del servidor IBM WebSphere Application Server.
    • Miembros. Cuando se agrega un servidor o cluster de servidores a un SIB, un motor de mensajería es creado automáticamente para el nuevo miembro. Si se agrega un mismo servidor como miembro de varios buses, se crearán múltiples motores de mensajería, uno por cada SIB.
    • Destinos. Un destino es una ubicación virtual dentro de un bus en donde los mensajes son almacenados y procesados, por ejemplo, para cada cola JMS debe existir un destino de tipo cola definido en el bus de integración. Para utilizar el proveedor de mensajería por omisión utilizando JMS, las aplicaciones deben conectarse a un bus de integración de servicios o SIB, dentro del mismo se deben crear destinos y asignarles colas o tópicos JMS dependiendo del estilo de mensajería utilizado, punto a punto o publicar/suscribir.
    • Fabricas de conexiones (JMS). Una fábrica de conexiones JMS (o JMS Connection Factory) se utiliza para crear y obtener conexiones a los recursos JMS definidos en un bus de integración de servicios.
    • Colas (JMS). Una cola JMS es un objeto administrativo que encapsula el nombre de un destino de tipo cola definido en un bus de integración de servicios, las aplicaciones deben obtener estos objetos administrativos realizando una búsqueda en el espacio de nombres JNDI.
    • Tópicos (JMS). Las colas JMS se utilizan para comunicarse en un modelo de integración punto a punto, al igual que las colas, los tópicos JMS son objetos administrativos que se utilizan para comunicarse en un modelo de integración publicar/suscribir.
    • Aplicaciones cliente. Las aplicaciones que se conectan a un bus pueden estar corriendo dentro de un servidor IBM WebSphere Application Server, pueden ejecutarse como aplicaciones Java SE independientes o pueden acceder desde otras plataformas a través del estándar XMS

Estos conceptos serán de utilidad en el desarrollo de las siguientes secciones en las cuales se realizarán las configuraciones de la infraestructura de mensajería interna del servidor IBM WebSphere Application Server y se desarrollará una aplicación para acceder y realizar pruebas con el mismo. La siguiente imagen representa gráficamente los conceptos mencionados:

Configuración del bus

Versión del servidor y otros requisitos

Las actividades de configuración y desarrollo que se describirán en las siguientes secciones requieren de un servidor IBM WebSphere Application Server 8.x independiente ("Stand Alone") instalado con las configuraciones por omisión. Las capturas de pantalla se realizaron utilizando la edición Network Deployment, pero es posible utilizar -por ejemplo- la edición "for Developers".

Para el desarrollo de la aplicación de ejemplo se utilizó el paquete Eclipse IDE for Java EE Developers de Eclipse Juno.

Configuración de la infraestructura

El primer paso que daremos será la configuración de un nuevo bus de integración de servicios, para ello accederemos a la consola administrativa con el usuario administrador del servidor y seguiremos los pasos que se describen a continuación.

Creación de un nuevo bus de integración de servicios (SIB)

Abrir la sección Service integration dentro de la consola administrativa del servidor y seleccionar la opción Buses, el listado de buses de integración de servicios estará vacio. Presionar New... para iniciar el proceso de creación de un nuevo bus de servicios.

"Service Buses"/>

El asistente nos solicitará un nombre para el nuevo bus, especificar MGDevelopers como nombre, deshabilitar la seguridad deseleccionando la opción Bus security y presionar Next.

Bus: MGDevelopers

En el último paso, el asistente nos mostrará un resumen de la configuración, verificar el nombre ingresado y que la seguridad se encuentre deshabilitada, presionar Finish para crear el nuevo bus.

Finalización del asustente

Como en toda acción que requiere modificar los archivos de configuración internos del servidor, se nos solicitará que guardemos la configuración o revisemos los cambios realizados, presionar Save para grabar los cambios en la configuración.

Configuración maestra

En la lista de buses de integración de servicios deberá aparecer el bus creado con el nombre MGDevelopers y la seguridad en estado Disabled.

Listado de buses

Adición del servidor como miembro del nuevo bus

Una vez creado el bus de servicios tendremos que agregar la instancia del servidor actual como miembro del mismo, ubicado en la lista de buses seleccionamos el bus MGDevelopers y luego la opción Bus members en la sección Topology.

Configuración del bus

El listado de miembros del bus de integración de servicios estará vacio. Presionar Add para iniciar el proceso de adición de un nuevo miembro al bus de servicios.

Listado de miembros del bus

El asistente nos solicitará información sobre el miembro que deseamos agregar al bus, esta información se utilizará para realizar la configuración del motor de mensajería. Seleccionar la opción Server y verificar que el servidor actual se encuentre seleccionado en el listado, presionar Next para continuar.

Nuevo miembro

La información de los mensajes se puede persistir en el sistema de archivos o en una base de datos relacional, seleccionar la opción File Store y presionar Next para continuar.

Tipo de message store

Mantener los valores por omisión presentados para la configuración de file store y presionar Next para continuar.

Configuración del file store

El asistente nos recomendará valores para los tamaños iniciales y máximos del Java Heap, mantener seleccionada la opción Change heap sizes y presionar Next para continuar.

Tamaños del heap

En el último paso, el asistente nos mostrará un resumen de la configuración, verificar la información suministrada, presionar Finish para agregar el miembro al bus.

Finalización del asistente

Se nos solicitará que guardemos la configuración o revisemos los cambios realizados, presionar Save para grabar los cambios en la configuración.

Deshabilitación del requerimiento de conexiones al SIB vía SSL

Por tratarse de un artículo introductorio y para evitar una complejidad adicional, en los pasos precedentes configuramos un bus de integración sin seguridad. Ahora tendremos que modificar la configuración de seguridad global del servidor para deshabilitar el requerimiento de SSL en las comunicaciones IIOP que -en nuestro caso- se utilizan para acceder al servicio de nombres del servidor vía JNDI.

Si no se llegara el requerimiento de SSL, nuestra aplicación de ejemplo lanzará la siguiente excepción durente el lookup de los recursos administrados (JMS):

javax.naming.NamingException: Error getting WsnNameService properties [Root exception is org.omg.CORBA.TRANSIENT: initial and forwarded IOR inaccessible vmcid: IBM minor code: E07 completed: No]

Abrir la sección Security dentro de la consola administrativa del servidor y seleccionar la opción Global Security, luego seleccionar la opción RMI/IIOP security > CSIv2 inbound communications ubicada en la sección Authentication de la configuración global.

Seguridad global

Seleccionar el valor SSL-supported en el listado Transport ubicado en la sección CSIv2 Transport Layer, presionar OK para modificar la configuración.

Seguridad IIOP

Se nos solicitará que guardemos la configuración o revisemos los cambios realizados, presionar Save para grabar los cambios en la configuración.

Reinicio del servidor y verificación del estado de los motores de mensajería

Para que el servidor inicie el motor de mensajería configurado y se tomen los cambios realizados en la seguridad global será necesario reiniciarlo.

Luego de reiniciar el servidor, abrir la sección Service integration dentro de la consola administrativa del servidor y seleccionar la opción Buses.

Abrir la configuración del bus MGDevelopers y seleccionar la opción Messaging engines ubicada en la sección Topology.

Bus de integracion MGDevelopers

Se el motor de mensajería se inicio correctamente el estado del mismo será Started.

Motor de mensajeria

Configuración JMS

Configuración de una fábrica de conexiones (JMS)

Abrir la sección Service integration dentro de la consola administrativa del servidor y seleccionar la opción Buses. Abrir la configuración del bus MGDevelopers y seleccionar la opción Destinations ubicada en la sección Destination resources.

Bus de integracion MGDevelopers

El listado contiene destinos creados por omisión junto al bus de integración. Presionar New... para iniciar el proceso de creación de un nuevo destino.

Listado de destinos

El primer paso del proceso de creación contempla la selección del tipo de destino, en nuestro caso necesitamos crear una cola para nuestra aplicación de ejemplo. Seleccionar Queue como tipo de destino y presionar Next para continuar.

Tipo de destino

Establecer ColaEjemploQ como identificador del destino y Cola de ejemplo como descripción.

Id del destino

En el listado de miembros, seleccionar el único miembro del bus y presionar Next para continuar.

Selección de miembro

En el último paso, el asistente nos mostrará un resumen de la configuración especificada, verificar la información suministrada, presionar Finish para crear el destino.

Finalización del asistente

En el listado de destinos deberá aparece la cola ColaEjemploQ.

Listado de destinos

Configuración de una fábrica de conexiones (JMS)

Abrir la sección Resources dentro de la consola administrativa del servidor y seleccionar la opción JMS > Queue connection factories. Presionar New... en el listado de fábricas para iniciar el proceso de creación de una nueva fábrica de conexiones para colas.

Listado de fábricas para colas

El primer paso del proceso de creación contempla la selección del tipo de proveedor en el cual reside la cola, en nuestro caso el destino fue creado en el proveedor por omisión. Seleccionar Default messaging provider y presionar OK para continuar.

Tipo de proveedor

Especificar MGDevelopersConnFactory como nombre de la fábrica y jms/conn/mgdevelopers como nombre JNDI. Por último seleccionar MGDevelopers como nombre de bus y presionar Finish para crear la cola.

Información para la nueva fábrica

En el listado de colas deberá aparece la nueva cola.

Listado de fábricas para colas

Configuración de una cola (JMS)

Abrir la sección Resources dentro de la consola administrativa del servidor y seleccionar la opción JMS > Queues. Presionar New... en el listado de colas para iniciar el proceso de creación de una nueva cola.

Listado de colas

Seleccionar Default messaging provider y presionar OK para continuar.

Tipo de proveedor

Especificar Cola Ejemplo como nombre de la cola y jms/queue/ejemplo como nombre JNDI. Por último en la sección Connection seleccionar MGDevelopers como nombre de bus y ColaEjemploQ como nombre de cola. Presionar Finish para crear la cola.

Información para la nueva cola

En el listado de colas deberá aparece la nueva cola.

Listado de colas

Desarrollo de la aplicación de ejemplo

Una vez que configuramos la infraestructura de mensajería interna, y creamos los recursos administrados JMS, estaremos en condiciones de comenzar con el desarrollo de la aplicación de ejemplo.

En resumen, nuestra aplicación de ejemplo constará de una clase denominada ClienteJMS con métodos para obtener y enviar mensajes a la cola ColaEjemplo (jms/queue/ejemplo) y métodos de utilidad para obtener los recursos JMS y crear una conexión con el SIB a partir de la fábrica de conexiones MGDevelopersConnFactory (jms/conn/mgdevelopers).

    Para acceder al SIB configurado en el servidor IBM WebSphere Application Server será necesario que la aplicación tenga las siguientes librerías -que se encuentran en el directorio runtimes ubicado en el directorio de instalación del servidor- definidas como dependencias (Classpath):
    • com.ibm.ws.sib.client.thin.jms_8.5.0.jar, esta librería corresponde al IBM Thin Client for JMS que permite a una aplicación acceder al proveedor de mensajería por omisión del servidor IBM WebSphere Application Server.
    • com.ibm.ws.ejb.thinclient_8.5.0.jar, esta librería corresponde al IBM Thin Client for Enterprise JavaBeans (EJB) que permite el acceso a los EJB definidos en el servidor, también permite a una aplicación comunicarse con el espacio de nombres del servidor por medio JNDI para obtener, por ejemplo, recursos administrados JMS.
    • sibc.nls.zip, opcionalmente, este archivo contiene paquetes de recursos específicos para cada idioma.

Creación de un nuevo proyecto Java

En primer lugar tendremos que crear un nuevo proyecto para nuestra aplicación de ejemplo, para ello abrireremos el entorno de desarrollo Eclipse, especificaremos un espacio de trabajo (workspace), y seleccionaremos la opción de menú File > New > Java Project para iniciar el asistente de creación de un nuevo proyecto Java

Nuevo proyecto

En el siguiente diálogo especificaremos ProyectoClienteJMS como nombre del proyecto, mantendremos el resto de los campos con los valores por omisión y presionaremos Next para continuar.

Info del proyecto

Agregar las librerías requeridas por la aplicación presionando el botón Add External JARs..., luego de agregar las librerías presionar Finish para crear el proyecto.

Dependencias del proyecto

Creación de la clase

Una vez creado el proyecto crearemos una nueva clase Java seleccionando la opción de menú File > New > Class.

Nueva clase

En el siguiente diálogo especificaremos ClienteJMS como nombre de la clase, especificaremos com.microgestion.mgdevelopers.blog como nombre de paquete y chequearemos la opción public static main (string[] args), luego presionaremos Finish para crear la clase.

Valores de la clase
    La clase tendrá cinco métodos:
    • main, este método es el punto de entrada de todo programa Java independiente (stand alone), el mismo crea una instancia de la clase ClienteJMS y llama a los métodos de inicialización obtenerRecursosAdministradosJMS y obtenerSession; luego llamará al método enviarMensaje o al método obtenerMensajes dependiendo del valor del primer parámetro con el que se invoque a la clase.
    • obtenerRecursosAdministradosJMS, este método es el encargado de obtener los recursos administrados JMS requeridos por la aplicación, la fábrica de conexiones JMS (jms/conn/mgdevelopers) y el destino JMS (jms/queue/ejemplo). Para llevar a cabo su tarea, establece una conexión con el servicio de nombres (iiop://localhost:2809) utilizando las clases JNDI.
    • obtenerSession, este método crea e inicia una conexión a partir de la fábrica de conexiones creada previamente, luego crea la sesión que será utilizada para producir y consumir mensajes.
    • enviarMensaje, este método recibe el texto del mensaje que se desea enviar, crea un productor de mensajes (MessageProducer) para el destino JMS (cola), crea un mensaje de texto (TextMessage) y envía el mensaje utilizando el método send del productor.
    • recibirMensajes, este método utiliza un consumidor de mensajes (MessageConsumer) del destino JMS (cola) y obtiene los mensajes que en el mismo se encuentren depositados, para ello utiliza el método receiveNoWait del consumidor.

A continuación se muestra el código de la clase ClienteJMS:

package com.microgestion.mgdevelopers.blog;

import java.util.Hashtable;
import java.util.logging.Logger;

import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.QueueConnectionFactory;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class ClienteJMS {
	private static Logger logger = Logger.getLogger("com.microgestion.mgdevelopers.blog");	
	private QueueConnectionFactory queueConnectionFactory = null;
	private Destination            queue                  = null;
	private Session                session                = null;
	private Connection             connection             = null;
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {

		ClienteJMS app = new ClienteJMS();
		// Obtiene los recursos JMS
		app.obtenerRecursosAdministradosJMS();
    	// Obtiene la sesión con el SIB
		app.obtenerSession();
		
		if(args[0].toLowerCase().compareTo("send")==0){
			app.enviarMensaje(args[1]);			
		}else{
			app.obtenerMensaje();
		}		
	}

	/**
	 * Método que envía un mensaje a la cola 
	 */		
	public void enviarMensaje(String message){
		logger.entering(this.getClass().getName(), "enviarMensaje");
	    MessageProducer messageProducer = null;	
		
	    try {
	    	// Crear un productor de mensajes para la cola
	    	messageProducer = session.createProducer(queue);
			// Crear mensaje
	    	message = message + " (enviado el " + ( new java.util.Date() ).toString() + ")";
			TextMessage outMessage = session.createTextMessage( message );
			// Enviar mensaje a la cola
			messageProducer.send(outMessage);			
			logger.info("Se envió el mensaje '" + message + "'");

		} catch (JMSException e) {
			logger.throwing(ClienteJMS.class.getName(), "enviarMensaje", e);
		} finally {
			try {
				logger.fine("Liberación de recursos");
				messageProducer.close();
				session.close();
				connection.close();
			} catch (JMSException e) {
				logger.throwing(ClienteJMS.class.getName(), "enviarMensaje", e);
			}
		}
		logger.exiting(this.getClass().getName(), "enviarMensaje");
	}
	
	/**
	 * Método que obtiene los mensajes alojados en la cola
	 */		
	public void obtenerMensaje(){
		logger.entering(this.getClass().getName(), "obtenerMensaje");
	    MessageConsumer messageConsumer = null;	
	    Message inMessage = null;
	    try {
	    	// Crear un productor de mensajes para la cola
	    	messageConsumer = session.createConsumer(queue);
			inMessage = messageConsumer.receiveNoWait();

            //Obtiene un mensaje
            while (inMessage instanceof TextMessage) {
                TextMessage txtMessage = (TextMessage) inMessage;
                logger.info("Read Message: " + txtMessage.getText());
    			inMessage = messageConsumer.receiveNoWait();
            }

		} catch (JMSException e) {
			e.printStackTrace();
		} finally {
			try {
				logger.fine("Liberación de recursos");
				messageConsumer.close();
				session.close();
				connection.close();
			} catch (JMSException e) {
				e.printStackTrace();
			}
		}
		logger.exiting(this.getClass().getName(), "enviarMensaje");
	}
	
	/**
	 * Método que permite establecer una sessión 
	 */	
	public void obtenerSession(){	
		logger.entering(this.getClass().getName(), "obtenerSession");		
		 try {
			 // Obtención de una conexión a partir de la fábrica
			 connection = queueConnectionFactory.createConnection();
			 // Inicio de la conexión
			 connection.start();
			 // Creación de la sesión
			 session = connection.createSession(false, 1);
		 } catch (JMSException e) {
			 logger.throwing(ClienteJMS.class.getName(), "enviarMensaje", e);
		 }
		 logger.exiting(this.getClass().getName(), "obtenerSession");
	}
	
	/**
	 * Método que permite obtener los recursos JMS administrados
	 */
	public void obtenerRecursosAdministradosJMS(){		
		logger.entering(this.getClass().getName(), "obtenerRecursosAdministrados");
		try {
	    	Hashtable env = new Hashtable();
	    	env.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory");
	    	env.put(Context.PROVIDER_URL, "iiop://localhost:2809");	
			Context jndiContext = new InitialContext(env);
			queueConnectionFactory = (QueueConnectionFactory) jndiContext.lookup("jms/conn/mgdevelopers");
			queue = (Destination) jndiContext.lookup("jms/queue/ejemplo");
		} catch (NamingException e) {
			logger.throwing(ClienteJMS.class.getName(), "enviarMensaje", e);
			System.exit(0);
		}	
		logger.exiting(this.getClass().getName(), "obtenerRecursosAdministrados");
	}	
}

Conclusiones

En esta artículo hemos realizado una configuración básica del proveedor de mensajería interna del servidor IBM WebSphere Application Server y hemos creado una aplicación sencilla para probar su funcionamiento bajo un modelo de comunicación punto a punto.

El lector que luego de seguir los pasos de configuración haya probado exitosamente la aplicación de ejemplo, estará en condiciones de profundizar sobre los conceptos que aquí se explicaron brevemente y emprender el camino de explorar tópicos mas avanzados como la configuración y el acceso a un SIB con seguridad, el desarrollo de aplicaciones bajo el modelo de comunicación publicar/suscribir, etc.

Referencias


Modificado por última vez en Jueves, 02 Enero 2014 22:50

Acerca del autor

Diego E. Mendoza

Diego se desempeña como arquitecto de software en MicroGestion participando en el proceso de análisis y diseño de soluciones que tengan requerimientos de alta disponibilidad, integración de ambientes heterogéneos, orientación a servicios, gestión de procesos de negocio, etc.