Gestión de eventos en web sockets con Spring Messaging

0
6847

En este tutorial vamos a ver un ejemplo de cómo engancharnos a los eventos de conexión y suscripción
en web sockets con el soporte de Spring Messaging y el framework de eventos que proporciona Spring.

Gestión de eventos en web sockets con Spring Messaging.

0. Índice de contenidos.


1. Introducción

El soporte de eventos que proporciona Spring nos permite emitir y escuchar eventos de una manera muy sencilla
permitiendo desacoplar componentes para compartir información. A su vez el soporte de Spring Messaging emite
una serie de eventos que nos permite engancharnos al ciclo de vida de conexión/desconexión y, de igual manera,
a la suscripción a colas dentro de las conexiones bidireccionales que podemos implementar entre cliente y servidor
con el soprote de web sockets que proporciona.

En este tutorial vamos a ver un ejemplo de cómo engancharnos a los eventos de conexión y suscripción
en web sockets con el soporte de Spring Messaging y el framework de eventos que proporciona Spring.

2. Entorno.

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 15′ (2.3 GHz Intel Core i7, 16GB DDR3).
  • Sistema Operativo: Mac OS Mavericks 10.9.4
  • Spring 4.1.6.RELEASE
  • Apache Tomcat 8.0.20


3. Configuración.

La configuración es muy similar a la vista en el tutorial anterior sobre Notificaciones vía web sockets con Spring Messaging en una aplicación AngularJS:

  <websocket:message-broker application-destination-prefix="/app"
	user-destination-prefix="/user"	>
		<websocket:stomp-endpoint path="/chat" >
            <websocket:handshake-interceptors>
                <bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/>
            </websocket:handshake-interceptors>
            <websocket:sockjs session-cookie-needed="true" />
		</websocket:stomp-endpoint>
		<websocket:simple-broker prefix="/topic" />
	</websocket:message-broker>

Hemos añadido un interceptor que copia la información de la conexión http en el mapa de atributos de la sesión para
poder recuperarlos en la lectura de los eventos.


4. Captura de eventos.

Vamos a añadir un bean que escucha los eventos antes nombrados, comenzando por la conexión y desconexión que,
con el soporte de un repositorio en memoria de los mismos nos permitirá acceder a la información de los usuarios
conectados y suscritos a colas de mensajería.

package com.autentia.labs.websockets;

import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionConnectEvent;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;
import org.springframework.web.socket.messaging.SessionSubscribeEvent;
import org.springframework.web.socket.messaging.SessionUnsubscribeEvent;


@Component
public class WebSocketEventListener {
	
	private UserChatRepository userChatRepository;

	@Autowired
	public WebSocketEventListener(UserChatRepository userChatRepository) {
		this.userChatRepository = userChatRepository;
	}
		
	@EventListener
	private void handleSessionConnected(SessionConnectEvent event) {
		final SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.wrap(event.getMessage());
		final LoginEvent loginEvent = new LoginEvent(headers.getSessionId(), headers.getNativeHeader("username").get(0));
		userChatRepository.addParticipant(headers.getSessionId(), loginEvent);
	}
	
	@EventListener
	private void handleSessionDisconnect(SessionDisconnectEvent event) {
		
		Optional.ofNullable(userChatRepository.getParticipant(event.getSessionId()))
				.ifPresent(login -> {
					userChatRepository.removeParticipant(event.getSessionId());
				});
	}
	
}

Voy a omitir el código tanto del repositorio como del POJO que representa la información que nos interesa almacenar
sobre los eventos en la conexión.

A continuación y dentro de la misma clase podríamos igualmente tratar los eventos de suscripción a colas de web sockets:


	@EventListener
	private void handleSessionSubscription(SessionSubscribeEvent event){
		final SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.wrap(event.getMessage());
		final SubscriptionEvent subscriptionEvent = new SubscriptionEvent(headers.getSessionId(), headers.getNativeHeader("username").get(0), headers.getDestination());
		userChatRepository.addSuscription(headers.getSessionId(), loginEvent);
	}
	
	@EventListener
	private void handleSessionSubscription(SessionUnsubscribeEvent event){
		Optional.ofNullable(userChatRepository.getSubscriptor(event.getSessionId()))
				.ifPresent(login -> {
					userChatRepository.removeSubscriptor(event.getSessionId());
				});
	}
	

Vemos que no son más que métodos con eventos de callback que, anotados apropiadamente y recibiendo como parámetro
el evento del tipo adecuado nos permite acceder a la información del mismo.


5. Referencias.


6. Conclusiones.

Sin necesidad de conocer internamente como están emitidos los eventos
solo tenemos que conocer el API de la clase que nos va a permitir acceder
a toda la información de estos.

Un saludo.

Jose

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad