Need help implementing WebSocket in java - java

I'm working on an Web Application in which multiple users work on the same data (source is sql database)
I'm using
Netbeans 8.0.2
Tomcat 8.0.28
Maven 4.0.0
jquery-2.1.4
I want the server to push a message to all clients which have opened a WebSocket Connection to my server.
I found a lot of guides/tutorials on how to implement WebSockets but they all rely on the Client pushing something to the Server.
I just need the server to push a message to the Client.
Can any1 provide a short example on how to to this??
It just needs to be:
Client opens SocketConnection
JavaClass establishes connection
JavaClass method sends message/data to client
EDIT:
My setup right now:
On application startup I do the following:
startup.java
package com.mycompany.ssp;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import javax.servlet.ServletContextEvent;
public class Startup implements javax.servlet.ServletContextListener {
private static WebSocketServer socket_server = null;
// create singleton object Socket
getSocket();
public static WebSocketServer getSocket(){
if(socket_server == null) {
socket_server = new WebSocketServer();
}
return socket_server;
}
}
WebSocketServer.java
package com.mycompany.ssp;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint(value = "/socket")
public class WebSocketServer {
private static final Logger LOGGER = Logger.getLogger(WebSocketServer.class.getName());
private List<Session> session_list = new ArrayList<Session>();
WebSocketServer socket_server = Startup.getSocket();
public WebSocketServer() {
}
#OnOpen
public void onOpen(Session session) {
LOGGER.log(Level.INFO, "New connection with client: {0}",
session.getId());
socket_server.session_list.add(session);
}
#OnMessage
public String onMessage(String message, Session session) {
LOGGER.log(Level.INFO, "New message from Client [{0}]: {1}",
new Object[] {session.getId(), message});
return "Server received [" + message + "]";
}
#OnClose
public void onClose(Session session) {
LOGGER.log(Level.INFO, "Close connection for client: {0}",
session.getId());
socket_server.session_list.remove(session);
}
#OnError
public void onError(Throwable exception, Session session) {
LOGGER.log(Level.INFO, "Error for client: {0}", session.getId());
}
public void send(String message) throws IOException{
for(Session session: socket_server.session_list){
session.getBasicRemote().sendText(message);
}
}
}
I get an Error when trying to start my application.
Why does it happen?
Well, the Method getSocket() loops multiple times and everytime after
socket_server = new WebSocketServer(); the variable socket_server is still null, which should be initialized though.
Netbeans Apache TomcatEE Log:
SEVERE [http-nio-8080-exec-1050] org.apache.catalina.core.StandardContext.listenerStart Exception sending context initialized event to listener instance of class com.mycompany.ssp.Startup
java.lang.StackOverflowError
Does any1 have an idea why this is happening??

var websocket=new websocket(websocket_url);
Java Code
#ServerEndpoint(value = "/websocket/one")
public class WebsocketEndPoint {
public static List clients=new ArrayList();
#OnOpen
public void OnOpen(Session session, EndpointConfig config)
throws IOException {
//Save the endpoints session that opened the connection in List
}
#OnMessage
public void OnMessage(Session session, String message) {
}
#OnClose
public void OnClose(Session session, CloseReason reason) {
//remove from list
}
#OnError
public void OnError(Session session, Throwable throwable) {
}
}
}
3.
class Sender{
public void send(String message){
for(Session session:WebsocketEndPoint.clients){
session.getBasicRemote().sendText(message);
}
}
}
Hope this helps
And in Javascript u can use onMessage to get the message

Related

Use Actors to send data to Akka websockets

