By Alvin Alexander. Last updated: August 29, 2022
As a brief note today, I started to create a little Scala/JavaFX WebSocket client based on the Java-WebSocket project. I initially created it to test my Play Framework WebSocket example. I had hoped to be able to easily get to the server response request headers, but atm I don’t see a way to do that.
That being said, this is what the Scala/JavaFX WebSocket client currently looks like:
And here’s its source code:
package websockets
// JavaFx
import javafx.application.Application
import javafx.event.ActionEvent
import javafx.event.EventHandler
import javafx.scene.Scene
import javafx.scene.control._
import javafx.scene.layout._
import javafx.stage.Stage
import javafx.application.Platform
import javafx.geometry.Insets
// WebSocket client
import java.net.URI
import java.net.URISyntaxException
import java.util.Map
import org.java_websocket.client.WebSocketClient
import org.java_websocket.drafts.Draft
import org.java_websocket.drafts.Draft_6455
import org.java_websocket.framing.Framedata
import org.java_websocket.handshake.ServerHandshake
object ScalaJavaFxWebSocketClientMain {
def main(args: Array[String]) {
Application.launch(classOf[ScalaJavaFxWebSocketClient], args: _*)
}
}
trait HandleServerMessageReceived {
def handleServerMessageReceived(msg: String): Unit
}
class ScalaJavaFxWebSocketClient extends Application with HandleServerMessageReceived
{
val urlField = new TextField
val messageField = new TextArea
val replyField = new TextArea
var wsClient: ScalaWebSocketClient = null
def handleServerMessageReceived(msg: String): Unit = {
replyField.setText(msg)
}
var btnShowsConnectText = true
override def start(primaryStage: Stage)
{
Platform.setImplicitExit(true)
urlField.setText("ws://localhost:9000/ws")
primaryStage.setTitle("WebSocket Client")
messageField.setDisable(true)
replyField.setDisable(true)
// connect button
val btnConnect = new Button
btnConnect.setText("Connect")
btnConnect.setOnAction((e: ActionEvent) => {
val url = urlField.getText
println(s"URL: $url")
wsClient = new ScalaWebSocketClient(
new URI(url),
this
)
val doConnectAction = if (btnShowsConnectText) true else false
connectToServer(doConnectAction, wsClient, btnConnect)
})
// spacer
val spacer = new Region
spacer.setPrefHeight(40)
// message field
val messageLabel = new Label("Message To Send")
messageField.setPrefHeight(200)
messageField.setPromptText("your message")
messageField.setText("{\"message\":\"Hello\"}")
// reply field
val replyLabel = new Label("Server’s Reply")
replyField.setPrefHeight(200)
replyField.setPromptText("")
// send button
val btnSend = new Button
btnSend.setText("Send")
btnSend.setOnAction((e: ActionEvent) => {
println("SendButton pressed")
val ourMsg = messageField.getText
wsClient.send(ourMsg)
})
val vbox = new VBox
vbox.setSpacing(20)
vbox.getChildren.addAll(
urlField,
btnConnect, spacer,
messageLabel, messageField,
replyLabel, replyField,
btnSend
)
val borderPane = new BorderPane(vbox)
borderPane.setPadding(new Insets(20, 20, 20, 20))
primaryStage.setScene(new Scene(borderPane, 800, 600))
primaryStage.show
primaryStage.setOnCloseRequest(event => {
// TODO figure out what’s really needed here
Platform.exit()
primaryStage.close
System.exit(0)
})
}
def connectToServer(b: Boolean, wsClient: ScalaWebSocketClient, btnConnect: Button): Unit = {
if (b) {
println("Trying to connect to the server ...")
wsClient.connect
btnConnect.setText("Disconnect")
btnShowsConnectText = false
messageField.setDisable(false)
replyField.setDisable(false)
} else {
println("Closing the connection to the server ...")
// TODO might need to call closeBlocking or closeConnection here instead
wsClient.close()
btnConnect.setText("Connect")
btnShowsConnectText = true
messageField.setDisable(true)
replyField.setDisable(true)
}
}
}
class ScalaWebSocketClient(uri: URI, serverMsgHandler: HandleServerMessageReceived)
extends WebSocketClient(uri) {
@Override
def onOpen(handshakedata: ServerHandshake) {
send("{\"message\":\"Hello\"}")
send("{\"message\":\"world\"}")
println( "opened connection" )
}
@Override
def onMessage(message: String) {
println( "received: " + message )
serverMsgHandler.handleServerMessageReceived(message)
}
@Override
def onClose(code: Int, reason: String, remote: Boolean) {
// The codecodes are documented in class org.java_websocket.framing.CloseFrame
println( "Connection closed by "
+ ( if (remote) "remote peer" else "us" ) + " Code: " + code + " Reason: " + reason )
}
@Override
def onError(e: Exception) {
e.printStackTrace()
}
}
this post is sponsored by my books: | |||
![]() #1 New Release |
![]() FP Best Seller |
![]() Learn Scala 3 |
![]() Learn FP Fast |
Also, here’s its build.sbt file:
name := "JavaScalaWebSocketClient"
version := "0.1"
scalaVersion := "2.12.11"
// need this to stop JavaFX clients within sbt
// see: https://stackoverflow.com/questions/5137460/sbt-stop-run-without-exiting
fork in run := true
libraryDependencies ++= Seq(
"org.java-websocket" % "Java-WebSocket" % "1.4.1"
)
for scalacOptions descriptions
scalacOptions ++= Seq(
"-deprecation", //emit warning and location for usages of deprecated APIs
"-unchecked", //enable additional warnings where generated code depends on assumptions
"-explaintypes", //explain type errors in more detail
"-Ywarn-dead-code", //warn when dead code is identified
"-Xfatal-warnings" //fail the compilation if there are any warnings
)