Aplicaciones Web (parte 7)
Eduardo Ostertag Jenkins, Ph.D.
OBCOM INGENIERIA S.A. (Chile)
[Link]@[Link]
WebSocket y Servlet
Browser Application Server (JEE)
Database
HTML
CSS JSF
DOM E
Java Script J
REST B
J
D
Servlet D Data
Rich Client A Procs
B Model
O
C
Java SOAP M
.NET D
Android Web B
iOS Socket
Protocolo WebSocket
◼ Protocolo de comunicaciones que provee
un canal de comunicación full-duplex a
través una única conexión TCP/IP
◼ Full-duplex: capaz de transmitir en ambas
direcciones de un canal al mismo tiempo
◼ Ambos, el cliente y el servidor, pueden
enviar mensajes cuando quieran ☺
◼ El servidor ya no tiene que esperar a
recibir un requerimiento del cliente ☺
WebSocket no es HTTP
◼ WebSocket está diseñado para funcionar
por los puertos 80 y 443 de HTTP
◼ WebSocket opera a través de servidores
proxy y otros intermediarios HTTP
◼ WebSocket es compatible con HTTP, pero
es distinto de HTTP
◼ Un canal WebSocket parte vía HTTP, pero
luego se cambia con un “upgrade header”
Iniciar canal WebSocket
[Link] (inseguro)
[Link] (seguro)
GET /chat/room HTTP/1.1
Host: [Link]
Upgrade: websocket
S
C Connection: Upgrade
E
L Sec-WebSocket-Version: 13
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== R
I
V
E
I
N HTTP/1.1 101 Switching Protocols D
T Upgrade: websocket O
E Connection: Upgrade R
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Mensaje binario WebSocket
◼ Non-Control Frames ◼ Control Frames
◼ Text (UTF-8 bytes) ◼ Close (channel)
◼ Binary (raw bytes) ◼ Ping (question)
◼ Continue (previous) ◼ Pong (answer)
Ejemplo: chat room
Browser
HTML5 Application Server (JEE)
json
Browser
HTML5 WebSocket
json
Server
Endpoint
●●●
json
Rich Client
Java
WebSocket Server Endpoint
◼ Requiere una clase “Server Endpoint”
◼ Decorada con @ServerEndpoint(…)
◼ Con método @OnOpen
◼ Invocado cuando se abre una sesión
◼ Con método @OnClose
◼ Invocado cuando se cierra una sesión
◼ Con método @OnMessage
◼ Invocado cuando se recibe un mensaje
◼ Con método @OnError
◼ Invocado cuando ocurre un error asíncrono
Clase Server Endpoint
import [Link].*;
import [Link].*;
@ServerEndpoint(
value = "/chat",
encoders = [Link],
decoders = [Link])
public class ChatServerEndpoint
{
@OnOpen {...}
@OnClose {...}
@OnMessage {...}
@OnError {...}
}
Método @OnOpen
@ServerEndpoint(…)
public class ChatServerEndpoint
{
...
@OnOpen
public void onOpen(Session sesión, EndpointConfig cofig)
{
...
}
...
}
Método invocado cuando se abre una nueva sesión
Método @OnClose
@ServerEndpoint(…)
public class ChatServerEndpoint
{
...
@OnClose
public void onClose(Session session, CloseReason reason)
{
...
}
...
}
Método invocado cuando se cierra una sesión
Método @OnError
@ServerEndpoint(…)
public class ChatServerEndpoint
{
...
@OnError
public void onError(Session session, Throwable thrown)
{
...
}
...
}
Método invocado cuando ocurre un error asíncrono
Método @OnMessage
@ServerEndpoint(…)
public class ChatServerEndpoint
{
...
@OnMessage
public void onMessage(ChatMessage cmessage, Session session)
{
...
}
...
}
Método invocado cuando se recibe un mensaje
Clase ChatMessage
public class ChatMessage
{
private String sender;
private String message;
public ChatMessage(String sender, String message)
{
[Link] = sender;
[Link] = message;
}
public String getSender()
{
return sender;
}
public String getMessage()
{
return message;
}
}
Clase ChatMessageDecoder
import [Link].*;
public class ChatMessageDecoder implements [Link]<ChatMessage>
{
...
@Override
public ChatMessage decode(String json)
throws DecodeException
{
... parse json and obtain sender and message
return new ChatMessage(sender, message);
}
...
}
Convierte un String en un objeto ChatMessage
[Link]
import [Link].*;
import [Link].*;
...
@Override
public ChatMessage decode(String json)
throws DecodeException
{
StringReader textReader = new StringReader(json);
JsonReader jsonReader = [Link](textReader);
JsonObject jsonObject = [Link]();
String sender = [Link]("sender", null);
String message = [Link]("message", null);
return new ChatMessage(sender, message);
}
Clase ChatMessageEncoder
import [Link].*;
public class ChatMessageEncoder implements [Link]<ChatMessage>
{
...
@Override
public String encode(ChatMessage cmessage)
throws EncodeException
{
... build json string using cmessage fields
return json;
}
...
}
Convierte un objeto ChatMessage en un String
[Link]
import [Link].*;
import [Link].*;
...
@Override
public String encode(ChatMessage cmessage)
throws EncodeException
{
String sender = [Link]();
String message = [Link]();
JsonObjectBuilder builder = [Link]();
if (sender != null) [Link]("sender", sender);
if (message != null) [Link]("message", message);
return [Link]().toString();
}
WebSocket Client Endpoint
◼ Requiere una clase “Client Endpoint”
◼ Decorada con @ClientEndpoint(…)
◼ Con método @OnOpen
◼ Invocado cuando se abre una sesión
◼ Con método @OnClose
◼ Invocado cuando se cierra una sesión
◼ Con método @OnMessage
◼ Invocado cuando se recibe un mensaje
◼ Con método @OnError
◼ Invocado cuando ocurre un error asíncrono
Clase Client Endpoint
import [Link].*;
@ClientEndpoint(
encoders = [Link],
decoders = [Link])
public class ChatClientEndpoint
{
@OnOpen {...}
@OnClose {...}
@OnMessage {...}
@OnError {...}
public static void main(String[] args) {...}
}
Método main del cliente
public static void main(String[] args)
{
String host = [Link]("host", "localhost:8080");
URI path = new URI("[Link] + host + "/SampleWebSocketWeb/chat");
WebSocketContainer container = [Link]();
ChatClientEndpoint client = new ChatClientEndpoint();
try (Session session = [Link](client, path)) {
for (;;) {
[Link]("> ");
String line = [Link](); ☺
if (line == null || [Link]("quit")) break;
[Link]().sendObject(new ChatMessage(user, line));
}
}
}
Bibliotecas para clientes Java
◼ API de WebSocket ([Link].*)
◼ [Link]
◼ API de JSON ([Link].*)
◼ [Link]
◼ Descargar desde Maven Repository
◼ [Link]
◼ Estas bibliotecas ya forman parte de los
servidores JEE, y no se necesitan para
construir ni ejecutar Server Endpoints
Cliente HTML WebSocket
◼ Las API de WebSocket están incluidas en todos
los navegadores (browsers) modernos
◼ Documento con detalles de compatibilidad:
◼ [Link]
◼ En JavaScript se programa los mismos eventos que
usamos para construir Server y Client Endpoinds:
◼ OnOpen, OnClose, OnError y OnMessage
◼ Los mensajes son normalmente strings JSON
JavaScript y WebSocket
...
var websocket;
function initWebSocket() {
var wsURL = "[Link] + [Link] + "/chat/room";
websocket = new WebSocket(wsURL);
[Link] = function(event) {
displayOutput("Connected to " + wsURL);
};
[Link] = function(event) {
displayOutput("Disconnected from " + wsURL);
};
[Link] = function(event) {
displayOutput("Received: " + [Link]);
};
[Link] = function(event) {
displayOutput("Error: " + [Link]);
};
}
[Link]("load", initWebSocket);
...
[Link]([Link]({"sender":sender, "message":message}));
Todos hablando con todos ☺
Muchas gracias