I am using Akka websockets to push data to some client.
This is what I have done so far:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import akka.NotUsed;
import akka.actor.ActorSystem;
import akka.http.javadsl.ConnectHttp;
import akka.http.javadsl.Http;
import akka.http.javadsl.ServerBinding;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.HttpResponse;
import akka.http.javadsl.model.ws.Message;
import akka.http.javadsl.model.ws.WebSocket;
import akka.japi.Function;
import akka.stream.ActorMaterializer;
import akka.stream.Materializer;
import akka.stream.javadsl.Flow;
import akka.stream.javadsl.Sink;
import akka.stream.javadsl.Source;
public class Server {
public static HttpResponse handleRequest(HttpRequest request) {
System.out.println("Handling request to " + request.getUri());
if (request.getUri().path().equals("/greeter")) {
final Flow<Message, Message, NotUsed> greeterFlow = greeterHello();
return WebSocket.handleWebSocketRequestWith(request, greeterFlow);
} else {
return HttpResponse.create().withStatus(404);
}
}
public static void main(String[] args) throws Exception {
ActorSystem system = ActorSystem.create();
try {
final Materializer materializer = ActorMaterializer.create(system);
final Function<HttpRequest, HttpResponse> handler = request -> handleRequest(request);
CompletionStage<ServerBinding> serverBindingFuture = Http.get(system).bindAndHandleSync(handler,
ConnectHttp.toHost("localhost", 8080), materializer);
// will throw if binding fails
serverBindingFuture.toCompletableFuture().get(1, TimeUnit.SECONDS);
System.out.println("Press ENTER to stop.");
new BufferedReader(new InputStreamReader(System.in)).readLine();
} finally {
system.terminate();
}
}
public static Flow<Message, Message, NotUsed> greeterHello() {
return Flow.fromSinkAndSource(Sink.ignore(),
Source.single(new akka.http.scaladsl.model.ws.TextMessage.Strict("Hello!")));
}
}
At the client side, I am successfully receiving a 'Hello!' message.
However, now I want to send data dynamically (preferably from an Actor), something like this:
import akka.actor.ActorRef;
import akka.actor.UntypedActor;
public class PushActor extends UntypedActor {
#Override
public void onReceive(Object message) {
if (message instanceof String) {
String statusChangeMessage = (String) message;
// How to push this message to a socket ??
} else {
System.out.println(String.format("'%s':\nReceived unknown message '%s'!", selfActorPath, message));
}
}
}
I am unable to find any example regarding this online.
The following is the software stack being used:
Java 1.8
akka-http 10.0.10
One - not necessarily very elegant - way of doing this is to use Source.actorRef and send the materialized actor somewhere (maybe a router actor?) depending on your requirements.
public static Flow<Message, Message, NotUsed> greeterHello() {
return Flow.fromSinkAndSourceMat(Sink.ignore(),
Source.actorRef(100, OverflowStrategy.fail()),
Keep.right()).mapMaterializedValue( /* send your actorRef to a router? */);
}
Whoever receives the actorRefs of the connected clients must be responsible for routing messages to them.

Format to send and receive data using wss (websocket)

I am working on Websocket currently. So do I send and receive data using wss protocol? I am already using HTTP post and get but need to upgrade to wss. Please help. Thanks in advance
if you are using standalone applications (console app) I recommend you to use java-websocket or if it's a JavaEE WebApp, Example:
package org.hectorvent.gpstracking.websocket;
import org.hectorvent.gpstracking.restful.model.PdaGeoData;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.Singleton;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#Singleton
#ServerEndpoint("/geodata")
public class WebSocketGmap {
private final Set<Session> clients = new HashSet();
#OnOpen
public void open(Session session) {
clients.add(session);
}
#OnMessage
public void onMessage(String message, Session session) {
// here you're going to received client messages.
}
#OnClose
public void close(Session session) {
clients.remove(session);
}
#OnError
public void onError(Throwable error) {
}
public void sendMessage(PdaGeoData pgd) {
for (Session client : clients) {
Future fu = client.getAsyncRemote()
.sendText(GsonUtils.toJson(pgd));
}
}
}

Abnormal CPU usage with WS server

