From fda8efcfa7058aae75ed9b4e4e7a3d32d8aa6931 Mon Sep 17 00:00:00 2001 From: Gonzalo Gallotti Date: Fri, 8 Jul 2022 16:56:59 -0300 Subject: [PATCH 1/9] Improvements to WebSocket implementation --- .../internet/websocket/GXWebSocket.java | 17 ++---- .../internet/websocket/GXWebSocket.java | 17 ++---- .../main/java/com/genexus/Application.java | 20 +++++-- .../genexus/internet/GXWebNotification.java | 55 ++++++++----------- .../internet/websocket/GXWebSocketCommon.java | 4 +- ...ketAsync.java => IGXWebSocketService.java} | 2 +- 6 files changed, 55 insertions(+), 60 deletions(-) rename java/src/main/java/com/genexus/internet/websocket/{IGXWebSocketAsync.java => IGXWebSocketService.java} (81%) diff --git a/gxwebsocket/src/main/java/com/genexus/internet/websocket/GXWebSocket.java b/gxwebsocket/src/main/java/com/genexus/internet/websocket/GXWebSocket.java index f0143a655..c79df7bf0 100644 --- a/gxwebsocket/src/main/java/com/genexus/internet/websocket/GXWebSocket.java +++ b/gxwebsocket/src/main/java/com/genexus/internet/websocket/GXWebSocket.java @@ -7,21 +7,16 @@ import javax.websocket.OnOpen; import javax.websocket.server.ServerEndpoint; +import com.genexus.Application; import com.genexus.websocket.Session; @ServerEndpoint(value = "/gxwebsocket") -public class GXWebSocket extends GXWebSocketCommon implements IGXWebSocketAsync { - - private static GXWebSocket instance = null; - - public GXWebSocket(){ - instance = this; - } - - public static IGXWebSocketAsync getInstance() { - return instance; +public class GXWebSocket extends GXWebSocketCommon implements IGXWebSocketService { + + public GXWebSocket() { + Application.registerSocketService(this); } - + @OnOpen public void OnOpen (javax.websocket.Session session) { OnOpenCommon(new Session(session)); diff --git a/gxwebsocketjakarta/src/main/java/com/genexus/internet/websocket/GXWebSocket.java b/gxwebsocketjakarta/src/main/java/com/genexus/internet/websocket/GXWebSocket.java index 5d23a8232..6c53e2c6a 100644 --- a/gxwebsocketjakarta/src/main/java/com/genexus/internet/websocket/GXWebSocket.java +++ b/gxwebsocketjakarta/src/main/java/com/genexus/internet/websocket/GXWebSocket.java @@ -1,5 +1,6 @@ package com.genexus.internet.websocket; +import com.genexus.Application; import jakarta.websocket.CloseReason; import jakarta.websocket.OnClose; import jakarta.websocket.OnError; @@ -10,18 +11,12 @@ import com.genexus.websocket.Session; @ServerEndpoint(value = "/gxwebsocket") -public class GXWebSocket extends GXWebSocketCommon implements IGXWebSocketAsync { - - private static GXWebSocket instance = null; - - public GXWebSocket(){ - instance = this; - } - - public static IGXWebSocketAsync getInstance() { - return instance; +public class GXWebSocket extends GXWebSocketCommon implements IGXWebSocketService { + + public GXWebSocket(){ + Application.registerSocketService(this); } - + @OnOpen public void OnOpen (jakarta.websocket.Session session) { OnOpenCommon(new Session(session)); diff --git a/java/src/main/java/com/genexus/Application.java b/java/src/main/java/com/genexus/Application.java index 96214b021..f90eb54b4 100644 --- a/java/src/main/java/com/genexus/Application.java +++ b/java/src/main/java/com/genexus/Application.java @@ -3,10 +3,7 @@ import java.io.Closeable; import java.io.IOException; import java.sql.SQLException; -import java.util.Date; -import java.util.Enumeration; -import java.util.Properties; -import java.util.Vector; +import java.util.*; import com.genexus.db.DBConnectionManager; import com.genexus.db.DynamicExecute; @@ -15,6 +12,7 @@ import com.genexus.db.driver.ExternalProvider; import com.genexus.diagnostics.core.ILogger; import com.genexus.diagnostics.core.LogManager; +import com.genexus.internet.websocket.IGXWebSocketService; import com.genexus.specific.java.Connect; import com.genexus.util.GXQueue; import com.genexus.util.GXService; @@ -49,6 +47,7 @@ public class Application private static volatile ExternalProvider externalProvider = null; private static volatile ExternalProvider externalProviderAPI = null; + private static volatile HashMap services = new HashMap<>(); private static Object objectLock = new Object(); private static volatile boolean initialized = false; @@ -753,10 +752,23 @@ public static boolean getShowConnectError() static boolean useSmartCache = false; + public static com.genexus.GXSmartCacheProvider getSmartCacheProvider(int handle) { useSmartCache = true; return getConnectionManager().getUserInformation(handle).getSmartCacheProvider(); } + private static String WEBSOCKET_SERVICE_NAME = "WS_SERVER"; + + public static void registerSocketService(IGXWebSocketService wsService) { + services.put(WEBSOCKET_SERVICE_NAME, wsService); + } + + public static IGXWebSocketService getSocketService() { + if (services.containsKey(WEBSOCKET_SERVICE_NAME)) { + return (IGXWebSocketService) services.get(WEBSOCKET_SERVICE_NAME); + } + return null; + } } diff --git a/java/src/main/java/com/genexus/internet/GXWebNotification.java b/java/src/main/java/com/genexus/internet/GXWebNotification.java index 9f993d286..dc832805e 100644 --- a/java/src/main/java/com/genexus/internet/GXWebNotification.java +++ b/java/src/main/java/com/genexus/internet/GXWebNotification.java @@ -1,22 +1,21 @@ package com.genexus.internet; +import com.genexus.Application; import com.genexus.ModelContext; import com.genexus.diagnostics.core.ILogger; import com.genexus.diagnostics.core.LogManager; -import com.genexus.internet.websocket.IGXWebSocketAsync; +import com.genexus.internet.websocket.IGXWebSocketService; import com.genexus.internet.websocket.SendResponseType; import com.genexus.xml.GXXMLSerializable; public class GXWebNotification { public static final ILogger logger = LogManager.getLogger(GXWebNotification.class); - - private static IGXWebSocketAsync ws; + private static IGXWebSocketService _ws; private HttpContext _ctx; private short _errCode; private String _errDescription; - - + public short getErrCode() { return _errCode; @@ -30,26 +29,16 @@ public String getErrDescription() public GXWebNotification(ModelContext gxContext) { _ctx = (HttpContext) gxContext.getHttpContext(); - if (ws == null) - { - try { - setError((short)1); - Class c = Class.forName("com.genexus.internet.websocket.GXWebSocket"); - java.lang.reflect.Method method = c.getDeclaredMethod("getInstance", (Class[])null); - Object o = method.invoke(null, (Object[])null); - ws = (IGXWebSocketAsync)o; - if (ws != null) - setError((short)0); - } catch (Exception e) { - logger.error("GXWebNotification", e); - } - } - if (_errCode != 0) + } + + private IGXWebSocketService getWSService() { + if (_ws == null) { - logger.error("Could not create com.genexus.internet.GXWebSocket instance. Check whether WebServer requirements are met and WebNotifications Provider Generator Property is set"); + _ws = Application.getSocketService(); } - } - + return _ws; + } + public short notifyClient(String clientId, String message) { return notifyClientImpl(clientId, message); @@ -62,8 +51,9 @@ public short notifyClient(String clientId, GXXMLSerializable message) } public short notifyClientImpl(String clientId, String message) - { - if (ws != null) + { + IGXWebSocketService ws = getWSService(); + if (ws != null) { SendResponseType result = ws.send(clientId.trim(), message); switch (result) @@ -84,8 +74,9 @@ public short notifyClientImpl(String clientId, String message) break; } } - else - setError((short)1); + else { + setError((short) 1); + } return _errCode; } @@ -113,14 +104,16 @@ public void broadcast(String message) } private void broadcastImpl(String message) - { + { + IGXWebSocketService ws = getWSService(); if (ws != null) { ws.broadcast(message); setError((short)0); } - else - setError((short)1); + else { + setError((short) 1); + } } private void setError(short i) @@ -132,7 +125,7 @@ private void setError(short i) _errDescription = "OK"; break; case 1: - _errDescription = "Could not start WebSocket Server"; + _errDescription = "WebSocket Server has not been initialized yet"; break; case 2: _errDescription = "WebSocket Session not found"; diff --git a/java/src/main/java/com/genexus/internet/websocket/GXWebSocketCommon.java b/java/src/main/java/com/genexus/internet/websocket/GXWebSocketCommon.java index f4e6e49f7..5de7ec3d9 100644 --- a/java/src/main/java/com/genexus/internet/websocket/GXWebSocketCommon.java +++ b/java/src/main/java/com/genexus/internet/websocket/GXWebSocketCommon.java @@ -15,7 +15,7 @@ import com.genexus.xml.GXXMLSerializable; import com.genexus.websocket.ISession; -public class GXWebSocketCommon { +public abstract class GXWebSocketCommon { private static String[] handlerCache = new String[HandlerType.values().length]; @@ -26,7 +26,7 @@ public class GXWebSocketCommon { public enum HandlerType { ReceivedMessage, OnOpen, OnClose, OnError } - + public void closedSession(GXWebSocketSession session) { wsClients.remove(session); diff --git a/java/src/main/java/com/genexus/internet/websocket/IGXWebSocketAsync.java b/java/src/main/java/com/genexus/internet/websocket/IGXWebSocketService.java similarity index 81% rename from java/src/main/java/com/genexus/internet/websocket/IGXWebSocketAsync.java rename to java/src/main/java/com/genexus/internet/websocket/IGXWebSocketService.java index 314fdadc9..e929e7465 100644 --- a/java/src/main/java/com/genexus/internet/websocket/IGXWebSocketAsync.java +++ b/java/src/main/java/com/genexus/internet/websocket/IGXWebSocketService.java @@ -1,6 +1,6 @@ package com.genexus.internet.websocket; -public interface IGXWebSocketAsync { +public interface IGXWebSocketService { boolean start(); SendResponseType send(String clientId, String message); void broadcast(String message); From 0fedb541d67d7f8d82b37118e57be46414329519 Mon Sep 17 00:00:00 2001 From: Gonzalo Gallotti Date: Fri, 8 Jul 2022 17:10:45 -0300 Subject: [PATCH 2/9] Add logging --- java/src/main/java/com/genexus/Application.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/java/src/main/java/com/genexus/Application.java b/java/src/main/java/com/genexus/Application.java index f90eb54b4..5091f096d 100644 --- a/java/src/main/java/com/genexus/Application.java +++ b/java/src/main/java/com/genexus/Application.java @@ -762,7 +762,10 @@ public static com.genexus.GXSmartCacheProvider getSmartCacheProvider(int handle) private static String WEBSOCKET_SERVICE_NAME = "WS_SERVER"; public static void registerSocketService(IGXWebSocketService wsService) { - services.put(WEBSOCKET_SERVICE_NAME, wsService); + if (wsService != null) { + services.put(WEBSOCKET_SERVICE_NAME, wsService); + logger.info("WebSocket Service has been initialized successfully"); + } } public static IGXWebSocketService getSocketService() { From 8e88105992be48b6a73557aef90700cfe6e62344 Mon Sep 17 00:00:00 2001 From: Gonzalo Date: Thu, 14 Jul 2022 09:41:05 -0300 Subject: [PATCH 3/9] Resolve @iroqueta review --- java/src/main/java/com/genexus/Application.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/java/src/main/java/com/genexus/Application.java b/java/src/main/java/com/genexus/Application.java index 5091f096d..1917e0518 100644 --- a/java/src/main/java/com/genexus/Application.java +++ b/java/src/main/java/com/genexus/Application.java @@ -761,17 +761,15 @@ public static com.genexus.GXSmartCacheProvider getSmartCacheProvider(int handle) private static String WEBSOCKET_SERVICE_NAME = "WS_SERVER"; - public static void registerSocketService(IGXWebSocketService wsService) { - if (wsService != null) { - services.put(WEBSOCKET_SERVICE_NAME, wsService); - logger.info("WebSocket Service has been initialized successfully"); - } + public static void registerSocketService(IGXWebSocketService wsService) { + services.put(WEBSOCKET_SERVICE_NAME, wsService); + logger.info("WebSocket Service has been initialized successfully"); } public static IGXWebSocketService getSocketService() { if (services.containsKey(WEBSOCKET_SERVICE_NAME)) { return (IGXWebSocketService) services.get(WEBSOCKET_SERVICE_NAME); } - return null; + return null; } } From 30e7a1a53b5985ffe9c9d26c18557b909f59f3da Mon Sep 17 00:00:00 2001 From: Gonzalo Date: Thu, 14 Jul 2022 09:45:43 -0300 Subject: [PATCH 4/9] Improve messages --- .../main/java/com/genexus/internet/GXWebNotification.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/java/src/main/java/com/genexus/internet/GXWebNotification.java b/java/src/main/java/com/genexus/internet/GXWebNotification.java index dc832805e..b745569c3 100644 --- a/java/src/main/java/com/genexus/internet/GXWebNotification.java +++ b/java/src/main/java/com/genexus/internet/GXWebNotification.java @@ -125,16 +125,16 @@ private void setError(short i) _errDescription = "OK"; break; case 1: - _errDescription = "WebSocket Server has not been initialized yet"; + _errDescription = "WebSocket Server has not been initialized yet. No incoming connections were received"; break; case 2: - _errDescription = "WebSocket Session not found"; + _errDescription = "WebSocket Session not found. The client is not connected to socket server"; break; case 3: - _errDescription = "WebSocket Session is closed or invalid"; + _errDescription = "WebSocket Session was found, but it's state was closed or invalid"; break; case 4: - _errDescription = "Message could not be delivered to client"; + _errDescription = "Message could not be delivered to client because of a connection error"; break; default: _errDescription = "Unknown error"; From 76e7b4dfe92c313156f1d7090514680fe5b66a7a Mon Sep 17 00:00:00 2001 From: Gonzalo Gallotti Date: Fri, 15 Jul 2022 12:47:02 -0300 Subject: [PATCH 5/9] @iroqueta review --- java/src/main/java/com/genexus/Application.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/java/src/main/java/com/genexus/Application.java b/java/src/main/java/com/genexus/Application.java index 1917e0518..c3957c5a3 100644 --- a/java/src/main/java/com/genexus/Application.java +++ b/java/src/main/java/com/genexus/Application.java @@ -767,9 +767,6 @@ public static void registerSocketService(IGXWebSocketService wsService) { } public static IGXWebSocketService getSocketService() { - if (services.containsKey(WEBSOCKET_SERVICE_NAME)) { - return (IGXWebSocketService) services.get(WEBSOCKET_SERVICE_NAME); - } - return null; + return (IGXWebSocketService) services.get(WEBSOCKET_SERVICE_NAME); } } From 768bf3b44baea69c2f4434e75d50eb749b5bcde4 Mon Sep 17 00:00:00 2001 From: Gonzalo Gallotti Date: Fri, 15 Jul 2022 16:05:04 -0300 Subject: [PATCH 6/9] Refactoring and improvements --- .../internet/websocket/GXWebSocket.java | 28 ++- .../java/com/genexus/websocket/Session.java | 2 +- .../internet/websocket/GXWebSocket.java | 42 ++-- .../java/com/genexus/websocket/Session.java | 4 +- .../main/java/com/genexus/Application.java | 13 +- .../genexus/internet/GXWebNotification.java | 102 ++++----- .../internet/websocket/GXWebSocketCommon.java | 188 ---------------- .../websocket/GXWebSocketService.java | 200 ++++++++++++++++++ .../websocket/GXWebSocketSession.java | 2 +- .../websocket/IGXWebSocketService.java | 1 - .../genexus/webpanels/GXWebObjectStub.java | 2 +- .../java/com/genexus/websocket/ISession.java | 2 +- 12 files changed, 280 insertions(+), 306 deletions(-) delete mode 100644 java/src/main/java/com/genexus/internet/websocket/GXWebSocketCommon.java create mode 100644 java/src/main/java/com/genexus/internet/websocket/GXWebSocketService.java diff --git a/gxwebsocket/src/main/java/com/genexus/internet/websocket/GXWebSocket.java b/gxwebsocket/src/main/java/com/genexus/internet/websocket/GXWebSocket.java index c79df7bf0..fa67436e4 100644 --- a/gxwebsocket/src/main/java/com/genexus/internet/websocket/GXWebSocket.java +++ b/gxwebsocket/src/main/java/com/genexus/internet/websocket/GXWebSocket.java @@ -11,43 +11,41 @@ import com.genexus.websocket.Session; @ServerEndpoint(value = "/gxwebsocket") -public class GXWebSocket extends GXWebSocketCommon implements IGXWebSocketService { +public class GXWebSocket implements IGXWebSocketService { + + private GXWebSocketService wsService; public GXWebSocket() { - Application.registerSocketService(this); + wsService = GXWebSocketService.getService(); } @OnOpen - public void OnOpen (javax.websocket.Session session) { - OnOpenCommon(new Session(session)); + public void OnOpen(javax.websocket.Session session) { + wsService.onOpen(new Session(session)); } @OnMessage - public void OnMessage (String txt, javax.websocket.Session session) { - OnMessageCommon(txt, new Session(session)); + public void OnMessage(String txt, javax.websocket.Session session) { + wsService.onMessage(txt, new Session(session)); } @OnClose - public void myOnClose (javax.websocket.Session session, CloseReason reason) { - myOnCloseCommon(new Session(session)); + public void myOnClose(javax.websocket.Session session, CloseReason reason) { + wsService.onClose(new Session(session)); } @OnError public void onError(Throwable exception, javax.websocket.Session session) { - onErrorCommon(exception, new Session(session)); + wsService.onError(exception, new Session(session)); } public SendResponseType send(String clientId, String message) { - return sendCommon(clientId, message); + return wsService.send(clientId, message); } public void broadcast(String message) { - broadcastCommon(message); + wsService.broadcast(message); } - - public boolean start() { - return true; - } } diff --git a/gxwebsocket/src/main/java/com/genexus/websocket/Session.java b/gxwebsocket/src/main/java/com/genexus/websocket/Session.java index 7d41df17b..84a959ab9 100644 --- a/gxwebsocket/src/main/java/com/genexus/websocket/Session.java +++ b/gxwebsocket/src/main/java/com/genexus/websocket/Session.java @@ -14,7 +14,7 @@ public Integer getHashCode() { return new Integer(session.hashCode()); } - public String getQueryString() { + public String getId() { return session.getQueryString(); } diff --git a/gxwebsocketjakarta/src/main/java/com/genexus/internet/websocket/GXWebSocket.java b/gxwebsocketjakarta/src/main/java/com/genexus/internet/websocket/GXWebSocket.java index 6c53e2c6a..99f3d8d2a 100644 --- a/gxwebsocketjakarta/src/main/java/com/genexus/internet/websocket/GXWebSocket.java +++ b/gxwebsocketjakarta/src/main/java/com/genexus/internet/websocket/GXWebSocket.java @@ -11,43 +11,41 @@ import com.genexus.websocket.Session; @ServerEndpoint(value = "/gxwebsocket") -public class GXWebSocket extends GXWebSocketCommon implements IGXWebSocketService { +public class GXWebSocket implements IGXWebSocketService { - public GXWebSocket(){ - Application.registerSocketService(this); + private GXWebSocketService wsService; + + public GXWebSocket() { + wsService = GXWebSocketService.getService(); } @OnOpen - public void OnOpen (jakarta.websocket.Session session) { - OnOpenCommon(new Session(session)); + public void OnOpen(jakarta.websocket.Session session) { + wsService.onOpen(new Session(session)); } - + @OnMessage - public void OnMessage (String txt, jakarta.websocket.Session session) { - OnMessageCommon(txt, new Session(session)); + public void OnMessage(String txt, jakarta.websocket.Session session) { + wsService.onMessage(txt, new Session(session)); } @OnClose - public void myOnClose (jakarta.websocket.Session session, CloseReason reason) { - myOnCloseCommon(new Session(session)); + public void myOnClose(jakarta.websocket.Session session, CloseReason reason) { + wsService.onClose(new Session(session)); } - + @OnError - public void onError(Throwable exception, jakarta.websocket.Session session) { - onErrorCommon(exception, new Session(session)); - } - + public void onError(Throwable exception, jakarta.websocket.Session session) { + wsService.onError(exception, new Session(session)); + } + public SendResponseType send(String clientId, String message) { - return sendCommon(clientId, message); + return wsService.send(clientId, message); } - + public void broadcast(String message) { - broadcastCommon(message); + wsService.broadcast(message); } - - public boolean start() { - return true; - } } diff --git a/gxwebsocketjakarta/src/main/java/com/genexus/websocket/Session.java b/gxwebsocketjakarta/src/main/java/com/genexus/websocket/Session.java index b7da86f30..edf07c796 100644 --- a/gxwebsocketjakarta/src/main/java/com/genexus/websocket/Session.java +++ b/gxwebsocketjakarta/src/main/java/com/genexus/websocket/Session.java @@ -3,7 +3,7 @@ import jakarta.websocket.RemoteEndpoint; import java.io.IOException; -public class Session implements ISession{ +public class Session implements ISession { private jakarta.websocket.Session session; public Session(jakarta.websocket.Session session) { @@ -14,7 +14,7 @@ public Integer getHashCode() { return new Integer(session.hashCode()); } - public String getQueryString() { + public String getId() { return session.getQueryString(); } diff --git a/java/src/main/java/com/genexus/Application.java b/java/src/main/java/com/genexus/Application.java index c3957c5a3..3bedad3bd 100644 --- a/java/src/main/java/com/genexus/Application.java +++ b/java/src/main/java/com/genexus/Application.java @@ -757,16 +757,5 @@ public static com.genexus.GXSmartCacheProvider getSmartCacheProvider(int handle) { useSmartCache = true; return getConnectionManager().getUserInformation(handle).getSmartCacheProvider(); - } - - private static String WEBSOCKET_SERVICE_NAME = "WS_SERVER"; - - public static void registerSocketService(IGXWebSocketService wsService) { - services.put(WEBSOCKET_SERVICE_NAME, wsService); - logger.info("WebSocket Service has been initialized successfully"); - } - - public static IGXWebSocketService getSocketService() { - return (IGXWebSocketService) services.get(WEBSOCKET_SERVICE_NAME); - } + } } diff --git a/java/src/main/java/com/genexus/internet/GXWebNotification.java b/java/src/main/java/com/genexus/internet/GXWebNotification.java index b745569c3..14da7995d 100644 --- a/java/src/main/java/com/genexus/internet/GXWebNotification.java +++ b/java/src/main/java/com/genexus/internet/GXWebNotification.java @@ -1,44 +1,36 @@ package com.genexus.internet; -import com.genexus.Application; import com.genexus.ModelContext; import com.genexus.diagnostics.core.ILogger; import com.genexus.diagnostics.core.LogManager; -import com.genexus.internet.websocket.IGXWebSocketService; +import com.genexus.internet.websocket.GXWebSocketService; import com.genexus.internet.websocket.SendResponseType; import com.genexus.xml.GXXMLSerializable; public class GXWebNotification { public static final ILogger logger = LogManager.getLogger(GXWebNotification.class); - private static IGXWebSocketService _ws; - private HttpContext _ctx; + private GXWebSocketService wsService; + private HttpContext httpContext; - private short _errCode; - private String _errDescription; + private short errCode; + private String errDescription; public short getErrCode() { - return _errCode; + return errCode; } public String getErrDescription() { - return _errDescription; + return errDescription; } public GXWebNotification(ModelContext gxContext) - { - _ctx = (HttpContext) gxContext.getHttpContext(); + { + wsService = GXWebSocketService.getService(); + httpContext = (HttpContext) gxContext.getHttpContext(); } - private IGXWebSocketService getWSService() { - if (_ws == null) - { - _ws = Application.getSocketService(); - } - return _ws; - } - public short notifyClient(String clientId, String message) { return notifyClientImpl(clientId, message); @@ -52,44 +44,37 @@ public short notifyClient(String clientId, GXXMLSerializable message) public short notifyClientImpl(String clientId, String message) { - IGXWebSocketService ws = getWSService(); - if (ws != null) + SendResponseType result = wsService.send(clientId.trim(), message); + switch (result) { - SendResponseType result = ws.send(clientId.trim(), message); - switch (result) - { - case OK: - setError((short)0); - break; - case SessionNotFound: - setError((short)2); - break; - case SessionInvalid: - setError((short)3); - break; - case SendFailed: - setError((short)4); - break; - default: - break; - } - } - else { - setError((short) 1); + case OK: + setError((short)0); + break; + case SessionNotFound: + setError((short)2); + break; + case SessionInvalid: + setError((short)3); + break; + case SendFailed: + setError((short)4); + break; + default: + break; } - - return _errCode; + + return errCode; } public short notify(String message) { - return notifyClient(_ctx.getClientId(), message); + return notifyClient(httpContext.getClientId(), message); } public short notify(GXXMLSerializable message) { - return notifyClient(_ctx.getClientId(), message); + return notifyClient(httpContext.getClientId(), message); } @@ -105,45 +90,38 @@ public void broadcast(String message) private void broadcastImpl(String message) { - IGXWebSocketService ws = getWSService(); - if (ws != null) - { - ws.broadcast(message); - setError((short)0); - } - else { - setError((short) 1); - } + wsService.broadcast(message); + setError((short)0); } private void setError(short i) { - this._errCode = i; + this.errCode = i; switch (i) { case 0: - _errDescription = "OK"; + errDescription = "OK"; break; case 1: - _errDescription = "WebSocket Server has not been initialized yet. No incoming connections were received"; + errDescription = "WebSocket Server has not been initialized yet. No incoming connections were received"; break; case 2: - _errDescription = "WebSocket Session not found. The client is not connected to socket server"; + errDescription = "WebSocket Session not found. The client is not connected to socket server"; break; case 3: - _errDescription = "WebSocket Session was found, but it's state was closed or invalid"; + errDescription = "WebSocket Session was found, but it's state was closed or invalid"; break; case 4: - _errDescription = "Message could not be delivered to client because of a connection error"; + errDescription = "Message could not be delivered to client because of a connection error"; break; default: - _errDescription = "Unknown error"; + errDescription = "Unknown error"; break; } } public String getClientId() { - return _ctx.getClientId(); + return httpContext.getClientId(); } } diff --git a/java/src/main/java/com/genexus/internet/websocket/GXWebSocketCommon.java b/java/src/main/java/com/genexus/internet/websocket/GXWebSocketCommon.java deleted file mode 100644 index 5de7ec3d9..000000000 --- a/java/src/main/java/com/genexus/internet/websocket/GXWebSocketCommon.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.genexus.internet.websocket; - -import java.io.IOException; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; - -import json.org.json.JSONObject; - -import com.genexus.Application; -import com.genexus.GXutil; -import com.genexus.ModelContext; -import com.genexus.db.DynamicExecute; -import com.genexus.util.GXService; -import com.genexus.util.GXServices; -import com.genexus.xml.GXXMLSerializable; -import com.genexus.websocket.ISession; - -public abstract class GXWebSocketCommon { - - private static String[] handlerCache = new String[HandlerType.values().length]; - - private static GXWebSocketSessionCollection wsClients = new GXWebSocketSessionCollection(); - - private ConcurrentHashMap sessions = new ConcurrentHashMap(); - - public enum HandlerType { - ReceivedMessage, OnOpen, OnClose, OnError - } - - public void closedSession(GXWebSocketSession session) - { - wsClients.remove(session); - } - - protected void OnOpenCommon (ISession session) { - GXWebSocketSession client = getGXWebSocketSession(session); - wsClients.put(client); - - Object[] parms = new Object[1]; - parms[0] = client.getId(); - ExecuteHandler(HandlerType.OnOpen, parms); - } - - protected void OnMessageCommon (String txt, ISession session) { - Object[] parms = new Object[2]; - parms[0] = getGXWebSocketSession(session).getId(); - - try { - - GXXMLSerializable nInfo = (GXXMLSerializable) Class.forName("com.genexuscore.genexus.server.SdtNotificationInfo").getConstructor().newInstance(); - JSONObject jInfo = new JSONObject(); - jInfo.put("Message", txt); - nInfo.FromJSONObject(jInfo); - parms[1] = nInfo; - ExecuteHandler(HandlerType.ReceivedMessage, parms); - - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private void ExecuteHandler(HandlerType type, Object[] parameters){ - String handler = getHandlerClassName(type); - if (handler != null){ - try { - if (!DynamicExecute.dynamicExecute(ModelContext.getModelContext(GXutil.class), -1, Application.class, handler, parameters)){ - System.out.println("GXWebSocket - Handler could not be executed: " + handler); - } - } - catch (Exception e){ - System.out.println("GXWebSocket - Handler failed executing action: " + handler); - e.printStackTrace(); - } - } - } - - private String getPtyTypeName(HandlerType type){ - String typeName = ""; - switch(type) - { - case ReceivedMessage: - typeName = "WEBNOTIFICATIONS_RECEIVED_HANDLER"; - break; - case OnClose: - typeName = "WEBNOTIFICATIONS_ONCLOSE_HANDLER"; - break; - case OnError: - typeName = "WEBNOTIFICATIONS_ONERROR_HANDLER"; - break; - case OnOpen: - typeName = "WEBNOTIFICATIONS_ONOPEN_HANDLER"; - break; - } - return typeName; - } - - private String getHandlerClassName(HandlerType hType){ - int idx = hType.ordinal(); - String handlerClassName = handlerCache[idx]; - if (handlerClassName == null){ - String type = getPtyTypeName(hType); - GXService service = GXServices.getInstance().get(GXServices.WEBNOTIFICATIONS_SERVICE); - if (service != null && service.getProperties() != null){ - String className = service.getProperties().get(type); - if (className != null && className.length() > 0){ - handlerClassName = GXutil.getClassName(className.toLowerCase()); - handlerCache[idx] = handlerClassName; - } - } - } - return handlerClassName; - } - - protected void myOnCloseCommon (ISession session) { - GXWebSocketSession client = getGXWebSocketSession(session); - closedSession(client); - Object[] parms = new Object[1]; - parms[0] = client.getId(); - ExecuteHandler(HandlerType.OnClose, parms); - sessions.remove(client.getSession().getHashCode()); - } - - protected void onErrorCommon(Throwable exception, ISession session) { - Object[] parms = new Object[2]; - parms[0] = getGXWebSocketSession(session).getId(); - parms[1] = exception.getMessage(); - ExecuteHandler(HandlerType.OnError, parms); - } - - protected SendResponseType sendCommon(String clientId, String message) { - SendResponseType result = SendResponseType.SessionNotFound; - List list = wsClients.getById(clientId); - if (list != null){ - for (GXWebSocketSession session : list){ - result = sendMessage( session,message); - } - } - return result; - } - - private SendResponseType sendMessage( GXWebSocketSession session, String message) { - SendResponseType result = SendResponseType.SessionInvalid; - if (session != null ){ - if (session.getSession().isOpen()){ - try { - session.getSession().sendEndPointText(message); - result = SendResponseType.OK; - } catch (IOException e) { - result = SendResponseType.SendFailed; - System.out.println("GXWebSocket - sendMessage failed. " + e.getMessage()); - } - } - else - { - System.out.println("GXWebSocket - sendMessage failed Session Was Closed"); - } - } - else - { - result = SendResponseType.SessionNotFound; - System.out.println("GXWebSocketServlet - sendMessage failed SessionNotFound"); - } - return result; - } - - - protected void broadcastCommon(String message) { - for ( GXWebSocketSession session : wsClients.getAll() ) { - sendMessage(session,message); - } - } - - public boolean start() { - return true; - } - - private GXWebSocketSession getGXWebSocketSession(ISession session) { - if (sessions.containsKey(session.getHashCode())) - return sessions.get(session.getHashCode()); - GXWebSocketSession socketSession = new GXWebSocketSession(session); - sessions.put(socketSession.getSession().getHashCode(), socketSession); - return socketSession; - } -} - - diff --git a/java/src/main/java/com/genexus/internet/websocket/GXWebSocketService.java b/java/src/main/java/com/genexus/internet/websocket/GXWebSocketService.java new file mode 100644 index 000000000..8171ffdaf --- /dev/null +++ b/java/src/main/java/com/genexus/internet/websocket/GXWebSocketService.java @@ -0,0 +1,200 @@ +package com.genexus.internet.websocket; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import com.genexus.diagnostics.core.ILogger; +import com.genexus.diagnostics.core.LogManager; +import json.org.json.JSONException; +import json.org.json.JSONObject; + +import com.genexus.Application; +import com.genexus.GXutil; +import com.genexus.ModelContext; +import com.genexus.db.DynamicExecute; +import com.genexus.util.GXService; +import com.genexus.util.GXServices; +import com.genexus.xml.GXXMLSerializable; +import com.genexus.websocket.ISession; + +public class GXWebSocketService { + public static final ILogger logger = LogManager.getLogger(GXWebSocketService.class); + private static GXWebSocketService instance; + + private String[] handlerCache = new String[HandlerType.values().length]; + private GXWebSocketSessionCollection wsClients = new GXWebSocketSessionCollection(); + private ConcurrentHashMap sessions = new ConcurrentHashMap(); + + public enum HandlerType { + ReceivedMessage, OnOpen, OnClose, OnError + } + + public static GXWebSocketService getService() { + if (instance == null) { + synchronized (GXWebSocketService.class) { + if (instance == null) { + instance = new GXWebSocketService(); + } + } + } + return instance; + } + + public void closedSession(GXWebSocketSession session) { + wsClients.remove(session); + } + + protected void onOpen(ISession session) { + logger.debug(String.format("WebSocket - Connection opened '%s'", session.getId())); + + GXWebSocketSession client = getGXWebSocketSession(session); + wsClients.put(client); + + Object[] parms = new Object[1]; + parms[0] = client.getId(); + executeHandler(HandlerType.OnOpen, parms); + } + + protected void onMessage(String txt, ISession session) { + logger.debug(String.format("WebSocket - New Message received '%s'", session.getId())); + + Object[] parameters = new Object[2]; + parameters[0] = getGXWebSocketSession(session).getId(); + + try { + + GXXMLSerializable nInfo = (GXXMLSerializable) Class.forName("com.genexuscore.genexus.server.SdtNotificationInfo").getConstructor().newInstance(); + JSONObject jInfo = new JSONObject(); + jInfo.put("Message", txt); + nInfo.FromJSONObject(jInfo); + parameters[1] = nInfo; + executeHandler(HandlerType.ReceivedMessage, parameters); + + } catch (ClassNotFoundException e) { + logger.error("WebSocket - SdtNotificationInfo class not found", e); + } catch (JSONException | InstantiationException | IllegalAccessException| InvocationTargetException | NoSuchMethodException e) { + logger.error("WebSocket - General error ", e); + } + } + + private void executeHandler(HandlerType type, Object[] parameters) { + String handler = getHandlerClassName(type); + if (handler != null) { + try { + if (!DynamicExecute.dynamicExecute(ModelContext.getModelContext(GXutil.class), -1, Application.class, handler, parameters)) { + logger.error(String.format("WebSocket - Handler '%s' failed to execute", handler)); + } + } catch (Exception e) { + logger.error(String.format("WebSocket - Handler '%s' failed to execute", handler)); + } + } + } + + private String getPtyTypeName(HandlerType type) { + String typeName = ""; + switch (type) { + case ReceivedMessage: + typeName = "WEBNOTIFICATIONS_RECEIVED_HANDLER"; + break; + case OnClose: + typeName = "WEBNOTIFICATIONS_ONCLOSE_HANDLER"; + break; + case OnError: + typeName = "WEBNOTIFICATIONS_ONERROR_HANDLER"; + break; + case OnOpen: + typeName = "WEBNOTIFICATIONS_ONOPEN_HANDLER"; + break; + } + return typeName; + } + + private String getHandlerClassName(HandlerType hType) { + int idx = hType.ordinal(); + String handlerClassName = handlerCache[idx]; + if (handlerClassName == null) { + String type = getPtyTypeName(hType); + GXService service = GXServices.getInstance().get(GXServices.WEBNOTIFICATIONS_SERVICE); + if (service != null && service.getProperties() != null) { + String className = service.getProperties().get(type); + if (className != null && className.length() > 0) { + handlerClassName = GXutil.getClassName(className.toLowerCase()); + handlerCache[idx] = handlerClassName; + } + } + } + return handlerClassName; + } + + protected void onClose(ISession session) { + logger.debug(String.format("WebSocket - Connection closed '%s'", session.getId())); + + GXWebSocketSession client = getGXWebSocketSession(session); + closedSession(client); + Object[] parms = new Object[1]; + parms[0] = client.getId(); + executeHandler(HandlerType.OnClose, parms); + sessions.remove(client.getSession().getHashCode()); + } + + protected void onError(Throwable exception, ISession session) { + logger.debug(String.format("WebSocket - Connection error '%s'", session.getId())); + + Object[] parms = new Object[2]; + parms[0] = getGXWebSocketSession(session).getId(); + parms[1] = exception.getMessage(); + executeHandler(HandlerType.OnError, parms); + } + + public SendResponseType send(String clientId, String message) { + logger.debug(String.format("WebSocket - Try send message to '%s'", clientId)); + + SendResponseType result = SendResponseType.SessionNotFound; + List list = wsClients.getById(clientId); + if (list != null) { + for (GXWebSocketSession session : list) { + result = sendMessage(session, message); + } + } + return result; + } + + private SendResponseType sendMessage(GXWebSocketSession session, String message) { + SendResponseType result = SendResponseType.SessionInvalid; + if (session != null) { + if (session.getSession().isOpen()) { + try { + session.getSession().sendEndPointText(message); + result = SendResponseType.OK; + } catch (IOException e) { + result = SendResponseType.SendFailed; + logger.warn("WebSocket - sendMessage failed", e); + } + } else { + logger.warn("WebSocket - sendMessage failed because session was invalid"); + } + } else { + result = SendResponseType.SessionNotFound; + } + return result; + } + + public void broadcast(String message) { + for (GXWebSocketSession session : wsClients.getAll()) { + sendMessage(session, message); + } + } + + private GXWebSocketSession getGXWebSocketSession(ISession session) { + if (sessions.containsKey(session.getHashCode())) { + return sessions.get(session.getHashCode()); + } + GXWebSocketSession socketSession = new GXWebSocketSession(session); + sessions.put(socketSession.getSession().getHashCode(), socketSession); + return socketSession; + } +} + + diff --git a/java/src/main/java/com/genexus/internet/websocket/GXWebSocketSession.java b/java/src/main/java/com/genexus/internet/websocket/GXWebSocketSession.java index 24d4d5532..b6aaec37d 100644 --- a/java/src/main/java/com/genexus/internet/websocket/GXWebSocketSession.java +++ b/java/src/main/java/com/genexus/internet/websocket/GXWebSocketSession.java @@ -11,7 +11,7 @@ public String getId(){ return id; } public GXWebSocketSession(ISession session){ - id = session.getQueryString(); + id = session.getId(); this.session = session; } public ISession getSession() diff --git a/java/src/main/java/com/genexus/internet/websocket/IGXWebSocketService.java b/java/src/main/java/com/genexus/internet/websocket/IGXWebSocketService.java index e929e7465..d2295838a 100644 --- a/java/src/main/java/com/genexus/internet/websocket/IGXWebSocketService.java +++ b/java/src/main/java/com/genexus/internet/websocket/IGXWebSocketService.java @@ -1,7 +1,6 @@ package com.genexus.internet.websocket; public interface IGXWebSocketService { - boolean start(); SendResponseType send(String clientId, String message); void broadcast(String message); } diff --git a/java/src/main/java/com/genexus/webpanels/GXWebObjectStub.java b/java/src/main/java/com/genexus/webpanels/GXWebObjectStub.java index 322aa95a3..0a8f4ca0b 100644 --- a/java/src/main/java/com/genexus/webpanels/GXWebObjectStub.java +++ b/java/src/main/java/com/genexus/webpanels/GXWebObjectStub.java @@ -79,7 +79,7 @@ private void dumpRequestInfo(HttpContext httpContext) sBuffer.append(cookies[i].getValue()); } } - logger.debug(sBuffer.toString()); + //logger.debug(sBuffer.toString()); } protected void callExecute(String method, IHttpServletRequest req, IHttpServletResponse res) throws ServletException diff --git a/wrappercommon/src/main/java/com/genexus/websocket/ISession.java b/wrappercommon/src/main/java/com/genexus/websocket/ISession.java index 07eb227b5..03cbb5d6d 100644 --- a/wrappercommon/src/main/java/com/genexus/websocket/ISession.java +++ b/wrappercommon/src/main/java/com/genexus/websocket/ISession.java @@ -4,7 +4,7 @@ public interface ISession { Integer getHashCode(); - String getQueryString(); + String getId(); boolean isOpen(); void sendEndPointText(String message) throws IOException; } From 1957ab0fb26b3d1568f173f4eb00d7cfd9c1fc39 Mon Sep 17 00:00:00 2001 From: Gonzalo Gallotti Date: Fri, 15 Jul 2022 16:07:40 -0300 Subject: [PATCH 7/9] Removed unused services variable --- java/src/main/java/com/genexus/Application.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/java/src/main/java/com/genexus/Application.java b/java/src/main/java/com/genexus/Application.java index 3bedad3bd..fbddd6833 100644 --- a/java/src/main/java/com/genexus/Application.java +++ b/java/src/main/java/com/genexus/Application.java @@ -40,14 +40,12 @@ public class Application private static Boolean isJMXEnabled; public static Class gxCfg = ApplicationContext.getInstance().getClass(); - //public static ModelContext clientContext; private static Vector toCleanup = new Vector<>(); static LocalUtil localUtil; static Class ClassName = null; private static volatile ExternalProvider externalProvider = null; private static volatile ExternalProvider externalProviderAPI = null; - private static volatile HashMap services = new HashMap<>(); private static Object objectLock = new Object(); private static volatile boolean initialized = false; From 6b060bda533ec711ae7a9aad6c3f52e0e6c325c4 Mon Sep 17 00:00:00 2001 From: Gonzalo Gallotti Date: Fri, 15 Jul 2022 16:09:33 -0300 Subject: [PATCH 8/9] Revet logging --- java/src/main/java/com/genexus/webpanels/GXWebObjectStub.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/src/main/java/com/genexus/webpanels/GXWebObjectStub.java b/java/src/main/java/com/genexus/webpanels/GXWebObjectStub.java index 0a8f4ca0b..322aa95a3 100644 --- a/java/src/main/java/com/genexus/webpanels/GXWebObjectStub.java +++ b/java/src/main/java/com/genexus/webpanels/GXWebObjectStub.java @@ -79,7 +79,7 @@ private void dumpRequestInfo(HttpContext httpContext) sBuffer.append(cookies[i].getValue()); } } - //logger.debug(sBuffer.toString()); + logger.debug(sBuffer.toString()); } protected void callExecute(String method, IHttpServletRequest req, IHttpServletResponse res) throws ServletException From d3205379bb01316e5e74b1e413585e50f2b08d2f Mon Sep 17 00:00:00 2001 From: Gonzalo Gallotti Date: Fri, 15 Jul 2022 16:14:51 -0300 Subject: [PATCH 9/9] Refactoring --- .../internet/websocket/GXWebSocket.java | 18 +++++------------- .../internet/websocket/GXWebSocket.java | 17 ++++------------- .../src/main/java/com/genexus/Application.java | 1 - .../websocket/IGXWebSocketService.java | 7 ------- 4 files changed, 9 insertions(+), 34 deletions(-) delete mode 100644 java/src/main/java/com/genexus/internet/websocket/IGXWebSocketService.java diff --git a/gxwebsocket/src/main/java/com/genexus/internet/websocket/GXWebSocket.java b/gxwebsocket/src/main/java/com/genexus/internet/websocket/GXWebSocket.java index fa67436e4..96d683451 100644 --- a/gxwebsocket/src/main/java/com/genexus/internet/websocket/GXWebSocket.java +++ b/gxwebsocket/src/main/java/com/genexus/internet/websocket/GXWebSocket.java @@ -7,11 +7,10 @@ import javax.websocket.OnOpen; import javax.websocket.server.ServerEndpoint; -import com.genexus.Application; import com.genexus.websocket.Session; @ServerEndpoint(value = "/gxwebsocket") -public class GXWebSocket implements IGXWebSocketService { +public class GXWebSocket { private GXWebSocketService wsService; @@ -20,17 +19,17 @@ public GXWebSocket() { } @OnOpen - public void OnOpen(javax.websocket.Session session) { + public void onOpen(javax.websocket.Session session) { wsService.onOpen(new Session(session)); } @OnMessage - public void OnMessage(String txt, javax.websocket.Session session) { + public void onMessage(String txt, javax.websocket.Session session) { wsService.onMessage(txt, new Session(session)); } @OnClose - public void myOnClose(javax.websocket.Session session, CloseReason reason) { + public void onClose(javax.websocket.Session session, CloseReason reason) { wsService.onClose(new Session(session)); } @@ -38,14 +37,7 @@ public void myOnClose(javax.websocket.Session session, CloseReason reason) { public void onError(Throwable exception, javax.websocket.Session session) { wsService.onError(exception, new Session(session)); } - - public SendResponseType send(String clientId, String message) { - return wsService.send(clientId, message); - } - - public void broadcast(String message) { - wsService.broadcast(message); - } + } diff --git a/gxwebsocketjakarta/src/main/java/com/genexus/internet/websocket/GXWebSocket.java b/gxwebsocketjakarta/src/main/java/com/genexus/internet/websocket/GXWebSocket.java index 99f3d8d2a..3ca418848 100644 --- a/gxwebsocketjakarta/src/main/java/com/genexus/internet/websocket/GXWebSocket.java +++ b/gxwebsocketjakarta/src/main/java/com/genexus/internet/websocket/GXWebSocket.java @@ -1,6 +1,5 @@ package com.genexus.internet.websocket; -import com.genexus.Application; import jakarta.websocket.CloseReason; import jakarta.websocket.OnClose; import jakarta.websocket.OnError; @@ -11,7 +10,7 @@ import com.genexus.websocket.Session; @ServerEndpoint(value = "/gxwebsocket") -public class GXWebSocket implements IGXWebSocketService { +public class GXWebSocket { private GXWebSocketService wsService; @@ -20,17 +19,17 @@ public GXWebSocket() { } @OnOpen - public void OnOpen(jakarta.websocket.Session session) { + public void onOpen(jakarta.websocket.Session session) { wsService.onOpen(new Session(session)); } @OnMessage - public void OnMessage(String txt, jakarta.websocket.Session session) { + public void onMessage(String txt, jakarta.websocket.Session session) { wsService.onMessage(txt, new Session(session)); } @OnClose - public void myOnClose(jakarta.websocket.Session session, CloseReason reason) { + public void onClose(jakarta.websocket.Session session, CloseReason reason) { wsService.onClose(new Session(session)); } @@ -38,14 +37,6 @@ public void myOnClose(jakarta.websocket.Session session, CloseReason reason) { public void onError(Throwable exception, jakarta.websocket.Session session) { wsService.onError(exception, new Session(session)); } - - public SendResponseType send(String clientId, String message) { - return wsService.send(clientId, message); - } - - public void broadcast(String message) { - wsService.broadcast(message); - } } diff --git a/java/src/main/java/com/genexus/Application.java b/java/src/main/java/com/genexus/Application.java index fbddd6833..6bd7cfce3 100644 --- a/java/src/main/java/com/genexus/Application.java +++ b/java/src/main/java/com/genexus/Application.java @@ -12,7 +12,6 @@ import com.genexus.db.driver.ExternalProvider; import com.genexus.diagnostics.core.ILogger; import com.genexus.diagnostics.core.LogManager; -import com.genexus.internet.websocket.IGXWebSocketService; import com.genexus.specific.java.Connect; import com.genexus.util.GXQueue; import com.genexus.util.GXService; diff --git a/java/src/main/java/com/genexus/internet/websocket/IGXWebSocketService.java b/java/src/main/java/com/genexus/internet/websocket/IGXWebSocketService.java deleted file mode 100644 index d2295838a..000000000 --- a/java/src/main/java/com/genexus/internet/websocket/IGXWebSocketService.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.genexus.internet.websocket; - -public interface IGXWebSocketService { - SendResponseType send(String clientId, String message); - void broadcast(String message); -} -