0
# WebSocket Support
1
2
Complete WebSocket integration including connection management, protocol handling, message processing, and custom protocol implementations. Atmosphere provides full WebSocket support with fallback capabilities.
3
4
## Capabilities
5
6
### WebSocket Interface
7
8
Core WebSocket connection abstraction providing methods for communication and connection management.
9
10
```java { .api }
11
/**
12
* WebSocket connection abstraction
13
*/
14
public interface WebSocket {
15
/**
16
* Write string data to WebSocket
17
* @param data string data to send
18
* @return this WebSocket for chaining
19
*/
20
public WebSocket write(String data);
21
22
/**
23
* Write byte array data to WebSocket
24
* @param data byte array to send
25
* @return this WebSocket for chaining
26
*/
27
public WebSocket write(byte[] data);
28
29
/**
30
* Write generic object data (will be serialized)
31
* @param data object to send
32
* @return this WebSocket for chaining
33
*/
34
public WebSocket write(Object data);
35
36
/**
37
* Close the WebSocket connection
38
*/
39
public void close();
40
41
/**
42
* Close with specific code and reason
43
* @param closeCode WebSocket close code
44
* @param message close reason message
45
*/
46
public void close(int closeCode, String message);
47
48
/**
49
* Check if WebSocket is open and ready
50
* @return true if connection is open
51
*/
52
public boolean isOpen();
53
54
/**
55
* Get the associated AtmosphereResource
56
* @return AtmosphereResource instance
57
*/
58
public AtmosphereResource resource();
59
}
60
```
61
62
**Usage Examples:**
63
64
```java
65
public class ChatWebSocketHandler implements WebSocketHandler {
66
@Override
67
public void onOpen(WebSocket webSocket) {
68
System.out.println("WebSocket opened");
69
webSocket.write("Welcome to chat!");
70
}
71
72
@Override
73
public void onTextMessage(WebSocket webSocket, String message) {
74
// Echo message back
75
webSocket.write("Echo: " + message);
76
77
// Broadcast to all connected clients
78
webSocket.resource().getBroadcaster().broadcast(message);
79
}
80
81
@Override
82
public void onClose(WebSocket webSocket) {
83
System.out.println("WebSocket closed");
84
}
85
}
86
```
87
88
### WebSocketHandler Interface
89
90
Event handler interface for managing WebSocket lifecycle events and message processing.
91
92
```java { .api }
93
/**
94
* Handle WebSocket-specific events and messages
95
*/
96
public interface WebSocketHandler {
97
/**
98
* Called when WebSocket connection is opened
99
* @param webSocket the opened WebSocket
100
*/
101
public void onOpen(WebSocket webSocket);
102
103
/**
104
* Called when WebSocket connection is closed
105
* @param webSocket the closed WebSocket
106
*/
107
public void onClose(WebSocket webSocket);
108
109
/**
110
* Called when WebSocket connection encounters an error
111
* @param webSocket the WebSocket with error
112
* @param t the error that occurred
113
*/
114
public void onError(WebSocket webSocket, Throwable t);
115
116
/**
117
* Called when text message is received
118
* @param webSocket the receiving WebSocket
119
* @param message the text message received
120
*/
121
public void onTextMessage(WebSocket webSocket, String message);
122
123
/**
124
* Called when binary message is received
125
* @param webSocket the receiving WebSocket
126
* @param message the binary message as byte array
127
*/
128
public void onByteMessage(WebSocket webSocket, byte[] message);
129
}
130
```
131
132
**Usage Examples:**
133
134
```java
135
@WebSocketHandlerService(path = "/websocket/data")
136
public class DataWebSocketHandler implements WebSocketHandler {
137
138
@Override
139
public void onOpen(WebSocket webSocket) {
140
// Send initial data when client connects
141
webSocket.write("{\"type\":\"welcome\",\"message\":\"Connected\"}");
142
143
// Add to broadcaster for group messages
144
webSocket.resource().getBroadcaster()
145
.addAtmosphereResource(webSocket.resource());
146
}
147
148
@Override
149
public void onTextMessage(WebSocket webSocket, String message) {
150
try {
151
// Parse JSON message
152
JsonObject json = JsonParser.parseString(message).getAsJsonObject();
153
String type = json.get("type").getAsString();
154
155
switch (type) {
156
case "ping":
157
webSocket.write("{\"type\":\"pong\"}");
158
break;
159
case "broadcast":
160
String msg = json.get("message").getAsString();
161
webSocket.resource().getBroadcaster().broadcast(msg);
162
break;
163
default:
164
webSocket.write("{\"type\":\"error\",\"message\":\"Unknown type\"}");
165
}
166
} catch (Exception e) {
167
webSocket.write("{\"type\":\"error\",\"message\":\"Invalid JSON\"}");
168
}
169
}
170
171
@Override
172
public void onByteMessage(WebSocket webSocket, byte[] message) {
173
// Handle binary data (e.g., file uploads, images)
174
System.out.println("Received " + message.length + " bytes");
175
176
// Echo binary data back
177
webSocket.write(message);
178
}
179
180
@Override
181
public void onClose(WebSocket webSocket) {
182
// Cleanup when client disconnects
183
webSocket.resource().getBroadcaster()
184
.removeAtmosphereResource(webSocket.resource());
185
System.out.println("WebSocket closed for: " + webSocket.resource().uuid());
186
}
187
188
@Override
189
public void onError(WebSocket webSocket, Throwable t) {
190
System.err.println("WebSocket error: " + t.getMessage());
191
t.printStackTrace();
192
}
193
}
194
```
195
196
### WebSocketProcessor Interface
197
198
Interface for processing WebSocket messages and managing the WebSocket protocol lifecycle.
199
200
```java { .api }
201
/**
202
* Process WebSocket messages and manage protocol lifecycle
203
*/
204
public interface WebSocketProcessor {
205
/**
206
* Open WebSocket connection
207
* @param webSocket the WebSocket to open
208
* @return WebSocket instance
209
*/
210
public WebSocket open(WebSocket webSocket);
211
212
/**
213
* Invoke WebSocket protocol handling
214
* @param webSocket the WebSocket
215
* @param webSocketMessage message to process
216
*/
217
public void invokeWebSocketProtocol(WebSocket webSocket, String webSocketMessage);
218
219
/**
220
* Close WebSocket connection
221
* @param webSocket the WebSocket to close
222
* @param closeCode close status code
223
*/
224
public void close(WebSocket webSocket, int closeCode);
225
226
/**
227
* Destroy processor and cleanup resources
228
*/
229
public void destroy();
230
}
231
```
232
233
### DefaultWebSocketProcessor
234
235
Default implementation of WebSocketProcessor providing standard WebSocket message processing.
236
237
```java { .api }
238
/**
239
* Default WebSocket message processor
240
*/
241
public class DefaultWebSocketProcessor implements WebSocketProcessor {
242
/**
243
* Create processor with AtmosphereFramework
244
* @param framework AtmosphereFramework instance
245
*/
246
public DefaultWebSocketProcessor(AtmosphereFramework framework);
247
248
/**
249
* Register WebSocketHandler for path pattern
250
* @param path URL path pattern
251
* @param handler WebSocketHandler instance
252
* @return this processor
253
*/
254
public DefaultWebSocketProcessor registerWebSocketHandler(String path, WebSocketHandler handler);
255
}
256
```
257
258
### WebSocketProtocol Interface
259
260
Interface for defining custom WebSocket message protocols and handling protocol-specific logic.
261
262
```java { .api }
263
/**
264
* Define WebSocket message protocols
265
*/
266
public interface WebSocketProtocol {
267
/**
268
* Handle incoming WebSocket message according to protocol
269
* @param webSocket the WebSocket connection
270
* @param message the incoming message
271
* @return list of processed messages for broadcast
272
*/
273
public List<AtmosphereRequest> onMessage(WebSocket webSocket, String message);
274
275
/**
276
* Configure the protocol
277
* @param config AtmosphereConfig for setup
278
*/
279
public void configure(AtmosphereConfig config);
280
281
/**
282
* Get supported protocols
283
* @return list of supported protocol names
284
*/
285
public List<String> supportedProtocols();
286
287
/**
288
* Inspect message and determine if protocol applies
289
* @param message message to inspect
290
* @return true if this protocol handles the message
291
*/
292
public boolean inspectResponse();
293
}
294
```
295
296
### Built-in WebSocket Protocols
297
298
Pre-built protocol implementations for common WebSocket communication patterns.
299
300
```java { .api }
301
/**
302
* Simple HTTP-over-WebSocket protocol
303
*/
304
public class SimpleHttpProtocol implements WebSocketProtocol {
305
/**
306
* Create protocol with delimiter
307
* @param delimiter message delimiter character
308
*/
309
public SimpleHttpProtocol(String delimiter);
310
}
311
312
/**
313
* Streaming HTTP protocol for WebSocket
314
*/
315
public class StreamingHttpProtocol implements WebSocketProtocol {
316
/**
317
* Create streaming protocol with delimiter
318
* @param delimiter message delimiter
319
*/
320
public StreamingHttpProtocol(String delimiter);
321
}
322
```
323
324
**Usage Examples:**
325
326
```java
327
// Register custom WebSocket protocol
328
@WebSocketProtocolService
329
public class JsonWebSocketProtocol implements WebSocketProtocol {
330
331
@Override
332
public List<AtmosphereRequest> onMessage(WebSocket webSocket, String message) {
333
List<AtmosphereRequest> requests = new ArrayList<>();
334
335
try {
336
// Parse JSON message
337
JsonObject json = JsonParser.parseString(message).getAsJsonObject();
338
339
// Create AtmosphereRequest from JSON
340
AtmosphereRequest.Builder builder = new AtmosphereRequest.Builder();
341
builder.pathInfo(json.get("path").getAsString());
342
builder.method(json.get("method").getAsString());
343
344
if (json.has("body")) {
345
builder.body(json.get("body").getAsString());
346
}
347
348
requests.add(builder.build());
349
350
} catch (Exception e) {
351
// Send error response
352
webSocket.write("{\"error\":\"Invalid JSON protocol message\"}");
353
}
354
355
return requests;
356
}
357
358
@Override
359
public void configure(AtmosphereConfig config) {
360
// Protocol configuration
361
}
362
363
@Override
364
public List<String> supportedProtocols() {
365
return Arrays.asList("json-protocol");
366
}
367
}
368
```
369
370
### WebSocket Factory
371
372
Factory interface for creating WebSocket instances with different implementations.
373
374
```java { .api }
375
/**
376
* Factory for creating WebSocket instances
377
*/
378
public interface WebSocketFactory {
379
/**
380
* Create WebSocket instance
381
* @param request AtmosphereRequest
382
* @param response AtmosphereResponse
383
* @return WebSocket instance
384
*/
385
public WebSocket create(AtmosphereRequest request, AtmosphereResponse response);
386
387
/**
388
* Find existing WebSocket by AtmosphereResource
389
* @param resource AtmosphereResource
390
* @return WebSocket instance or null
391
*/
392
public WebSocket find(AtmosphereResource resource);
393
}
394
395
/**
396
* Default WebSocket factory implementation
397
*/
398
public class DefaultWebSocketFactory implements WebSocketFactory {
399
/**
400
* Create factory with AtmosphereConfig
401
* @param config AtmosphereConfig instance
402
*/
403
public DefaultWebSocketFactory(AtmosphereConfig config);
404
}
405
```
406
407
### WebSocket Configuration and Management
408
409
Configuration and management utilities for WebSocket connections and behavior.
410
411
```java { .api }
412
/**
413
* WebSocket event listener for monitoring connections
414
*/
415
public interface WebSocketEventListener {
416
/**
417
* Called when any WebSocket opens
418
* @param event WebSocket event
419
*/
420
public void onWebSocketConnect(WebSocketEvent event);
421
422
/**
423
* Called when any WebSocket closes
424
* @param event WebSocket event
425
*/
426
public void onWebSocketClose(WebSocketEvent event);
427
428
/**
429
* Called on WebSocket error
430
* @param event WebSocket event with error
431
*/
432
public void onWebSocketError(WebSocketEvent event);
433
}
434
435
/**
436
* WebSocket event containing connection and context information
437
*/
438
public class WebSocketEvent {
439
/**
440
* Get the WebSocket connection
441
* @return WebSocket instance
442
*/
443
public WebSocket webSocket();
444
445
/**
446
* Get any associated error
447
* @return Throwable or null
448
*/
449
public Throwable throwable();
450
451
/**
452
* Get event type
453
* @return WebSocketEventType enum
454
*/
455
public WebSocketEventType type();
456
}
457
458
/**
459
* Types of WebSocket events
460
*/
461
public enum WebSocketEventType {
462
CONNECT,
463
MESSAGE,
464
CLOSE,
465
ERROR
466
}
467
```
468
469
### AsyncIOWriter Interface
470
471
Interface for asynchronous, non-blocking I/O operations in WebSocket and HTTP streaming contexts.
472
473
```java { .api }
474
/**
475
* Asynchronous I/O writer for non-blocking writes
476
*/
477
public interface AsyncIOWriter {
478
/**
479
* Write data asynchronously
480
* @param resource AtmosphereResource target
481
* @param data data to write
482
* @return Future for async write operation
483
*/
484
public Future<String> write(AtmosphereResource resource, String data);
485
486
/**
487
* Write byte data asynchronously
488
* @param resource AtmosphereResource target
489
* @param data byte array to write
490
* @return Future for async write operation
491
*/
492
public Future<byte[]> write(AtmosphereResource resource, byte[] data);
493
494
/**
495
* Write generic object asynchronously
496
* @param resource AtmosphereResource target
497
* @param data object to write (will be serialized)
498
* @return Future for async write operation
499
*/
500
public Future<Object> write(AtmosphereResource resource, Object data);
501
502
/**
503
* Close the writer and cleanup resources
504
* @param resource AtmosphereResource
505
*/
506
public void close(AtmosphereResource resource);
507
508
/**
509
* Flush pending writes
510
* @param resource AtmosphereResource
511
*/
512
public void flush(AtmosphereResource resource);
513
}
514
515
/**
516
* Default AsyncIOWriter implementation
517
*/
518
public class DefaultAsyncIOWriter implements AsyncIOWriter {
519
/**
520
* Create writer with AtmosphereResponse
521
* @param response AtmosphereResponse for writing
522
*/
523
public DefaultAsyncIOWriter(AtmosphereResponse response);
524
525
/**
526
* Set write timeout
527
* @param timeout write timeout in milliseconds
528
* @return this writer
529
*/
530
public DefaultAsyncIOWriter setTimeout(long timeout);
531
}
532
```
533
534
**Usage Examples:**
535
536
```java
537
@WebSocketHandlerService(path = "/async-websocket")
538
public class AsyncWebSocketHandler implements WebSocketHandler {
539
540
@Override
541
public void onOpen(WebSocket webSocket) {
542
AtmosphereResource resource = webSocket.resource();
543
AsyncIOWriter writer = resource.getResponse().getAsyncIOWriter();
544
545
// Asynchronous welcome message
546
Future<String> writeResult = writer.write(resource, "Welcome! Connection established.");
547
548
writeResult.thenAccept(result -> {
549
System.out.println("Welcome message sent successfully");
550
}).exceptionally(throwable -> {
551
System.err.println("Failed to send welcome message: " + throwable.getMessage());
552
return null;
553
});
554
}
555
556
@Override
557
public void onTextMessage(WebSocket webSocket, String message) {
558
AtmosphereResource resource = webSocket.resource();
559
AsyncIOWriter writer = resource.getResponse().getAsyncIOWriter();
560
561
// Process message asynchronously
562
CompletableFuture.supplyAsync(() -> processMessage(message))
563
.thenCompose(processed -> writer.write(resource, processed))
564
.thenAccept(result -> System.out.println("Response sent"))
565
.exceptionally(throwable -> {
566
System.err.println("Error processing message: " + throwable.getMessage());
567
return null;
568
});
569
}
570
571
private String processMessage(String message) {
572
// Simulate processing
573
try {
574
Thread.sleep(100); // Simulate work
575
} catch (InterruptedException e) {
576
Thread.currentThread().interrupt();
577
}
578
return "Processed: " + message;
579
}
580
}
581
```
582
583
### Complete WebSocket Example
584
585
```java
586
@WebSocketHandlerService(path = "/websocket/chat/{room}")
587
public class ChatWebSocketHandler implements WebSocketHandler {
588
private final Map<String, Set<WebSocket>> roomConnections = new ConcurrentHashMap<>();
589
590
@Override
591
public void onOpen(WebSocket webSocket) {
592
// Extract room from path
593
String room = extractRoomFromPath(webSocket.resource().getRequest().getPathInfo());
594
595
// Add to room connections
596
roomConnections.computeIfAbsent(room, k -> ConcurrentHashMap.newKeySet())
597
.add(webSocket);
598
599
// Send welcome message
600
webSocket.write(createMessage("system", "Welcome to room " + room));
601
602
// Notify room of new user
603
broadcastToRoom(room, createMessage("system", "User joined the room"), webSocket);
604
605
System.out.println("WebSocket opened for room: " + room);
606
}
607
608
@Override
609
public void onTextMessage(WebSocket webSocket, String message) {
610
String room = extractRoomFromPath(webSocket.resource().getRequest().getPathInfo());
611
612
try {
613
// Parse incoming message
614
JsonObject json = JsonParser.parseString(message).getAsJsonObject();
615
String type = json.get("type").getAsString();
616
617
switch (type) {
618
case "chat":
619
String text = json.get("text").getAsString();
620
String user = json.get("user").getAsString();
621
622
// Broadcast chat message to room
623
String chatMessage = createMessage("chat", text, user);
624
broadcastToRoom(room, chatMessage, null); // Include sender
625
break;
626
627
case "typing":
628
String typingUser = json.get("user").getAsString();
629
String typingMessage = createMessage("typing", typingUser + " is typing...");
630
broadcastToRoom(room, typingMessage, webSocket); // Exclude sender
631
break;
632
633
default:
634
webSocket.write(createMessage("error", "Unknown message type"));
635
}
636
} catch (Exception e) {
637
webSocket.write(createMessage("error", "Invalid message format"));
638
}
639
}
640
641
@Override
642
public void onClose(WebSocket webSocket) {
643
String room = extractRoomFromPath(webSocket.resource().getRequest().getPathInfo());
644
645
// Remove from room connections
646
Set<WebSocket> connections = roomConnections.get(room);
647
if (connections != null) {
648
connections.remove(webSocket);
649
if (connections.isEmpty()) {
650
roomConnections.remove(room);
651
}
652
}
653
654
// Notify room of user leaving
655
broadcastToRoom(room, createMessage("system", "User left the room"), null);
656
657
System.out.println("WebSocket closed for room: " + room);
658
}
659
660
@Override
661
public void onError(WebSocket webSocket, Throwable t) {
662
System.err.println("WebSocket error: " + t.getMessage());
663
t.printStackTrace();
664
665
// Send error message to client
666
webSocket.write(createMessage("error", "Connection error occurred"));
667
}
668
669
private void broadcastToRoom(String room, String message, WebSocket exclude) {
670
Set<WebSocket> connections = roomConnections.get(room);
671
if (connections != null) {
672
connections.stream()
673
.filter(ws -> ws != exclude && ws.isOpen())
674
.forEach(ws -> ws.write(message));
675
}
676
}
677
678
private String createMessage(String type, String content) {
679
return String.format("{\"type\":\"%s\",\"content\":\"%s\",\"timestamp\":%d}",
680
type, content, System.currentTimeMillis());
681
}
682
683
private String createMessage(String type, String content, String user) {
684
return String.format("{\"type\":\"%s\",\"content\":\"%s\",\"user\":\"%s\",\"timestamp\":%d}",
685
type, content, user, System.currentTimeMillis());
686
}
687
688
private String extractRoomFromPath(String pathInfo) {
689
// Extract room from path like "/websocket/chat/room123"
690
String[] parts = pathInfo.split("/");
691
return parts.length > 3 ? parts[3] : "default";
692
}
693
}
694
```