I made a websocket server using Tyrus implementation and it takes 50 % of the cpu usage but I don't know why. At first I thought it was the processes besides but after that, I wrote an extremely simple ws server after that and it is still the same...
Here is a screenshot from the resource monitor (Windows Server 2008 R2) :
The server runs on a Intel(R) Xeon(R) CPU E5-2650 0 # 2.00 Ghz with 4GB Memory
I don't know the exact architecture...
The code of the simplified ws server :
package wstest;
import javax.websocket.DeploymentException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.glassfish.tyrus.server.Server;
public class Wstest {
private static final Logger logger = LogManager.getLogger();
public static void main(String[] args) {
runServer();
}
private static void runServer() {
Server server = new Server("localhost", 8025, "/tp", null, wsendpoint.class);
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
logger.info("Server stopped.");
}
});
try {
server.start();
logger.info("Server started.");
while (true) { }
} catch (DeploymentException ex) {
logger.fatal(ex);
}
}
}
package wstest;
import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
#ServerEndpoint(
value = "/test"
)
public class wsendpoint {
private static final Logger logger = LogManager.getLogger();
#OnOpen
public void onOpen(Session session) {
logger.info("Client " + session.getId() + " connected");
}
#OnClose
public void onClose(Session session, CloseReason closeReason) {
logger.info("Client " + session.getId() + " disconnected.");
}
#OnMessage
public void onMessage(String request, Session session) {
logger.info(session.getId() + " sent message : " + request);
}
#OnError
public void onError(Session session, Throwable t) {
logger.error("Error !", t);
}
}
Here are the librairies I used :
There is no limit on the while loop that keeps your server running. Because of this, the full cpu usage goes to making this as fast as possible, while nothing is happening. I'm pretty sure adding Thread.sleep(5) would solve the problem. Fixed it most of the times I needed to make a server that listened for a socket. However, I don't know if this is best practice.

websocket was forcibly closed by the remote host

