Versiones comparadas

Clave

  • Se ha añadido esta línea.
  • Se ha eliminado esta línea.
  • El formato se ha cambiado.

...

En el caso de querer tener una comunicación push de un solo mensaje, normalmente porque se quiere presentar el resultado de una tarea asíncrona lanzada desde la vista, como es el caso del ejemplo anterior, se puede cerrar la conexión push invocando en el cliente  FundeWeb.Push.openclose(channel), pasando el nombre del canal como parámetro. Por ejemplo, podemos usar el listener Javascript onmessage para relizar la acción:

...

Es importante no mezclar las dos formas de controlar la conexión push. O se usa una expresión EL en el atributo connected, o se especifica connected="false" y la API Javascript  FundeWeb.Push para controlar la apertura/cierre de la conexión push. Mezclar ambas configuraciones puede provocar comportamientos impredecibles porque el estado de la vista Faces en el servidor no puede ser notificada de la apertura o cierre manual desde el cliente.


Eventos en el Cliente

El listener opcional de Javascript onopen, se usa cuando se abre el websocket en el cliente. Se lanza en el primer intento de conexión, independientemente de que la conexión se pueda realizar o no. No se invoca, en las auto-reconexiones que se hagan posteriormente. Acepta como único parámetro channel, el nombre del canal.

Bloque de código
languagexml
<fw:socket channel="foo" scope="view" ... connected="false" onopen="socketOpenListener" />

...

Bloque de código
languagexml
<fw:socket channel="foo" scope="view" ... connected="false" onerror="socketErrorListener" />

...

El listener opcional de Javascript onclose, se puede usar para detectar el cierro normal o no del websocket. Se invocará cuando falle el primer intento de conexión, o el servidor haya devuelto el código de motivo de cierre 1000 (cierre normal) o 1008 (política violada), o se haya excedido el máximo de intentos de reconexión. NO se invocará cuando el websocket pueda realizar un intento de reconexión automática en una conexión interrumpida después de la primera conexión correcta. En su lugar, se invocará onerror.

Bloque de código
languagexml
<fw:socket channel="foo" scope="view" ... onclose="socketCloseListener" />
Bloque de código
languagejs
function socketCloseListener(code, channel, event) {
    if (code == -1) {
        // Web sockets not supported by client.
    } else if (code == 1000) {
        // Normal close (as result of expired session or view).
    } else {
        // Abnormal close reason (as result of an error).
    }
}

El listener de Javascript onclose acepta tres parámetros:

  • code: el código que indica el tipo de cierre. Si el código es -1, entonces el cliente no soporta los websockets. Si es 1000, el websocket es cerrado por la expiración de una sesión o vista. El resto de valores que no son 1000, indican algún tipo de error. Mirar RFC 6455 sección 7.4.1 y CloseReason.CloseCodes.
  • channel: el nombre del canal, útil si se intenta tener un listener global.
  • event: la instancia de CloseEvent, útil en caso de revisión de querer más información sobre el error.


Cuando una conexión de ámbito sesión o vista, es cerrado automáticamente por el servidor con un código de 1000 (y no cerrado manualmente con FundeWeb.Push.close(channel)), indica que la sesión o la vista a expirado. Si la conexión que expira tiene ámbito de sesión, podemos aprovechar la oportunidad para mostrar un mensaje de información y redirigir a la página de inicio o autenticación usando window.location. Para el caso de que una conexión con ámbito vista expire, la gestión dependerá del tipo de expiración. Una vista puede expirar cuando la sesión asociada expira, pero además se puede producir con una navegación o recarga accidental, o cuando la configuración Faces "view per session" tiene un valor bajo y el cliente tiene bastantes vistas (ventanas/pestañas) abiertas en la misma sesión. Puedes aprovechar la oportunidad para advertir al cliente y/o dejar que JavaScript vuelva a cargar la página, ya que enviar cualquier formulario generaría una excepción ViewExpiredException.


Eventos en el Servidor

Cuando un websocket es abierto, se lanza un evento es.umatica.faces.push.socketEvent.opened (definido en la constante SocketEvent.EVENT_SOCKET_OPENED). Cuando el atributo user de <fw:socket> cambia, se lanza un evento es.umatica.faces.push.socketEvent.switched (definido en la constante SocketEvent.EVENT_SOCKET_SWITCHED). Cuando un websocket es cerrado, se lanza un evento es.umatica.faces.push.socketEvent.closed (definido en la constante SocketEvent.EVENT_SOCKET_CLOSED). Observar estos eventos en componentes de ámbito EVENT/PAGE/SESSION no tiene sentido, ya que no se puede realizar una solicitud HTTP en ese momento.

Bloque de código
languagejava
@Name("socketObserver")
@Scope(ScopeType.APPLICATION)
public class SocketObserver {

    @Observer( SocketEvent.EVENT_SOCKET_OPENED )
    public void onOpen(SocketEvent event) {
        String channel = event.getChannel(); // Returns <o:socket channel>.
        Long userId = event.getUser(); // Returns <o:socket user>, if any.
        // Do your thing with it. E.g. collecting them in a concurrent/synchronized collection.
        // Do note that a single person can open multiple sockets on same channel/user.
    }

    @Observer( SocketEvent.EVENT_SOCKET_SWITCHED )
    public void onSwitch(SocketEvent event) {
        String channel = event.getChannel(); // Returns <o:socket channel>.
        Long currentUserId = event.getUser(); // Returns current <o:socket user>, if any.
        Long previousUserId = event.getPreviousUser(); // Returns previous <o:socket user>, if any.
        // Do your thing with it. E.g. updating in a concurrent/synchronized collection.
    }

    @Observer( SocketEvent.EVENT_SOCKET_CLOSED ) 
    public void onClose(@Observes @Closed SocketEvent event) {
        String channel = event.getChannel(); // Returns <o:socket channel>.
        Long userId = event.getUser(); // Returns <o:socket user>, if any.
        CloseCode code = event.getCloseCode(); // Returns close reason code.
        // Do your thing with it. E.g. removing them from collection.
    }

}