Send messages from server to websocket clients - java

I'm building a websocket application using glassfish I need in a given event my server to send message to all connected clients. I can send and receive messages from both, but I am not able to use the class server to send messages.
My server class has the following body:
#ApplicationScoped
#ServerEndpoint("/actions")
public class DeviceWebSocketServer {
#Inject
private DeviceSessionHandler sessionHandler;
#OnOpen
public void open(Session session) {
sessionHandler.addSession(session);
}
#OnClose
public void close(Session session) {
sessionHandler.removeSession(session);
}
#OnError
public void onError(Throwable error) {
Logger.getLogger(DeviceWebSocketServer.class.getName()).log(Level.SEVERE, null, error);
}
#OnMessage
public void handleMessage(String message, Session session) {
System.out.println("Chegou uma mensagem: " + message);
System.out.println("Na sessao: " + session.getId());
try (JsonReader reader = Json.createReader(new StringReader(message))) {
JsonObject jsonMessage = reader.readObject();
if ("add".equals(jsonMessage.getString("action"))) {
Device device = new Device();
device.setName(jsonMessage.getString("name"));
device.setDescription(jsonMessage.getString("description"));
device.setType(jsonMessage.getString("type"));
device.setStatus("Off");
sessionHandler.addDevice(device);
}
if ("remove".equals(jsonMessage.getString("action"))) {
int id = (int) jsonMessage.getInt("id");
sessionHandler.removeDevice(id);
}
if ("toggle".equals(jsonMessage.getString("action"))) {
int id = (int) jsonMessage.getInt("id");
sessionHandler.toggleDevice(id);
}
}
}
How do I send messages to customers after receiving an event? Should I instantiate my class server?

Theres a example on howto send messages to all connected clients in this whiteboard app:
https://netbeans.org/kb/docs/javaee/maven-websocketapi.html
#ServerEndpoint(value="/whiteboardendpoint", encoders = {FigureEncoder.class}, decoders = {FigureDecoder.class})
public class MyWhiteboard {
private static Set<Session> peers = Collections.synchronizedSet(new HashSet<Session>());
#OnMessage
public void broadcastFigure(Figure figure, Session session) throws IOException, EncodeException {
System.out.println("broadcastFigure: " + figure);
for (Session peer : peers) {
if (!peer.equals(session)) {
peer.getBasicRemote().sendObject(figure);
}
}
}

Related

WebSocket Implementation in Java 11

So, I have the following code working for connecting to the socket.
But I am trying to invoke (or listen to) OnText event from the WebSocketListener, to get the data received from websocket.
Any help is much appreciated.
public class WebSocketListener implements WebSocket.Listener {
#Override
public void onOpen(WebSocket webSocket) {
webSocket.request(1);
_logger.trace("Connected to WebSocket.");
_logger.debug("WebSocket Listener has been opened for requests.");
WebSocket.Listener.super.onOpen(webSocket);
}
#Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
_logger.trace("onText: ", data);
webSocket.request(1);
_logger.info("onText() completed.");
JSONObject response = new JSONObject(data.toString());
//
// How to return it to the class requesting/listening on it?
//
return new CompletableFuture().newIncompleteFuture().thenAccept(System.out::println);
//return WebSocket.Listener.super.onText(webSocket, data, last);
}
#Override
public CompletionStage<?> onClose(WebSocket webSocket, int statusCode, String reason) {
_logger.debug("WebSocket Listener has been closed with statusCode: {}, and cause: {}",statusCode, reason);
webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
return new CompletableFuture<Void>();
//return WebSocket.Listener.super.onClose(webSocket, statusCode, reason);
}
#Override
public void onError(WebSocket webSocket, Throwable error) {
_logger.error("A " + error.getCause() + " exception was thrown.");
_logger.error("Message: " + error.getLocalizedMessage());
webSocket.abort();
}
#Override
public CompletionStage<?> onPing(WebSocket webSocket, ByteBuffer message){
webSocket.request(1);
_logger.trace("Ping: Client ---> Server");
_logger.trace(message.asCharBuffer().toString());
_logger.trace("Ping completed.");
// return new CompletableFuture().completedFuture​("Ping completed.").thenAccept(System.out::println);
return new CompletableFuture().newIncompleteFuture().thenAccept(System.out::println);
}
#Override
public CompletionStage<?> onPong(WebSocket webSocket, ByteBuffer message){
webSocket.request(1);
_logger.trace("Pong: Client ---> Server");
_logger.trace(message.asCharBuffer().toString());
//return new CompletableFuture().completedFuture​("Pong completed.").thenAccept(System.out::println);
_logger.trace("Pong completed.");
return new CompletableFuture().newIncompleteFuture().thenAccept(System.out::println);
}
}
Following is the WebSocketClient that would handle creating the socket, connect, reconnect, login, logout, getSession from the WebSocket API.
private static CompletableFuture<WebSocket> _websocket_cf;
private static WebSocket _webSocket;
public WebSocketClient() {
try {
_secure = true;
WebSocketListener wsListener = new WebSocketListener();
TrustingHttpClient client = HttpUtil.getDefaultHttpClient().addTrustedHost(10.200.60.15);
_websocket_cf = client
.newWebSocketBuilder()
.buildAsync(URI.create("wss://10.200.60.15/remoteapi"), wsListener); //
_webSocket = _websocket_cf.join();
_logger.info("WebSocket created.");
}
catch (Exception ex) {
_logger.error("Failed to create WebSocket. ", ex);
}
}
public WebSocket getWebSocket() { return _webSocket; }
.....
}
No, I would like to get the data received from OnText event, here in this method.
Public class SocketExample {
private WebSocketClient _wsc;
private void getData(){
_wsc = new WebSocketClient();
WebSocket ws = _wsc.getWebSocket();
// get the data received in OnText event here ?
}
}
Thanks for your help.

