Java broadcast message websocket

websocketAcredito que possa ser útil dar uma olhada no WebSockets, que é uma tecnologia relativamente nova que promete tornar sites mais reativos, permitindo menor latência entre os usuários e o servidor.
Neste artigo vou mostrar um simples exemplos de envio de mensagem a todos conectado no servidor utilizando Websocket e Java.

O que é WebSocket?

Antes de começar com o código fonte, mas descobrir o que é a tecnologia.
O WebSocket é um protocolo que permite a comunicação entre o cliente e o servidor / nó de extremidade usando uma única conexão TCP.
Parecido com o http. A vantagem que o WebSocket tem sobre o HTTP é que o protocolo é full-duplex (permite a comunicação simultânea em dois sentidos) e seu cabeçalho é muito menor que o de um cabeçalho HTTP,
permitindo uma comunicação mais eficiente mesmo em pequenos pacotes de dados.

O ciclo de vida de um WebSocket é fácil de entender também:

O cliente envia ao servidor uma solicitação de handshake na forma de um cabeçalho de atualização HTTP com dados sobre o WebSocket ao qual está tentando se conectar.
O servidor responde à solicitação com outro cabeçalho HTTP, esta é a última vez que um cabeçalho HTTP é usado na conexão WebSocket. Se o handshake foi bem sucedido, o servidor envia um
cabeçalho HTTP dizendo ao cliente que está mudando para o protocolo WebSocket.
Agora uma conexão constante é aberta e o cliente eo servidor podem enviar qualquer número de mensagens umas às outras até que a conexão seja fechada. Essas mensagens têm apenas cerca de 2 bytes de sobrecarga.

Um Exemplo

A API do WebSocket foi introduzida com o Java EE7, neste exemplo vamos criar dois clientes, uma aplicação web e outra standalone, que enviará uma mensagem para o servidor e o servidor deverá espalhar a mensagem e responder a quem enviou a mensagem.

Neste exemplo, usarei o Eclipse, servidor Tomcat 8 e a biblioteca do nv-websocket-client para o cliente standalone.
Para o seu servidor, crie um aplicação Web.
Converta para um projeto Maven e adicione as seguintes linhas no pom.xml:


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>br.com.tsystems</groupId>
<artifactId>webSocket-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>

<properties>
<java-version>1.8</java-version>
<tomcat.version>8.0.30</tomcat.version>
<debug.code>true</debug.code>
</properties>

<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>${java-version}</source>
<target>${java-version}</target>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>

<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
</dependency>

<dependency>
<groupId>com.neovisionaries</groupId>
<artifactId>nv-websocket-client</artifactId>
<version>1.30</version>
</dependency>

<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

Crie seu EndPoint, classe Java responsável por receber as mensagens e espalha:


/**
* @ServerEndpoint poderá ser acessado por ws://localhost:8080/webSocket-example/echo
*/
@ServerEndpoint("/echo")
public class WebSocketDemo {
private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>());

@OnOpen
public void onOpen(final Session session) {
// Adicionar sessão
sessions.add(session);
}

