0
# WebSocket Support
1
2
WebSocket client functionality with message types (text, binary, close) and event-driven listener interface for real-time bidirectional communication.
3
4
## Capabilities
5
6
### WebSocket Interface
7
8
Main interface for WebSocket communication with message sending capabilities and resource management.
9
10
```java { .api }
11
/**
12
* WebSocket interface for bidirectional communication
13
* Extends Closeable for proper resource management
14
*/
15
public interface WebSocket extends Closeable {
16
/**
17
* Logger instance for WebSocket operations
18
*/
19
Logger LOG = Logger.getLogger(WebSocket.class.getName());
20
21
/**
22
* Sends a WebSocket message
23
* @param message Message to send (TextMessage, BinaryMessage, or CloseMessage)
24
* @return This WebSocket instance for chaining
25
*/
26
WebSocket send(Message message);
27
28
/**
29
* Sends text message (convenience method)
30
* @param data Text data to send
31
* @return This WebSocket instance for chaining
32
*/
33
default WebSocket sendText(CharSequence data);
34
35
/**
36
* Sends binary message (convenience method)
37
* @param data Binary data to send
38
* @return This WebSocket instance for chaining
39
*/
40
default WebSocket sendBinary(byte[] data);
41
42
/**
43
* Closes the WebSocket connection
44
*/
45
void close();
46
}
47
```
48
49
**Usage Examples:**
50
51
```java
52
import org.openqa.selenium.remote.http.*;
53
54
// Open WebSocket connection via HTTP client
55
HttpRequest wsRequest = new HttpRequest(HttpMethod.GET, "/websocket");
56
wsRequest.addHeader("Upgrade", "websocket");
57
58
WebSocket.Listener listener = new WebSocket.Listener() {
59
@Override
60
public void onText(CharSequence data) {
61
System.out.println("Received text: " + data);
62
}
63
64
@Override
65
public void onBinary(byte[] data) {
66
System.out.println("Received binary: " + data.length + " bytes");
67
}
68
69
@Override
70
public void onClose(int code, String reason) {
71
System.out.println("Connection closed: " + code + " - " + reason);
72
}
73
74
@Override
75
public void onError(Throwable cause) {
76
System.err.println("WebSocket error: " + cause.getMessage());
77
}
78
};
79
80
WebSocket socket = client.openSocket(wsRequest, listener);
81
82
// Send different types of messages
83
socket.sendText("Hello WebSocket!");
84
socket.sendBinary("Binary data".getBytes());
85
86
// Send custom messages
87
socket.send(new TextMessage("Custom text message"));
88
socket.send(new BinaryMessage("Custom binary".getBytes()));
89
90
// Chaining method calls
91
socket.sendText("Message 1")
92
.sendText("Message 2")
93
.sendBinary("data".getBytes());
94
95
// Close connection
96
socket.close();
97
```
98
99
### WebSocket Listener
100
101
Event-driven interface for handling incoming WebSocket messages and connection events.
102
103
```java { .api }
104
/**
105
* Listener interface for WebSocket events
106
* Extends Consumer<Message> for functional interface compatibility
107
*/
108
public interface Listener extends Consumer<Message> {
109
/**
110
* Default message dispatcher that routes messages to specific handlers
111
* @param message Incoming message (BinaryMessage, TextMessage, or CloseMessage)
112
*/
113
default void accept(Message message);
114
115
/**
116
* Handles incoming binary messages
117
* Default implementation does nothing
118
* @param data Binary message data
119
*/
120
default void onBinary(byte[] data);
121
122
/**
123
* Handles connection close events
124
* Default implementation does nothing
125
* @param code Close status code
126
* @param reason Close reason string
127
*/
128
default void onClose(int code, String reason);
129
130
/**
131
* Handles incoming text messages
132
* Default implementation does nothing
133
* @param data Text message data
134
*/
135
default void onText(CharSequence data);
136
137
/**
138
* Handles WebSocket errors
139
* Default implementation logs error at WARNING level
140
* @param cause Error cause
141
*/
142
default void onError(Throwable cause);
143
}
144
```
145
146
**Usage Examples:**
147
148
```java
149
import org.openqa.selenium.remote.http.*;
150
151
// Full listener implementation
152
WebSocket.Listener fullListener = new WebSocket.Listener() {
153
@Override
154
public void onText(CharSequence data) {
155
System.out.println("Text received: " + data);
156
// Echo back
157
if (socket != null) {
158
socket.sendText("Echo: " + data);
159
}
160
}
161
162
@Override
163
public void onBinary(byte[] data) {
164
System.out.println("Binary received: " + data.length + " bytes");
165
// Process binary data
166
processData(data);
167
}
168
169
@Override
170
public void onClose(int code, String reason) {
171
System.out.println("Connection closed with code " + code + ": " + reason);
172
cleanup();
173
}
174
175
@Override
176
public void onError(Throwable cause) {
177
System.err.println("WebSocket error occurred: " + cause.getMessage());
178
cause.printStackTrace();
179
// Custom error handling
180
handleError(cause);
181
}
182
183
private void processData(byte[] data) { /* process binary data */ }
184
private void cleanup() { /* cleanup resources */ }
185
private void handleError(Throwable cause) { /* handle error */ }
186
};
187
188
// Minimal listener (only text messages)
189
WebSocket.Listener textOnlyListener = new WebSocket.Listener() {
190
@Override
191
public void onText(CharSequence data) {
192
System.out.println("Received: " + data);
193
}
194
};
195
196
// Lambda-based listener using Consumer interface
197
WebSocket.Listener lambdaListener = message -> {
198
if (message instanceof TextMessage) {
199
System.out.println("Text: " + ((TextMessage) message).text());
200
} else if (message instanceof BinaryMessage) {
201
System.out.println("Binary: " + ((BinaryMessage) message).data().length + " bytes");
202
}
203
};
204
205
// Use listeners with WebSocket
206
WebSocket socket1 = client.openSocket(wsRequest, fullListener);
207
WebSocket socket2 = client.openSocket(wsRequest, textOnlyListener);
208
WebSocket socket3 = client.openSocket(wsRequest, lambdaListener);
209
```
210
211
## Message Types
212
213
### Message Interface
214
215
Base interface for all WebSocket message types.
216
217
```java { .api }
218
/**
219
* Marker interface for WebSocket messages
220
* Implemented by TextMessage, BinaryMessage, and CloseMessage
221
*/
222
public interface Message {
223
// Marker interface - no methods
224
}
225
```
226
227
### TextMessage
228
229
WebSocket text message implementation for string data.
230
231
```java { .api }
232
/**
233
* WebSocket text message containing string data
234
*/
235
public class TextMessage implements Message {
236
/**
237
* Creates text message from character sequence
238
* @param text Text content for the message
239
*/
240
public TextMessage(CharSequence text);
241
242
/**
243
* Gets the text content
244
* @return Message text as String
245
*/
246
public String text();
247
}
248
```
249
250
**Usage Examples:**
251
252
```java
253
// Create and send text messages
254
TextMessage message1 = new TextMessage("Hello World");
255
TextMessage message2 = new TextMessage(new StringBuilder("Dynamic content"));
256
257
socket.send(message1);
258
socket.send(message2);
259
260
// Access text content
261
String content = message1.text();
262
System.out.println("Message content: " + content);
263
264
// Use in listener
265
WebSocket.Listener listener = new WebSocket.Listener() {
266
@Override
267
public void onText(CharSequence data) {
268
// Can also receive via accept method:
269
}
270
271
@Override
272
public void accept(Message message) {
273
if (message instanceof TextMessage) {
274
TextMessage textMsg = (TextMessage) message;
275
System.out.println("Received text: " + textMsg.text());
276
}
277
}
278
};
279
```
280
281
### BinaryMessage
282
283
WebSocket binary message implementation for byte data with defensive copying.
284
285
```java { .api }
286
/**
287
* WebSocket binary message containing byte data
288
* Makes defensive copies to ensure data integrity
289
*/
290
public class BinaryMessage implements Message {
291
/**
292
* Creates binary message from ByteBuffer
293
* Makes read-only copy of the buffer
294
* @param data ByteBuffer containing binary data
295
*/
296
public BinaryMessage(ByteBuffer data);
297
298
/**
299
* Creates binary message from byte array
300
* Makes defensive copy of the array
301
* @param data Byte array containing binary data
302
*/
303
public BinaryMessage(byte[] data);
304
305
/**
306
* Gets the binary data
307
* Returns copy of internal data to prevent modification
308
* @return Byte array copy of message data
309
*/
310
public byte[] data();
311
}
312
```
313
314
**Usage Examples:**
315
316
```java
317
import java.nio.ByteBuffer;
318
319
// Create binary messages from byte array
320
byte[] imageData = loadImageData();
321
BinaryMessage imageMessage = new BinaryMessage(imageData);
322
socket.send(imageMessage);
323
324
// Create from ByteBuffer
325
ByteBuffer buffer = ByteBuffer.allocate(1024);
326
buffer.put("Binary content".getBytes());
327
buffer.flip();
328
BinaryMessage bufferMessage = new BinaryMessage(buffer);
329
socket.send(bufferMessage);
330
331
// Access binary data (returns defensive copy)
332
byte[] messageData = imageMessage.data();
333
System.out.println("Message size: " + messageData.length + " bytes");
334
335
// Modify returned data doesn't affect original
336
byte[] data = imageMessage.data();
337
data[0] = 0; // This doesn't change the message's internal data
338
339
// Use in listener
340
WebSocket.Listener listener = new WebSocket.Listener() {
341
@Override
342
public void onBinary(byte[] data) {
343
System.out.println("Received " + data.length + " bytes");
344
processImageData(data);
345
}
346
347
@Override
348
public void accept(Message message) {
349
if (message instanceof BinaryMessage) {
350
BinaryMessage binMsg = (BinaryMessage) message;
351
byte[] data = binMsg.data();
352
saveBinaryData(data);
353
}
354
}
355
356
private void processImageData(byte[] data) { /* process image */ }
357
private void saveBinaryData(byte[] data) { /* save to file */ }
358
};
359
```
360
361
### CloseMessage
362
363
WebSocket close message with status code and reason.
364
365
```java { .api }
366
/**
367
* WebSocket close message with status code and optional reason
368
*/
369
public class CloseMessage implements Message {
370
/**
371
* Creates close message with status code only
372
* @param code Close status code
373
*/
374
public CloseMessage(int code);
375
376
/**
377
* Creates close message with status code and reason
378
* @param code Close status code
379
* @param reason Close reason string
380
*/
381
public CloseMessage(int code, String reason);
382
383
/**
384
* Gets the close status code
385
* @return Status code indicating close reason
386
*/
387
public int code();
388
389
/**
390
* Gets the close reason string
391
* @return Close reason or empty string if not provided
392
*/
393
public String reason();
394
}
395
```
396
397
**Usage Examples:**
398
399
```java
400
// Create close messages
401
CloseMessage normalClose = new CloseMessage(1000); // Normal closure
402
CloseMessage errorClose = new CloseMessage(1002, "Protocol error");
403
CloseMessage customClose = new CloseMessage(4000, "Custom application error");
404
405
// Send close messages
406
socket.send(normalClose);
407
408
// Access close information
409
int closeCode = errorClose.code(); // 1002
410
String closeReason = errorClose.reason(); // "Protocol error"
411
412
System.out.println("Closing with code " + closeCode + ": " + closeReason);
413
414
// Use in listener
415
WebSocket.Listener listener = new WebSocket.Listener() {
416
@Override
417
public void onClose(int code, String reason) {
418
System.out.println("Connection closed: " + code + " - " + reason);
419
420
// Handle different close codes
421
switch (code) {
422
case 1000:
423
System.out.println("Normal closure");
424
break;
425
case 1001:
426
System.out.println("Endpoint going away");
427
break;
428
case 1002:
429
System.out.println("Protocol error");
430
break;
431
default:
432
System.out.println("Other close reason: " + code);
433
}
434
}
435
436
@Override
437
public void accept(Message message) {
438
if (message instanceof CloseMessage) {
439
CloseMessage closeMsg = (CloseMessage) message;
440
handleClose(closeMsg.code(), closeMsg.reason());
441
}
442
}
443
444
private void handleClose(int code, String reason) {
445
// Custom close handling logic
446
}
447
};
448
```
449
450
## WebSocket Connection Lifecycle
451
452
Complete example showing WebSocket connection lifecycle:
453
454
```java
455
import org.openqa.selenium.remote.http.*;
456
import java.util.concurrent.CountDownLatch;
457
import java.util.concurrent.TimeUnit;
458
459
public class WebSocketExample {
460
private WebSocket socket;
461
private final CountDownLatch closeLatch = new CountDownLatch(1);
462
463
public void connectAndCommunicate() throws InterruptedException {
464
// Create HTTP client
465
HttpClient client = HttpClient.Factory.createDefault()
466
.createClient(new URL("wss://echo.websocket.org"));
467
468
// Create WebSocket request
469
HttpRequest wsRequest = new HttpRequest(HttpMethod.GET, "/");
470
471
// Create listener
472
WebSocket.Listener listener = new WebSocket.Listener() {
473
@Override
474
public void onText(CharSequence data) {
475
System.out.println("Echo received: " + data);
476
}
477
478
@Override
479
public void onClose(int code, String reason) {
480
System.out.println("Connection closed: " + code + " - " + reason);
481
closeLatch.countDown();
482
}
483
484
@Override
485
public void onError(Throwable cause) {
486
System.err.println("WebSocket error: " + cause.getMessage());
487
closeLatch.countDown();
488
}
489
};
490
491
// Open connection
492
socket = client.openSocket(wsRequest, listener);
493
494
// Send messages
495
socket.sendText("Hello WebSocket!");
496
socket.sendText("This is a test message");
497
498
// Send binary data
499
socket.sendBinary("Binary test data".getBytes());
500
501
// Wait a bit for responses
502
Thread.sleep(2000);
503
504
// Close connection gracefully
505
socket.send(new CloseMessage(1000, "Normal closure"));
506
507
// Wait for close confirmation
508
closeLatch.await(10, TimeUnit.SECONDS);
509
510
// Cleanup
511
client.close();
512
}
513
}
514
```