From 3da89c386b7595502b00ceeda17bca810c85383f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Rasie=C5=84ski?= Date: Wed, 17 Dec 2025 16:26:27 +0100 Subject: [PATCH] Created utils for websockets. --- client/pom.xml | 27 +++++ client/src/main/java/client/MyModule.java | 5 + .../java/client/utils/WebSocketUtils.java | 111 ++++++++++++++++++ commons/pom.xml | 6 + 4 files changed, 149 insertions(+) create mode 100644 client/src/main/java/client/utils/WebSocketUtils.java diff --git a/client/pom.xml b/client/pom.xml index d48d069..3bd793a 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -34,21 +34,25 @@ jersey-client ${version.jersey} + org.glassfish.jersey.inject jersey-hk2 ${version.jersey} + org.glassfish.jersey.media jersey-media-json-jackson ${version.jersey} + jakarta.activation jakarta.activation-api 2.1.3 + com.google.inject guice @@ -61,11 +65,13 @@ javafx-fxml ${version.jfx} + org.openjfx javafx-controls ${version.jfx} + org.openjfx javafx-web @@ -91,6 +97,27 @@ ${version.mockito} test + + + + org.springframework + spring-messaging + 6.2.12 + compile + + + + org.glassfish.tyrus.bundles + tyrus-standalone-client + 2.2.1 + + + org.springframework + spring-websocket + 6.2.12 + compile + + diff --git a/client/src/main/java/client/MyModule.java b/client/src/main/java/client/MyModule.java index 4f3464e..21da1dc 100644 --- a/client/src/main/java/client/MyModule.java +++ b/client/src/main/java/client/MyModule.java @@ -19,6 +19,8 @@ import client.scenes.FoodpalApplicationCtrl; import client.scenes.recipe.IngredientListCtrl; import client.scenes.recipe.RecipeStepListCtrl; import client.utils.LocaleManager; +import client.utils.ServerUtils; +import client.utils.WebSocketUtils; import com.google.inject.Binder; import com.google.inject.Module; import com.google.inject.Scopes; @@ -33,6 +35,9 @@ public class MyModule implements Module { binder.bind(FoodpalApplicationCtrl.class).in(Scopes.SINGLETON); binder.bind(IngredientListCtrl.class).in(Scopes.SINGLETON); binder.bind(RecipeStepListCtrl.class).in(Scopes.SINGLETON); + binder.bind(LocaleManager.class).in(Scopes.SINGLETON); + binder.bind(ServerUtils.class).in(Scopes.SINGLETON); + binder.bind(WebSocketUtils.class).in(Scopes.SINGLETON); } } \ No newline at end of file diff --git a/client/src/main/java/client/utils/WebSocketUtils.java b/client/src/main/java/client/utils/WebSocketUtils.java new file mode 100644 index 0000000..ed16b37 --- /dev/null +++ b/client/src/main/java/client/utils/WebSocketUtils.java @@ -0,0 +1,111 @@ +package client.utils; + +import commons.ws.messages.Message; +import org.springframework.messaging.converter.MappingJackson2MessageConverter; +import org.springframework.messaging.simp.stomp.StompSession; +import org.springframework.messaging.simp.stomp.StompHeaders; +import org.springframework.messaging.simp.stomp.StompCommand; +import org.springframework.messaging.simp.stomp.StompFrameHandler; +import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter; +import org.springframework.web.socket.client.standard.StandardWebSocketClient; +import org.springframework.web.socket.messaging.WebSocketStompClient; + +import java.lang.reflect.Type; +import java.util.function.Consumer; +import javax.annotation.Nullable; +import java.util.concurrent.CompletableFuture; + +public class WebSocketUtils { + private static final String WS_URL = "ws://localhost:8080/updates"; + private WebSocketStompClient stompClient; + private StompSession stompSession; + + /** + * Connect to the websocket server. + * @param onConnected OnConnected callback + */ + public void connect(@Nullable Runnable onConnected) { + StandardWebSocketClient webSocketClient = new StandardWebSocketClient(); // Create WS Client + + stompClient = new WebSocketStompClient(webSocketClient); + stompClient.setMessageConverter(new MappingJackson2MessageConverter()); // Use jackson + + CompletableFuture sessionFuture = stompClient.connectAsync( + WS_URL, + new StompSessionHandlerAdapter() { + @Override + public void afterConnected(StompSession session, StompHeaders connectedHeaders) { + stompSession = session; + System.out.println("WebSocket connected: " + session.getSessionId()); + } + + @Override + public void handleException(StompSession session, @Nullable StompCommand command, + StompHeaders headers, byte[] payload, + Throwable exception) { + System.err.println("STOMP error: " + exception.getMessage()); + exception.printStackTrace(); + } + + @Override + public void handleTransportError(StompSession session, Throwable exception) { + System.err.println("STOMP transport error: " + exception.getMessage()); + exception.printStackTrace(); + } + } + ); + + sessionFuture.thenAccept(session -> { + stompSession = session; + System.out.println("Connection successful, session ready"); + if (onConnected != null) { + onConnected.run(); + } + }).exceptionally(throwable -> { + System.err.println("Failed to connect: " + throwable.getMessage()); + throwable.printStackTrace(); + return null; + }); + } + + /** + * Subscribe to a topic. + * @param destination Destination to subscribe to, for example: /subscribe/recipe + * @param messageHandler Handler for received messages + */ + public void subscribe(String destination, Consumer messageHandler) { + if (stompSession == null || !stompSession.isConnected()) { + System.err.println("Cannot subscribe - not connected"); + return; + } + + stompSession.subscribe(destination, new StompFrameHandler() { + @Override + public Type getPayloadType(StompHeaders headers) { + return Message.class; + } + + @Override + public void handleFrame(StompHeaders headers, @Nullable Object payload) { + Message message = (Message) payload; + messageHandler.accept(message); + } + }); + System.out.println("Subscribed to: " + destination); + } + + public void disconnect() { + if (stompSession != null && stompSession.isConnected()) { + stompSession.disconnect(); + } + + if (stompClient != null) { + stompClient.stop(); + } + } + + public boolean isConnected() { + return stompSession != null && stompSession.isConnected(); + } + +} diff --git a/commons/pom.xml b/commons/pom.xml index e5d5ff4..f48fbcf 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -45,6 +45,12 @@ ${version.mockito} test + + com.fasterxml.jackson.core + jackson-databind + 2.20.1 + compile +