@OnMessage
public String echo(Session currentSession, String message) {
synchronized (sessions) {
for (Session session : sessions) {
// enviar mensagens para todos os clientes com essão daquele que enviou.
if (session.isOpen() && !session.equals(currentSession)) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
return message;
}

@OnError
public void onError(Session session, Throwable thr) {
//Ocorrer erro
thr.printStackTrace();
}

@OnClose
public void onClose(final Session session) {
// remover a sessão
sessions.remove(session);
}
}

Crie o index.html com o código abaixo:

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
</head>

<body>
<meta charset="utf-8">
<title>Web Socket JavaScript Echo Client</title>
<script language="javascript" type="text/javascript">
 var wsUri = getRootUri() + "/webSocket-example/echo";

function getRootUri() {
 return "ws://" + (document.location.hostname == "" ? "localhost" : document.location.hostname) + ":" +
 (document.location.port == "" ? "8080" : document.location.port);
 }

function init() {
 output = document.getElementById("output");
 }

function send_echo() {

websocket = new WebSocket(wsUri);
 websocket.onopen = function (evt) {
 onOpen(evt)
 };
 websocket.onmessage = function (evt) {
 onMessage(evt)
 };
 websocket.onerror = function (evt) {
 onError(evt)
 };

}

function onOpen(evt) {
 writeToScreen("CONNECTED");
 doSend(textID.value);

}

function onMessage(evt) {
 writeToScreen("RECEIVED: " + evt.data);
 }

function onError(evt) {
 writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
 }

function doSend(message) {
 writeToScreen("SENT: " + message);
 websocket.send(message);
 }

function writeToScreen(message) {
 var pre = document.createElement("p");
 pre.style.wordWrap = "break-word";
 pre.innerHTML = message;
 //alert(output);
 output.appendChild(pre);
 }

window.addEventListener("load", init, false);

</script>
<h2 style="text-align: center;">WebSocket Echo Client</h2>
</br>
<div style="text-align: center;">
<form action="">
<input onclick="send_echo()" value="Press me" type="button">
<input id="textID" name="message" value="Hello WebSocket!" type="text">

</form>
</div>
<div id="output"></div>
</body>
</html>

Por fim, crie o código do cliente stantalone:


/**
* @author Andre Rezende
*/
public class EchoClient {
private static final String SERVER = "ws://localhost:8443/cms/app/echo";
private static final int TIMEOUT = 5000;

public static void main(String[] args) throws Exception {
EchoClient echoClient = new EchoClient();
WebSocket ws = null;
try {
ws = echoClient.connect();
ws.sendText(new Date() + " teste->1");
} finally {
// Close the WebSocket.
ws.disconnect();
}
}

/**
* Conectar no servidor de websocket.
*/
public WebSocket connect() throws IOException, WebSocketException {
return new WebSocketFactory().setConnectionTimeout(TIMEOUT).createSocket(SERVER)
.addListener(new WebSocketAdapter() {
// A text message arrived from the server.
public void onTextMessage(WebSocket websocket, String message) {
System.out.println(message);
}
}).addExtension(WebSocketExtension.PERMESSAGE_DEFLATE).connect();
}
}

Para testar primeiro realize o deploy do seu war no tomcat. Talvez o tomcat requisite a biblioteca tomcat-juli.jar. Ela poderá ser obtida pelo endereço http://www.java2s.com/Code/Jar/t/Downloadtomcatjulijar.htm.
Após realizar o download, descompacte-a no diretório lib do seu tomcat.
Servidor de aplicação (Tomcat) em execução, realizado o deploy sem qualquer erro no tomcat, está na hora de iniciarmos os testes.
Para executar o cliente standalone, basta executar a classe EchoClient. A classe enviará a mensagem “Data corrente ” + test->1.
Abra a aplicação WEB no seu browser pela URL: localhost:8080/webSocket-example/
Por último abra o site: http://www.websocket.org/echo.html. Ele permite realizar testes por web em seu servidor de Websocket. Em location adicione ws://localhost:8080/websocket-example/echo
Clique no botão Connect, escreva em Message a mensagem que deseja compartilhar e por fim clique em Send para enviar a mensagem. Instruções em inglês e um exemplo em HTML está disponível no mesmo link.
Sua aplicação web deverá receber a mesma mensagem enviada pelo último site.

Concluindo

Webscoket permite envio de mensagem de forma assincrona e com segurança.
Substitui a antiga abordagem de consultas aos dados através de refresh de tela ou de tempos em tempos, o que particularmente é ineficiente na maior parte dos casos. Torna a vida do desenvolvedor mais fácil.
É baseado no TCP, bi-derecional e full-duplex. Part do HTML5 e a W3C define a API Jscript. Suportador pela maior parte dos browsers e suas respectivas versões.
Sugestão, comece fazendo um teste simples e vá aumentando a complexidade de seu websocket. Adicione recursos de reconexão e mensagens do mais variados tipos como textos ou binários.
Boa diversão.
O código está disponível para download no Github 

Anúncios

Hibernate e Oracle

Depois de passar 1 dia investigando o problema com o hibernate, oracle no tomcat “org.hibernate.dialect.Oracle10gDialect cannot be cast to java.sql.Driver”, finalmente descobri a causa do problema.

Meu hibernate não estava definindo o dialect, somente o driver Oracle. Todos meus Junits funcionavam perfeitamente, porém quando realizada deploy, o hibernate reclamava e não carregava a entidade.

A resolução é simples, no arquivo persistence.xml deixe sempre as seguintes propriedades:

<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>

Lembrando que o persistence.xml deverá estar na pasta META-INF do seu projeto (jar ou war). Isso tudo dependerá da hierarquia de pasta de seu projeto.
Abraços,
André Rezende