"Connection refused" Autobahn Android to Java EE Endpoint

I have a Java EE Endpoint set up on a Payara server to which I attempt to connect an Android client using Autobahn WebSockets. I have the following setup:
My WebSocket Endpoint on the server:
public class CommunicationSocket extends Endpoint {
#Override
public void onOpen(Session aSession, EndpointConfig aConfig) {
aSession.addMessageHandler(new MessageHandler.Whole<byte[]>() {
#Override
public void onMessage(byte[] aMessage) {
// Do something fun
}
});
}
}
I register the WebSocket as such:
public class RegisterSocket implements ServerApplicationConfig {
#Override
public Set<ServerEndpointConfig> getEndpointConfigs(
Set<Class<? extends Endpoint>> aEndpointClasses) {
Set<ServerEndpointConfig> result = new HashSet<>();
for (Class endpointClass : aEndpointClasses) {
if (endpointClass.equals(CommunicationSocket.class)) {
ServerEndpointConfig sec
= ServerEndpointConfig.Builder.create(endpointClass,
"/WebSocket").build();
result.add(sec);
}
}
return result;
}
#Override
public Set<Class<?>> getAnnotatedEndpointClasses(
Set<Class<?>> aScanned) {
return Collections.emptySet();
}
}
The WebSocket can now be reached att ws://localhost:46588/Server/WebSocket. I've confirmed that it works with the following javascript in chrome:
function WebSocketTest() {
if ("WebSocket" in window) {
ws = new WebSocket("ws://localhost:46588/Server/WebSocket");
ws.onopen = function() {
ws.send("Message to send");
alert("Message is sent...");
};
ws.onmessage = function (evt) {
var received_msg = evt.data;
alert("Message is received... \n" + received_msg);
};
} else {
// The browser doesn't support WebSocket
alert("WebSocket NOT supported by your Browser!");
}
}
However when I try to connect with my android client using autobahn, the socket closes without being able to establish a connection with the message "Connection refused". I use the following code in onCreate to connect (mSocket is a field of the activity class):
WebSocketHandler messageHandler = new WebSocketHandler() {
#Override
public void onOpen() {
System.out.println("Connected...");
}
#Override
public void onClose(int code, String reason) {
System.out.println("Socket closing: " + reason);
mSocket = null;
}
#Override
public void onTextMessage(String payload) {
System.out.println("Received: " + payload);
}
#Override
public void onBinaryMessage(byte[] payload) {
System.out.println("Message received: " + payload);
}
};
mSocket = new WebSocketConnection();
try {
String address = "ws://localhost:46588/Server/WebSocket";
mSocket.connect(address, messageHandler);
} catch (WebSocketException e) {
System.out.println("Could not connect to WebSocket: "
+ e.getMessage());
mSocket = null;
}
I have internet permissions i my manifest as so:
<uses-permission android:name="android.permission.INTERNET">
</uses-permission>
Is there anything in my code or approach that is wrong? Is it possible to log/catch the event of connecting (handshake or what not) in order to shed light onto why the connection is refused?
And as I got ready to post the question I googled one last time: lo and behold, localhost is not the localhost of the machine running the emulator (I guess it's the localhost of the emulated device). So use:
10.0.2.2:[port]
instead of
localhost:[port]
and it will be fine on the emulator (don't forget to change if running on an actual device)

get the value of OnMessage() websocket

I'm using websocket in the client side (javascript) and in the server side a java class.
This is my WordgameServerEndpoint side class
#ServerEndpoint(value = "/socket")
public class WordgameServerEndpoint {
private Logger logger = Logger.getLogger(this.getClass().getName());
#OnOpen
public void onOpen(Session session) {
logger.info("Connected ... " + session.getId());
}
#OnMessage
public String onMessage(String unscrambledWord, Session session) {
logger.info("Starting the game by sending first word");
return unscrambledWord;
}
#OnClose
public void onClose(Session session, CloseReason closeReason) {
logger.info(String.format("Session %s closed because of %s", session.getId(), closeReason));
}
}
This is the WebSocketServer class
public class WebSocketServer {
public static void main(String[] args) {
runServer();
}
public static void runServer() {
Server server = new Server("localhost", 9988, "/websockets", WordgameServerEndpoint.class);
try {
server.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Please press a key to stop the server.");
//reader.readLine();
System.out.println(reader.readLine());
} catch (Exception e) {
e.printStackTrace();
} finally {
server.stop();
}
}
}
and this is my javascript function to send message
$scope.savedata=function(){
socket= new WebSocket('ws://majed-PC:9988/websockets/socket');
socket.onopen= function() {
socket.send('hello');
};
};
How do I get the value of the sent message on the server side?
See
#OnMessage
public String onMessage(String unscrambledWord, Session session) {
logger.info("Starting the game by sending first word");
return unscrambledWord;
}
on server side. unscrambledWord is the received message. Your implementation just echoes it back, which might not be what you want to do - just place your logic there.

Jetty9 WebSocket Client - SessionFactory.createSession causes java.lang.NullPointerException

I'm new to Jerry, and trying to implement WebSocket Client on Jetty9.
I saw an example on Jetty8.
org.eclipse.jetty.websocket Class WebSocketClient
http://archive.eclipse.org/jetty/8.0.0.v20110901/apidocs/org/eclipse/jetty/websocket/WebSocketClient.html
to create a new instance of WebSocketClient is :
WebSocketClientFactory factory = new WebSocketClientFactory();
factory.start();
WebSocketClient client = factory.newWebSocketClient();
// Configure the client
WebSocket.Connection connection = client.open(new
URI("ws://127.0.0.1:8080/"), new WebSocket.OnTextMessage()
{
public void onOpen(Connection connection)
{
// open notification
}
public void onClose(int closeCode, String message)
{
// close notification
}
public void onMessage(String data)
{
// handle incoming message
}
}).get(5, TimeUnit.SECONDS);
connection.sendMessage("Hello World");
However, I've never seen a document for Jetty9 for this.
So far, referring to
org.eclipse.jetty.websocket.common
Interface SessionFactory
//----------------------------------------------
WebSocketSession createSession(URI requestURI,
EventDriver websocket,
LogicalConnection connection)
//----------------------------------------------
I've tried
private WebSocketSessionFactory factory = new WebSocketSessionFactory();
try
{
WebSocketSession session = factory.createSession(uri,
eventDriver, connection);
RemoteEndpoint ep = session.getRemote();
}
catch (Exception ex)
{
System.out.println("=ERROR= " + ex);
//=ERROR= java.lang.NullPointerException
}
private EventDriver eventDriver = new EventDriver()
{
#Override
public WebSocketPolicy getPolicy()
{
return null;
}
//......................................
#Override
public void incomingFrame(Frame frame)
{
}
};
private LogicalConnection connection = new LogicalConnection()
{
#Override
public void close()
{
}
//...............................
#Override
public void resume()
{
}
};
but I've encounter java.lang.NullPointerException
How do we implement Jetty9 WebSocket Client ??
Thanks for your advise.
Hope this helpful: EventClient.java

Can't send or receive presence with ASmack

I am trying to develop a XMPP chat client for Android (using Java connected to C#/Unity). I have got the Java -> Unity/C# connection working perfectly. I have also downloaded Asmack and can generate a library and my of wrapper class for initilazing a connection to a OpenFire XMPP server. However, I cannot seem to get Presence sent or recieved. I can log in, register new user and populate their roster, send messages, but cannot send any presence.
The code auto registrate users who never have used the app before. It also uses a preset friend list, and auto populates the roster with these friends.
The code is as follow (sorry for all the debug lines, can't use breakpoints when using Unity):
public class ASmackWrapper
{
private XMPPConnection connection;
private String[] friends;
private static final String eventClass = "ASmackEventListener";
private static ASmackWrapper wrapper;
public static ASmackWrapper instance()
{
System.out.println("instancecreator of ASmackWrapper 1!");
if (wrapper == null)
wrapper = new ASmackWrapper();
return wrapper;
}
public ASmackWrapper()
{
System.out.println("constructor of ASmackWrapper");
}
public boolean tryToRegister(String user, String pass){
AccountManager acManager = connection.getAccountManager();
try {
Map<String, String> attributes = new HashMap<String,String>();
attributes.put("email", "MY email");
acManager.createAccount(user, pass,attributes);
} catch (XMPPException e) {
System.out.println("cant autoregister user "+ user +" ... with pass: "+pass+" on server. error:" + e.getLocalizedMessage());
if (e.getLocalizedMessage().contains("conflict"))
return false; // Wrong password, since there is already an account with that id!
return false;
}
return true;
}
public void setFriends(String[] _friends) {
friends = _friends;
}
public void start(String host, String user, String pass)
{
System.out.println("Java: openConenction host:"+host);
ConnectionConfiguration cc = new ConnectionConfiguration(host,5222);
//cc.setSendPresence(true);
this.connection = new XMPPConnection(cc);
Connection.DEBUG_ENABLED = true;
try {
this.connection.connect();
} catch (XMPPException e) {
System.out.println("Error connecting to server");
return;
}
if(!this.connection.isConnected()) {
System.out.println("Java: is not connected");
onError("Connection failed");
return;
}
boolean loginStatus = login(user, pass);
if (!loginStatus) {
onError("Login Failed");
return;
}
RosterListener rl = new RosterListener() {
public void entriesAdded(Collection<String> addresses) {}
public void entriesUpdated(Collection<String> addresses) {}
public void entriesDeleted(Collection<String> addresses) {}
public void presenceChanged(Presence presence) {
System.out.println("presence changed!" + presence.getFrom() + " "+presence.getStatus());
onPresence(presence);
}
};
if (connection.getRoster() != null) {
connection.getRoster().setSubscriptionMode(Roster.SubscriptionMode.accept_all);
System.out.println("7");
connection.getRoster().addRosterListener(rl);
}
onAuthenticate("");
System.out.println("10");
//Set presence to online!
Presence presence = new Presence(Presence.Type.available);
presence.setStatus("Online, Programmatically!");
presence.setPriority(24);
presence.setMode(Presence.Mode.available);
connection.sendPacket(presence);
}
private void addFriends() throws Exception {
if (friends == null) {
System.out.println("No friends to add");
return;
}
System.out.println("Number of friends to add: "+friends.length);
for (int i = 0;i<friends.length;i++) {
System.out.println("Create user in roster: "+friends[i]);
connection.getRoster().createEntry("fb"+friends[i], "No name_",null);
}
}
private boolean login(String jid, String password) {
System.out.println("1");
boolean isLoggedIn=true;
try {
this.connection.login(jid, password);
} catch (XMPPException e) {
isLoggedIn=false;
}
System.out.println("2");
if(!isLoggedIn) {
boolean isRegistred = tryToRegister(jid,password);
if (isRegistred) {
connection.disconnect();
try {
connection.connect();
connection.login(jid, password);
} catch (XMPPException e) {
onError("Could not connect and login after registring");
return false;
}
} else {
return false;
}
}
try {
addFriends();
} catch (Exception e) {
onError("Could not add friends to roster");
}
ChatManager chatmanager = connection.getChatManager();
chatmanager.addChatListener(new ChatManagerListener()
{
public void chatCreated(final Chat chat, final boolean createdLocally)
{
System.out.println("OK Chat created!");
chat.addMessageListener(new MessageListener()
{
public void processMessage(Chat chat, Message message)
{
onMessage(chat, message);
}
});
}
});
return true;
}
public void sendMessage(String rec, String message) {
System.out.println("sendMessage(string,string) to host :"+connection.getHost());
Chat chat = connection.getChatManager().createChat(rec+"#"+connection.getHost(), new MessageListener() {
public void processMessage(Chat chat, Message message) {
// Print out any messages we get back to standard out.
System.out.println("Probably an error, since we got a instant reply on sent message. Received message body: " + message.getBody() + " from:"+message.getFrom() + " to:"+message.getTo());
}
});
try {
chat.sendMessage(message);
System.out.println("Message sent");
} catch (XMPPException e) {
System.out.println("Error sending message: "+e.toString());
e.printStackTrace();
}
}
public void logout () {
System.out.println("Login out...");
connection.disconnect();
}
public void getOnlineFriends() {
Roster roster = connection.getRoster();
Collection<RosterEntry> entries = roster.getEntries();
for(RosterEntry rosterEntry: entries) {
String user = rosterEntry.getUser();
Presence presence = roster.getPresence(user);
System.out.println("Presence : "+presence);
System.out.println("Presence type: "+presence.getType());
System.out.println("Presence mode: "+presence.getMode());
}
//Set presence to online!
Presence presence = new Presence(Presence.Type.available);
presence.setStatus("Online, Programmatically!");
presence.setPriority(24);
presence.setMode(Presence.Mode.available);
connection.sendPacket(presence);
}
private void onMessage(Chat chat, Message message) {
String m = ("Received message: " + (message != null ? message.getBody() : "NULL"));
System.out.println(m);
UnityPlayer.UnitySendMessage(eventClass, "Message", m);
}
private void onError(String message) {
UnityPlayer.UnitySendMessage(eventClass, "Error", message);
}
private void onAuthenticate(String message) {
UnityPlayer.UnitySendMessage(eventClass, "Authenticate", message);
}
private void onPresence(Presence presence) {
String user = presence.getFrom();
if (presence.getType() == Presence.Type.available)
UnityPlayer.UnitySendMessage(eventClass, "Online", user);
else
UnityPlayer.UnitySendMessage(eventClass, "Offline", user);
System.out.println("Java: Presence changed, from:" +presence.getFrom() + " type:"+presence.getType() + " toString:"+presence.toString());
}
}
The presence is checked in two ways, by setting a presence listener and by fetching the status after login. This SO page suggest waiting 5 sec before getting the precense: Unable to get presence of roster by using smack, openfire
I have tried that as well by calling getOnlineFriends from a button, more than 5 sec after login. The listener never gets called. It just fires once after login, once for each on the roster with a presence = null.
Edit: After turning on Debug mode on Asmack I see the following reply to my presence send message:
SENT <presence id="3sG7l-11"><status>Online, Programmatically!</status><priority>24</priority></presence>
RCV <presence id="6s7BX-5" to="787122012#xxx.tripnet.se/Smack" from="10000063946242" type="error">
<error code="404" type="cancel">
<remote-server-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
</error></presence>
The server log:
org.jivesoftware.openfire.nio.ConnectionHandler - Closing connection due to error while processing message:
<iq id="566-4" type="error" from="xxx.tripnet.se/f55aea72" to="xxx.tripnet.se">
<error /><error type="cancel" code="501">
<feature-not-implemented xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" /></error>
<ping xmlns="urn:xmpp:ping" /></iq>
java.lang.IllegalArgumentException: IQ must be of type 'set' or 'get'. Original IQ:
<iq id="566-4" type="error" from="xxx.tripnet.se/f55aea72" to="xxx.tripnet.se">
<error/><error type="cancel" code="501">
<feature-not-implemented xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error>
<ping xmlns="urn:xmpp:ping"/></iq>
at org.xmpp.packet.IQ.createResultIQ(IQ.java:384)
I have also tried to pass along setSendPresence = true to the connectionconfiguration passed in connect(), but no difference.
I have also tried to set the subscription mode manually in OpenFire server to "both" (from "none") on both users, but with no effect.
Got it working! It was probably due to that I did not use the correct format on my jid's in the roster list. The correct format had to be user#myserver.se, not just user.
Write a RosterListener and see if it works.
public void rosterOnlineStatus(){
Roster roster = connection.getRoster();
Presence status = new Presence(Type.available);
status.setStatus("Hello This is Phaneendra");
roster.addRosterListener(new RosterListener() {
#Override
public void presenceChanged(Presence presence) {
System.out.println(presence.getFrom()+ "is "+presence+" "+presence.getStatus());
presence.getStatus();
}
#Override
public void entriesUpdated(Collection<String> addresses) {}
#Override
public void entriesDeleted(Collection<String> addresses) {}
#Override
public void entriesAdded(Collection<String> addresses) {}
});
}
See if adding the RosterListener will work?

Categories

Resources