Como Desarrollar un nuevo Gateway de protocolo para la plataforma Sofia2

Una de las características técnicas más destacables de la plataforma Sofia2 es que los protocolos físicos de comunicación soportados (TCP, MQTT, Ajax-push…), y sobre los que se envían mensajes SSAP desde los KPs, no están ligados al proyecto core de Sofia2, sino que son creados y desplegados en forma de Plugins.

De este modo, en cada instalación de Sofia2, es posible desplegar únicamente aquellos protocolos que se van a usar, sin necesidad de añadir el resto.

Asimismo, es posible desarrollar nuevos Gateways y desplegarlos de manera sencilla sin tener que añadirlos al core de la plataforma. Basta con desarrollarlos de manera separada, compilarlos como un Jar de Java y añadirlos al directorio de Plugins para que la plataforma los arranque durante el despliegue. De manera que la plataforma tiene la versatilidad de poder ser extendida con nuevos protocolos necesarios para un proyecto concreto, sin necesidad de solicitar una ampliación de la misma.

El funcionamiento de carga de Plugins en Sofia2 es el siguiente:

· Mediante un parámetro se indica a la plataforma el directorio donde se van a desplegar los ficheros Jar con plugins.

· Durante el arranque de la plataforma, Sofia2 escanea el directorio de plugins y carga las clases y el contexto Spring de cada uno de los Jar.

· Cada Gateway es manejado a través de un Bean de Spring instanciado durante la carga de clases del paso anterior.