hi guys im trying implement an example of send file through websocket using sendBinary method . I`m deploying server code in Tomcat 8.0.20 and client code using tyrus 1.8.3 implementation/provider . There are my server and client class :
Server code :
package socket;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint("/chat")
public class Server {
#OnOpen
public void onOpen(Session session) {
}
#OnClose
public void onClose(Session session,CloseReason closeReason) {
}
#OnError
public void onError(Throwable throwable){
throwable.printStackTrace();
}
#OnMessage
public void message(String message, Session session) throws IOException {
}
#OnMessage
public void message(Session session,ByteBuffer byteBuffer) throws IOException {
System.out.println(" Binary received ... ");
}
}
Client code :
package br.com.jslsolucoes.socket.client;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.concurrent.CountDownLatch;
import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.DeploymentException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
import org.apache.commons.io.IOUtils;
#ClientEndpoint
public class Client {
private static CountDownLatch latch;
#OnOpen
public void onOpen(Session session) throws IOException {
InputStream inputStream = getClass().getResourceAsStream(
"/myvideo.wmv");
byte[] buffer = new byte[8 * 1024];
while (IOUtils.read(inputStream, buffer) != 0) {
session.getBasicRemote().sendBinary(ByteBuffer.wrap(buffer));
}
}
#OnClose
public void onClose(Session session,CloseReason closeReason) throws IOException {
latch.countDown();
}
#OnMessage
public void processMessage(String message) {
}
#OnError
public void onError(Throwable throwable){
throwable.printStackTrace();
}
public static void main(String[] args) throws DeploymentException,
IOException, InterruptedException {
latch = new CountDownLatch(1);
WebSocketContainer container = ContainerProvider
.getWebSocketContainer();
String uri = "ws://localhost:8081/socket/chat";
Client client = new Client();
container.connectToServer(client, URI.create(uri));
latch.await();
}
}
its works ok but while uploading after a time about 30 seconds an exception is launched :
java.io.ioexception : an existing connection was forcibly closed by the remote host
at sun.nio.ch.SocketDispatcher.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
at sun.nio.ch.IOUtil.read(IOUtil.java:197)
at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:379)
at org.apache.tomcat.util.net.NioChannel.read(NioChannel.java:140)
at org.apache.coyote.http11.upgrade.NioServletInputStream.fillReadBuffer(NioServletInputStream.java:136)
at org.apache.coyote.http11.upgrade.NioServletInputStream.doRead(NioServletInputStream.java:80)
at org.apache.coyote.http11.upgrade.AbstractServletInputStream.read(AbstractServletInputStream.java:124)
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:51)
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:203)
at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:198)
at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:96)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:654)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1558)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1515)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Someone can help me with this problem ?

Where should I close my activemq connection (java, jersey)

I have a class annotated with #Path and in this class I have a method that handles a PUT request. Within this method I am using ActiveMQ to publish a message to a JMS topic every time this method is invoked. Everything works fine.
But now I want to add some clean up code (mainly, just closing the ActiveMQ connection). How can I do this?
#PUT
#Consumes(MediaType.TEXT_PLAIN)
public void putString(String myString) throws JMSException {
if (txtmessage != null && producer != null ){
txtmessage.clearBody();
txtmessage.setText(myString);
producer.send(txtmessage);
}
}
all the initialization is done in a static block.
So I want the connection to be up as long as the server is listening but I want to explicitly close it when the server goes down. Is there a way jersey lets you handle on close events?
Implement the
ServletContextListener: http://tomcat.apache.org/tomcat-7.0-doc/servletapi/javax/servlet/ServletContextListener.html
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.log4j.Logger;
public class MyContextListener implements ServletContextListener {
public final static String ACTIVE_MQ_SESSION = "ActiveMQSession";
public final static String ACTIVE_MQ_PRODUCER = "ActiveMQProducer";
Logger logger = Logger.getLogger(this.getClass());
private static final int ackMode = Session.AUTO_ACKNOWLEDGE;
private static final boolean transacted = false;
private static final String brokerUrl = "vm://localhost:61616";
private Connection connection;
private Session session;
private MessageProducer producer;
#Override
public void contextDestroyed(ServletContextEvent sce) {
try {
this.producer.close();
this.session.close();
this.connection.close();
} catch (JMSException e) {
logger.warn("tearDown()", e);
}
}
#Override
public void contextInitialized(ServletContextEvent sce) {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
brokerUrl);
try {
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(transacted, ackMode);
Destination destination = session.createQueue("queue");
producer = session.createProducer(destination);
ServletContext sc = sce.getServletContext();
sc.setAttribute(ACTIVE_MQ_SESSION, session);
sc.setAttribute(ACTIVE_MQ_PRODUCER, producer);
} catch (JMSException e) {
logger.warn("setup() failed to setup connection brokerUrl="
+ brokerUrl);
}
}
}
Register the listener in web.xml:
<web-app...>
<listener>
<listener-class>package.MyContextListener</listener-class>
</listener>
</web-app>
and then the servlet (from where you use the producer and session):
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.servlet.http.HttpServlet;
import javax.ws.rs.Consumes;
import javax.ws.rs.PUT;
import javax.ws.rs.core.MediaType;
public class MessageServlet extends HttpServlet {
#PUT
#Consumes(MediaType.TEXT_PLAIN)
public void putString(String myString) throws JMSException {
MessageProducer producer = (MessageProducer) getServletContext()
.getAttribute(MyContextListener.ACTIVE_MQ_PRODUCER);
Session session = (Session) getServletContext().getAttribute(
MyContextListener.ACTIVE_MQ_SESSION);
TextMessage txtmessage = session.createTextMessage();
if (txtmessage != null && producer != null) {
txtmessage.clearBody();
txtmessage.setText(myString);
producer.send(txtmessage);
}
}
}

Categories

Resources