├── .gitignore ├── LICENSE.txt ├── README.md ├── pom.xml ├── screenshot.png └── src └── main ├── deploy ├── README-keystore.txt ├── keystore.jks └── package │ ├── macosx │ └── javafx-websocket-test.icns │ └── windows │ └── javafx-websocket-test.ico ├── java └── org │ └── jewelsea │ └── websocket │ └── sample │ ├── HelloController.java │ ├── JavaFXWebsocketDemoApp.java │ ├── client │ ├── HelloClientEndpoint.java │ ├── HelloService.java │ └── HelloTask.java │ └── server │ ├── HelloServer.java │ └── HelloServerEndpoint.java └── resources ├── fxml └── hello.fxml ├── images └── background.jpg ├── log4j.xml └── styles └── styles.css /.gitignore: -------------------------------------------------------------------------------- 1 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 2 | 3 | *.iml 4 | 5 | ## Directory-based project format: 6 | .idea/ -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2014 John Smith 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | *Overview* 2 | 3 | Sample of using a WebSocket client within a JavaFX client application. 4 | 5 | The project makes use of the [Tyrus WebSocket framework](https://tyrus.java.net). 6 | 7 | *Description* 8 | 9 | Creates a scene where the user can input their name, then submit 10 | a request to a WebSocket server, which will respond with `Hello `, 11 | the output of which is recorded in a label on the scene. 12 | 13 | As this is built to be a self-contained demonstration application, 14 | a local WebSocket server is started when the application starts up and 15 | the local server is shutdown when the application is stopped. 16 | 17 | *Implementation Notes* 18 | 19 | 1. Websocket communication occurs within an asynchronously executed JavaFX [Task](http://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Task.html). 20 | 2. WebSocket endpoints are defined as annotated endpoints as documented in the specification for [JSR-356: Java API for WebSockets](https://jcp.org/en/jsr/detail?id=356). 21 | 3. A new server connection is created for each communication task (i.e. connection resources are not shared or reused between tasks). 22 | 4. This implementation is not proxy aware. For information on making the system proxy aware see the [Tyrus proxy documentation](https://tyrus.java.net/documentation/1.9/user-guide.html#d0e1323). 23 | 5. For high traffic communication it would be recommended to use a different implementation 24 | which reuses such resources, for example: 25 | 26 | * Using a [Tyrus shared container](https://tyrus.java.net/documentation/1.9/user-guide.html#d0e1215) OR 27 | * Creating a persistent connection which is used for server calls (probably in conjunction with a the [Tyrus client reconnect facility](https://tyrus.java.net/documentation/1.9/user-guide.html#d0e1311)). 28 | 29 | *Sample Screenshot* 30 | 31 | ![image](https://raw.githubusercontent.com/jewelsea/javafx-websocket-test/master/screenshot.png) 32 | 33 | *Build Requirements* 34 | 35 | This project requires Oracle Java 8u20+ and Maven 3.2.3+. 36 | 37 | *Checkout* 38 | 39 | git clone https://github.com/jewelsea/javafx-websocket-test.git 40 | 41 | *Build* 42 | 43 | mvn com.zenjava:javafx-maven-plugin:8.1.2:web 44 | 45 | *Execution* 46 | 47 | To run the resultant application as a standalone jar: 48 | 49 | java -jar target/jfx/app/javafx-websocket-test-jfx.jar 50 | 51 | To run the resultant application as webstart app: 52 | 53 | javaws target/jfx/web/javafx-websocket-test.jnlp 54 | 55 | *Attribution* 56 | 57 | This is a JavaFX Maven Plugin built project. 58 | Information on using the JavaFX Maven Plugin is at: 59 | 60 | * [https://github.com/zonski/javafx-maven-plugin](https://github.com/zonski/javafx-maven-plugin) 61 | 62 | A skeleton for this project was generated using the [JavaFX Maven Plugin Quickstart Archetype](http://zenjava.com/javafx/maven/basic-archetype.html), then significantly modified after that. 63 | 64 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | org.jewelsea 7 | javafx-websocket-test 8 | javafx-websocket-test 9 | 10 | jar 11 | 1.0-SNAPSHOT 12 | 13 | 14 | 15 | Jewelsea 16 | 17 | 18 | 19 | 1.6.1 20 | 1.9 21 | 22 | 23 | 24 | 25 | javafx-websocket-test 26 | 27 | 28 | 29 | 30 | com.zenjava 31 | javafx-maven-plugin 32 | 8.1.2 33 | 34 | 35 | org.jewelsea.websocket.sample.JavaFXWebsocketDemoApp 36 | 37 | 38 | selfsigned 39 | password 40 | true 41 | 42 | org.jewelsea 43 | CA 44 | US 45 | 46 | 47 | 48 | 49 | 50 | org.apache.maven.plugins 51 | maven-compiler-plugin 52 | 3.2 53 | 54 | 1.8 55 | 1.8 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | com.miglayout 69 | miglayout-javafx 70 | 4.2 71 | 72 | 73 | 74 | 75 | 76 | commons-lang 77 | commons-lang 78 | 2.6 79 | 80 | 81 | 82 | 83 | 84 | org.slf4j 85 | slf4j-api 86 | ${slf4j.version} 87 | 88 | 89 | org.slf4j 90 | jcl-over-slf4j 91 | ${slf4j.version} 92 | 93 | 94 | org.slf4j 95 | slf4j-log4j12 96 | ${slf4j.version} 97 | 98 | 99 | log4j 100 | log4j 101 | 1.2.16 102 | 103 | 104 | 105 | 106 | org.glassfish.tyrus.bundles 107 | tyrus-standalone-client 108 | ${tyrus.version} 109 | 110 | 111 | 112 | org.glassfish.tyrus 113 | tyrus-server 114 | ${tyrus.version} 115 | 116 | 117 | 118 | org.glassfish.tyrus 119 | tyrus-container-grizzly-server 120 | ${tyrus.version} 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jewelsea/javafx-websocket-test/f7a5e6462e25353082a936939dd2eb970aa5d77a/screenshot.png -------------------------------------------------------------------------------- /src/main/deploy/README-keystore.txt: -------------------------------------------------------------------------------- 1 | Command to generate a self-signed keystore: 2 | 3 | Password to use is "password". 4 | 5 | This is necessary because the maven command jfx:generate-key-store doesn't seem to work with the JavaFX maven plugin 8.1.2: 6 | Refer to https://github.com/zonski/javafx-maven-plugin/issues/66 for more detail. 7 | 8 | $ keytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass password -validity 360 -keysize 2048 9 | What is your first and last name? 10 | [Unknown]: jewelsea 11 | What is the name of your organizational unit? 12 | [Unknown]: jewelsea.org 13 | What is the name of your organization? 14 | [Unknown]: jewelsea 15 | What is the name of your City or Locality? 16 | [Unknown]: Mountain View 17 | What is the name of your State or Province? 18 | [Unknown]: CA 19 | What is the two-letter country code for this unit? 20 | [Unknown]: US 21 | Is CN=jewelsea, OU=jewelsea.org, O=jewelsea, L=Mountain View, ST=CA, C=US correct? 22 | [no]: yes 23 | 24 | Enter key password for 25 | (RETURN if same as keystore password): 26 | Re-enter new password: 27 | $ -------------------------------------------------------------------------------- /src/main/deploy/keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jewelsea/javafx-websocket-test/f7a5e6462e25353082a936939dd2eb970aa5d77a/src/main/deploy/keystore.jks -------------------------------------------------------------------------------- /src/main/deploy/package/macosx/javafx-websocket-test.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jewelsea/javafx-websocket-test/f7a5e6462e25353082a936939dd2eb970aa5d77a/src/main/deploy/package/macosx/javafx-websocket-test.icns -------------------------------------------------------------------------------- /src/main/deploy/package/windows/javafx-websocket-test.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jewelsea/javafx-websocket-test/f7a5e6462e25353082a936939dd2eb970aa5d77a/src/main/deploy/package/windows/javafx-websocket-test.ico -------------------------------------------------------------------------------- /src/main/java/org/jewelsea/websocket/sample/HelloController.java: -------------------------------------------------------------------------------- 1 | package org.jewelsea.websocket.sample; 2 | 3 | import javafx.fxml.FXML; 4 | import javafx.scene.control.Label; 5 | import javafx.scene.control.TextField; 6 | import org.apache.commons.lang.StringUtils; 7 | import org.jewelsea.websocket.sample.client.HelloService; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | /** 12 | * FXML controller for the application. 13 | */ 14 | public class HelloController { 15 | private static final Logger log = LoggerFactory.getLogger(HelloController.class); 16 | 17 | private static final String DEFAULT_NAME = "mysterious person"; 18 | 19 | @FXML 20 | private TextField firstNameField; 21 | 22 | @FXML 23 | private TextField lastNameField; 24 | 25 | @FXML 26 | private Label messageLabel; 27 | 28 | private HelloService helloService = new HelloService(); 29 | 30 | /** 31 | * Event handler invoked when the user submits their name. 32 | * 33 | * Invokes an asynchronous task which will communicate 34 | * the user's name to the server and update the message 35 | * label with the server's response. 36 | * 37 | * If invoked again before an in progress task completes, 38 | * the in progress task is cancelled and a new task is issued 39 | * with the current value of the name fields. 40 | */ 41 | @FXML 42 | private void sayHello() { 43 | messageLabel.setText(""); 44 | 45 | String name = createFullName(); 46 | helloService.setName(name); 47 | 48 | helloService.setOnSucceeded(event -> { 49 | log.debug( 50 | "Said hello to " + name + ", response " + helloService.getValue() 51 | ); 52 | 53 | messageLabel.setText( 54 | helloService.getValue() 55 | ); 56 | }); 57 | 58 | helloService.setOnFailed(event -> 59 | log.error( 60 | "Unable to say hello to " + name, 61 | helloService.getException() 62 | ) 63 | ); 64 | 65 | helloService.restart(); 66 | } 67 | 68 | /** 69 | * Helper function which constructs the user's full name 70 | * from their input first and last names. 71 | * 72 | * @return the user's full name (or a default name if the user has not entered any name). 73 | */ 74 | private String createFullName() { 75 | StringBuilder builder = new StringBuilder(); 76 | 77 | String firstName = firstNameField.getText(); 78 | String lastName = lastNameField.getText(); 79 | 80 | if (!StringUtils.isEmpty(firstName)) { 81 | builder.append(firstName); 82 | } 83 | 84 | if (!StringUtils.isEmpty(lastName)) { 85 | if (builder.length() > 0) { 86 | builder.append(" "); 87 | } 88 | builder.append(lastName); 89 | } 90 | 91 | if (builder.length() == 0) { 92 | builder.append(DEFAULT_NAME); 93 | } 94 | 95 | return builder.toString(); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/org/jewelsea/websocket/sample/JavaFXWebsocketDemoApp.java: -------------------------------------------------------------------------------- 1 | package org.jewelsea.websocket.sample; 2 | 3 | import javafx.application.Application; 4 | import javafx.fxml.FXMLLoader; 5 | import javafx.scene.Parent; 6 | import javafx.scene.Scene; 7 | import javafx.stage.Stage; 8 | import org.jewelsea.websocket.sample.server.HelloServer; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import javax.websocket.DeploymentException; 13 | 14 | /** 15 | * Demonstration application for using WebSockets from JavaFX. 16 | * 17 | * Creates a scene where the user can input their name, then submit 18 | * a request to a WebSocket server, which will respond with "Hello ", 19 | * the output of which is recorded in a label on the scene. 20 | * 21 | * As this is built to be a self-contained demonstration application, 22 | * a local WebSocket server is started when the application starts up and 23 | * the local server is shutdown when the application is stopped. 24 | */ 25 | public class JavaFXWebsocketDemoApp extends Application { 26 | private static final Logger log = LoggerFactory.getLogger(JavaFXWebsocketDemoApp.class); 27 | 28 | private static final String MAIN_FXML_FILE = "/fxml/hello.fxml"; 29 | private static final String APPLICATION_STYLE_SHEET = "/styles/styles.css"; 30 | 31 | /** A local websocket server for testing purposes */ 32 | private HelloServer server; 33 | 34 | public static void main(String[] args) throws Exception { 35 | launch(args); 36 | } 37 | 38 | /** Starts a local websocket server for testing purposes */ 39 | public void init() throws DeploymentException { 40 | server = new HelloServer(); 41 | server.start(); 42 | } 43 | 44 | /** Stops the local websocket server. */ 45 | public void stop() throws DeploymentException { 46 | server.stop(); 47 | } 48 | 49 | /** Shows the main application scene. */ 50 | public void start(Stage stage) throws Exception { 51 | log.info("Starting Hello JavaFX WebSocket demonstration application"); 52 | 53 | log.debug("Loading FXML for main view from: {}", MAIN_FXML_FILE); 54 | FXMLLoader loader = new FXMLLoader(); 55 | Parent rootNode = loader.load( 56 | getClass().getResourceAsStream( 57 | MAIN_FXML_FILE 58 | ) 59 | ); 60 | 61 | log.debug("Showing JavaFX scene"); 62 | Scene scene = new Scene(rootNode, 400, 200); 63 | scene.getStylesheets().add(APPLICATION_STYLE_SHEET); 64 | 65 | stage.setTitle("Hello JavaFX WebSockets"); 66 | stage.setScene(scene); 67 | stage.show(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/org/jewelsea/websocket/sample/client/HelloClientEndpoint.java: -------------------------------------------------------------------------------- 1 | package org.jewelsea.websocket.sample.client; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import javax.websocket.*; 7 | import java.io.IOException; 8 | import java.util.concurrent.CountDownLatch; 9 | import java.util.concurrent.TimeUnit; 10 | import java.util.concurrent.TimeoutException; 11 | 12 | /** 13 | * WebSocket client endpoint to the hello service. 14 | * 15 | * Submits a name to the hello service on opening a connection. 16 | * 17 | * Expects a single response from the server which the server is to 18 | * send immediately upon receiving the request name. 19 | * 20 | * `getResponse()` is a blocking method which can be used to retrieve the response to the request. 21 | * 22 | * This endpoint is structured to only be used once per client connection. 23 | * (i.e. create a new endpoint instance for every client connection). 24 | */ 25 | @ClientEndpoint 26 | public class HelloClientEndpoint { 27 | private static final Logger log = LoggerFactory.getLogger(HelloClientEndpoint.class); 28 | 29 | private final String name; 30 | private String response; 31 | private Throwable exception; 32 | 33 | private final CountDownLatch messageLatch = new CountDownLatch(1); 34 | 35 | private static final int REQUEST_TIMEOUT_SECS = 10; 36 | 37 | public HelloClientEndpoint(String name) { 38 | this.name = name; 39 | } 40 | 41 | @OnOpen 42 | public void onOpen(Session session) { 43 | try { 44 | log.debug("Sending request: '" + name + "' with session " + session.getId()); 45 | session.getBasicRemote().sendText(name); 46 | } catch (IOException e) { 47 | log.error("Unable to connect to hello server: ", e); 48 | } 49 | } 50 | 51 | @OnMessage 52 | public void processResponse(Session session, String message) { 53 | log.debug("Received response: '" + message + "' for request: '" + name + "' with session " + session.getId()); 54 | response = message; 55 | messageLatch.countDown(); 56 | } 57 | 58 | @OnError 59 | public void onError(Session session, Throwable throwable) { 60 | log.error("Communication error, saying hello to '" + name + "' with session " + session.getId(), throwable); 61 | exception = throwable; 62 | messageLatch.countDown(); 63 | } 64 | 65 | /** 66 | * Blocks until either the server sends a response to the request, an communication error occurs 67 | * or the communication request times out. 68 | * 69 | * @return the server response message. 70 | * @throws TimeoutException if the server does not respond before the timeout value is reached. 71 | * @throws InterruptedException if the communication thread is interrupted (e.g. thread.interrupt() is invoked on it for cancellation purposes). 72 | * @throws IOException if a communication error occurs. 73 | */ 74 | public String getResponse() throws TimeoutException, InterruptedException, IOException { 75 | if (messageLatch.await(REQUEST_TIMEOUT_SECS, TimeUnit.SECONDS)) { 76 | if (exception != null) { 77 | throw new IOException("Unable to say hello", exception); 78 | } 79 | return response; 80 | } else { 81 | throw new TimeoutException("Timed out awaiting server hello response for " + name); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /src/main/java/org/jewelsea/websocket/sample/client/HelloService.java: -------------------------------------------------------------------------------- 1 | package org.jewelsea.websocket.sample.client; 2 | 3 | import javafx.beans.property.SimpleStringProperty; 4 | import javafx.beans.property.StringProperty; 5 | import javafx.concurrent.Service; 6 | import javafx.concurrent.Task; 7 | import org.glassfish.tyrus.client.ClientManager; 8 | import org.jewelsea.websocket.sample.server.HelloServer; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import javax.websocket.DeploymentException; 13 | import java.io.IOException; 14 | import java.net.URI; 15 | import java.util.concurrent.TimeoutException; 16 | import java.util.concurrent.atomic.AtomicLong; 17 | 18 | /** 19 | * Wraps communication with a WebSocket endpoint in a JavaFX Service. 20 | */ 21 | public class HelloService extends Service { 22 | private static final Logger log = LoggerFactory.getLogger(HelloService.class); 23 | 24 | private final StringProperty name = new SimpleStringProperty(this, "name"); 25 | 26 | /** 27 | * The name property is set as an input parameter for a service execution. 28 | * @return the name property. 29 | */ 30 | public final StringProperty nameProperty() { return name; } 31 | public final void setName(String value) { name.set(value); } 32 | public final String getName() { return name.get(); } 33 | 34 | @Override 35 | protected Task createTask() { 36 | return new HelloTask(getName()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/jewelsea/websocket/sample/client/HelloTask.java: -------------------------------------------------------------------------------- 1 | package org.jewelsea.websocket.sample.client; 2 | 3 | import javafx.concurrent.Task; 4 | import org.glassfish.tyrus.client.ClientManager; 5 | import org.jewelsea.websocket.sample.server.HelloServer; 6 | 7 | import javax.websocket.DeploymentException; 8 | import java.io.IOException; 9 | import java.net.URI; 10 | import java.util.concurrent.TimeoutException; 11 | 12 | /** 13 | * Wraps communication with a WebSocket endpoint in a JavaFX Task. 14 | * 15 | * This allows the communication to occur asynchronously to the JavaFX application thread, 16 | * so the JavaFX application thread is not blocked by the communication process. 17 | * 18 | * A new server connection is created for each communication task. 19 | * (i.e. connection resources are not shared or reused between tasks). 20 | * For high traffic communication it would be recommended to use a different implementation 21 | * which reuses such resources. 22 | */ 23 | public class HelloTask extends Task { 24 | private static final String SERVER_ENDPOINT_ADDRESS = 25 | HelloServer.SERVER_ADDRESS + "/hello"; 26 | 27 | private final String name; 28 | 29 | /** 30 | * Creates a new task for server communication. 31 | * @param name the request name to send to the server. 32 | */ 33 | public HelloTask(String name) { 34 | this.name = name; 35 | } 36 | 37 | /** 38 | * Sends the requested name passed in the Task constructor to the server endpoint. 39 | * A new connection is established for the request. 40 | * 41 | * @return the response from the server. 42 | * @throws IOException if there was an error communication with the server. 43 | * @throws TimeoutException if communication with the server timed out before a response was received. 44 | */ 45 | @Override 46 | protected String call() throws IOException, TimeoutException { 47 | String response = null; 48 | 49 | HelloClientEndpoint clientEndpoint = new HelloClientEndpoint( 50 | name 51 | ); 52 | 53 | try { 54 | ClientManager client = ClientManager.createClient(); 55 | client.connectToServer( 56 | clientEndpoint, 57 | URI.create(SERVER_ENDPOINT_ADDRESS) 58 | ); 59 | 60 | response = clientEndpoint.getResponse(); 61 | } catch (DeploymentException e) { 62 | throw new IOException(e); 63 | } catch (InterruptedException e) { 64 | Thread.interrupted(); 65 | } 66 | 67 | return response; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/org/jewelsea/websocket/sample/server/HelloServer.java: -------------------------------------------------------------------------------- 1 | package org.jewelsea.websocket.sample.server; 2 | 3 | import org.glassfish.tyrus.server.Server; 4 | import org.jewelsea.websocket.sample.JavaFXWebsocketDemoApp; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import javax.websocket.DeploymentException; 9 | 10 | /** A WebSocket server for handling hello message requests. */ 11 | public class HelloServer { 12 | private static final Logger log = LoggerFactory.getLogger(JavaFXWebsocketDemoApp.class); 13 | 14 | private static final String SERVER_HOSTNAME = "localhost"; 15 | private static final int SERVER_PORT = 8025; 16 | private static final String SERVER_CONTEXT_PATH = "/websocket"; 17 | 18 | private Server server; 19 | 20 | public static final String SERVER_ADDRESS = 21 | "ws://" + SERVER_HOSTNAME + ":" + SERVER_PORT + SERVER_CONTEXT_PATH; 22 | 23 | /** 24 | * Starts the server executing. 25 | * 26 | * @throws DeploymentException if there was an error starting the server and 27 | * deploying the server websocket endpoint to it. 28 | */ 29 | public void start() throws DeploymentException { 30 | try { 31 | log.info("Starting server for " + SERVER_ADDRESS); 32 | 33 | server = new Server( 34 | SERVER_HOSTNAME, 35 | SERVER_PORT, 36 | SERVER_CONTEXT_PATH, 37 | null, 38 | HelloServerEndpoint.class 39 | ); 40 | 41 | server.start(); 42 | } catch (DeploymentException e) { 43 | server = null; 44 | throw e; 45 | } 46 | } 47 | 48 | /** 49 | * Shuts down the server. 50 | */ 51 | public void stop() { 52 | if (server != null) { 53 | log.info("Stopping server for " + SERVER_ADDRESS); 54 | 55 | server.stop(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/jewelsea/websocket/sample/server/HelloServerEndpoint.java: -------------------------------------------------------------------------------- 1 | package org.jewelsea.websocket.sample.server; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import javax.websocket.OnError; 7 | import javax.websocket.OnMessage; 8 | import javax.websocket.Session; 9 | import javax.websocket.server.ServerEndpoint; 10 | 11 | /** A WebSocket server endpoint which responds to hello requests. */ 12 | @ServerEndpoint(value = "/hello") 13 | public class HelloServerEndpoint { 14 | private static final Logger log = LoggerFactory.getLogger(HelloServerEndpoint.class); 15 | 16 | /** 17 | * Service a hello request. 18 | * 19 | * @param session the current websocket session. 20 | * @param message a name to which the server should respond hello to. 21 | * @return the response string "Hello " + message; 22 | */ 23 | @OnMessage 24 | public String onMessage(Session session, String message) { 25 | log.debug("HelloServer received request for: " + message + " being processed for session " + session.getId()); 26 | 27 | return "Hello " + message; 28 | } 29 | 30 | /** 31 | * Logs an error if one is detected. 32 | * 33 | * @param session the websocket session to which is in error. 34 | * @param throwable the detected error to be logged. 35 | */ 36 | @OnError 37 | public void onError(Session session, Throwable throwable) { 38 | log.error("HelloServer encountered error for session " + session.getId(), throwable); 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/resources/fxml/hello.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12 | 13 |