Para ilustrar como desarrollar un nuevo Gateway, vamos a basarnos en el Gateway Websocket que estará disponible a partir de la release 2.10 de Sofia2, y que se ha creado utilizando el framework Atmosphere(ver http://unpocodejava.wordpress.com/2014/07/25/creando-websockets-de-manera-sencilla-con-atmosphere/)

· El primer paso es crear un nuevo proyecto en el que desarrollar el Gateway y configurar y añadir las dependencias de Sofia2 al pom.xml del proyecto.

Para configurar el proyecto tendremos en cuenta:

1. Todos los gateways de Sofia2 pertececen al grupo com.indra.sofia2.plugin.gateway Por lo que habrá que incluir la siguiente entrada en el pom.xml indicando el artifact padre del Gateway que vamos a crear:

Siendo la versión, la versión de la última distribución de Sofia2.

2. Configuramos nuestro proyecto como perteneciente al grupo de gateways y le damos un nombre y versión:

3. Incluimos las dependencias de Sofia2 que necesitaremos durante el desarrollo del plugin:

4. Añadimos el resto de dependencias. Que para nuestro ejemplo de Gateway websocket será el runtime de atmosphere

· Una vez configurado el proyecto, lo siguiente es pasar al desarrollo del plugin. Como hemos dicho, cada Gateway es manejado mediante un Bean de Spring, que Sofia2 carga durante el arranque de la plataforma. Por lo que será necesario que declaremos ese Bean, bien en un fichero de contexto, bien mediante una anotación de tipo @Component. De este modo el Bean será el punto de arranque de nuestro Gateway.

· A su vez, el core de Sofia2 proporciona la clase abstracta GatewayToExtendImpl con las utilidades que los Gateways necesitan para una vez recibido un mensaje SSAP por su protocolo físico correspondiente, elevarlo al SIB para su procesado y recepción de la respuesta a devolver al cliente.

Esta clase obliga a implementar los siguientes métodos:


@Override

public GatewayProtocol getProtocol() {//TODO Tipo de protocol implementado}

@Override

public void onStart() {//TODO Acciones a realizar al arrancar el Gateway }

@Override

public void onStop() {//TODO Acciones realizar al detener el Gateway}

Y proporciona el método:


public SSAPMessage process(SSAPMessage mensaje, ClientGatewayData client)

A través del que se elevará al SIB para su procesado un mensaje SSAP recibido desde un cliente. El otro argumento es un objeto de tipo ClientGatewayData utilizado para auditoria y recoge información de la conexión del cliente.

Siguiendo con el ejemplo del Gateway WebSocket los pasos descritos se traducen en:

1. Creamos la clase del Gateway WebSocket como un Bean de Spring, que implementa GatewayToExtendImp:


@Component("GatewayWebSockets")

public class GatewayWebSockets extends GatewayToExtendImpl

2. Creamos el manejador del protocolo Websocket mediante un manejador del framework Atmosphere(ver http://unpocodejava.wordpress.com/2014/07/25/creando-websockets-de-manera-sencilla-con-atmosphere/). En este caso, es el framework Atmosphere mediante esta clase, quien gestiona todos los aspectos relativos al protocolo físico Websocket, e invocando al método onTextMessage cuando recibe un mensaje a través del protocolo:


@WebSocketHandlerService(path = "/api_websocket", broadcaster = SimpleBroadcaster.class)

public class WebSocketsProtocolAdapter extends WebSocketHandlerAdapter {

//Logger

private static final Log logger = LogFactory.getLog(WebSocketsProtocolAdapter.class);

private GatewayWebSockets gatewayWebSockets;

@Override

public void onOpen(WebSocket webSocket) throws IOException {

logger.info("New websocket connection added: "+webSocket.resource().getRequest().getRemoteAddr());

webSocket.resource().addEventListener(new WebSocketEventListenerAdapter() {

@Override

public void onDisconnect(AtmosphereResourceEvent event) {

try {

logger.info("Disconnecting websocket connection");

event.getResource().close();

} catch (IOException e) {

logger.error("Error closing websocket connection: "+e.getMessage());

}

}

@Override

public void onClose(AtmosphereResourceEvent event) {

logger.info("Closing websocket connection");

super.onClose(event);

}

});

}

@Override

public void onTextMessage(WebSocket webSocket, String message) throws IOException {

AtmosphereResource resource = webSocket.resource();

logger.info("Gateway WebSocket receive SSAP message: "+message);

String response=getGatewayWebSockets().process(message, resource);

logger.info("Gateway WebSocket response SSAP message: "+response);

Broadcaster b = resource.getBroadcaster();

b.broadcast(response, resource);

}

Como vemos en el código, cuando se recibe un mensaje SSAP a través del manejador, este mensaje se pasa al Gateway de Websockets a través del método process, siendo ya esta clase quien eleve el mensaje al SIB al extender GatewayToExtendImpl

3. Al utilizar Atmosphere como framework para Websockets, nos encontramos con el problema de que este framework carga los manejadores de Websocket durante el arranque del contenedor Web, en un punto donde Sofia2 todavía no ha cargado las clases de los plugins, y por tanto el manejador desarrollado en el punto anterior (WebSocketsProtocolAdapter), al no estar cargado en el classpath, no ha sido descubierto por Atmosphere y no se encuentra disponible. Para resolver este problema, lo que hacemos es registrarlo explicitamente durante el arranque del Gateway en el método onStart():


@Override

public void onStart() {

//Registra el Adaptador de WebSockets ya que Atmosphere hace el escaneo de clases anotadas antes de que SOFIA registre los plugins

Map<Class<? extends Annotation>, Set<Class<?>>> annotations = (Map<Class<? extends Annotation>, Set<Class<?>>>)

servletContext.getAttribute(DefaultAnnotationProcessor.ANNOTATION_ATTRIBUTE);

Set<Class<?>> setAnotations=annotations.get(org.atmosphere.config.service.WebSocketHandlerService.class);

if(setAnotations==null){

setAnotations=new HashSet<Class<?>>();

annotations.put(org.atmosphere.config.service.WebSocketHandlerService.class, setAnotations);

}

setAnotations.add(com.indra.sofia2.sib.gateway.implementations.websockets.WebSocketsProtocolAdapter.class);

}

· Con lo visto hasta ahora, ya podemos registrar nuestro Gateway para que la plataforma lo arranque, elevar mensajes SSAP al SIB recibidos por el protocolo físico y recibir la respuesta desde el SIB para devolverla por el protocolo físico. Lo que falta es implementar la parte en la que el SIB pueda enviar notificaciones de suscripción a un KP (mensajes SSAP de tipo INDICATION).

Para esto, nuestro Gateway tiene que registrar un listener en el core de Sofia2, mediante el que recibir las notificaciones desde el motor de suscripciones y después enviarlas por la conexión del protocolo físico.

El listener que tenemos que registrar debe implementar la clase MessageSuscriptor:


public interface MessageSuscriptor {

public void onMessage(SSAPMessage message);

}

De manera que el SIB notificará este tipo de mensajes invocando al método onMessage del listener, pasándoles el mensaje SSAP a enviar al KP.

El registro del listener debe hacerse en un Bean Spring del core de Sofia2 llamado subscriptionEngine perteneciente a la clase SubscriptionEngine. De manera que nuestro Gateway deberá recuperar este Bean, y registrar su propio Listener:


@Autowired

private SubscriptionEngine subscriptionService;

·····························

subscriptionService.addMessageSubscriptor(sessionKey, new MessageSuscriptor() {

@Override

public void onMessage(SSAPMessage message) {

String toNotify=message.toJson();

//TODO notificar mensaje a través de protocolo físico

}

});

Continuando con el ejemplo del Gateway Websocket, una vez recibido el mensaje SSAP de notificación, la comunicación al KP cliente se hará a través de la conexión gestionada por Atmosphere en un objeto del tipo AtmosphereResource:


subscriptionService.addMessageSubscriptor(sessionKey, new MessageSuscriptor() {

@Override

public void onMessage(SSAPMessage message) {

String toNotify=message.toJson();

ClientGatewayData client =new ClientGatewayData(remoteAddress, remotePort, ClientGatewayType.WEB);

auditPluginManager.audit(message, listenerCipherKey, Calendar.getInstance().getTime(), client, AuditDirection.TO_CLIENT);

Broadcaster broadcaster=resource.getBroadcaster();

broadcaster.broadcast(toNotify, resource);

}

});

Como Desarrollar un nuevo Gateway de protocolo para la plataforma Sofia2

Un comentario en “Como Desarrollar un nuevo Gateway de protocolo para la plataforma Sofia2

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s