-
Notifications
You must be signed in to change notification settings - Fork 1
/
user-guide.html
1939 lines (1782 loc) · 171 KB
/
user-guide.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Tyrus 2.0.5 User Guide</title><link rel="stylesheet" type="text/css" href="/tyrus-project.github.io/documentation.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body class="contents"><div class="contents" bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div lang="en" class="book"><div class="titlepage"><div><div><h1 class="title"><a name="d0e2"></a>Tyrus 2.0.5 User Guide</h1></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="preface"><a href="#preface">Preface</a></span></dt><dt><span class="chapter"><a href="#getting-started">1. Getting Started</a></span></dt><dd><dl><dt><span class="section"><a href="#getting-started-wsapi-artifact">1.1. WebSocket Services Using Java API for WebSocket</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e34">1.1.1. Creating Annotated Server Endpoint</a></span></dt><dt><span class="section"><a href="#d0e78">1.1.2. Client Endpoint</a></span></dt><dt><span class="section"><a href="#websocket-programmatic-endpoint">1.1.3. Creating Server Endpoint Programmatically</a></span></dt><dt><span class="section"><a href="#standalone-mode">1.1.4. Tyrus in Standalone Mode</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#modules-and-dependencies">2. Tyrus Modules and Dependencies</a></span></dt><dt><span class="chapter"><a href="#deployment">3. Deploying WebSocket Endpoints</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e334">3.1. Deploying Endpoints as a WAR file</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e359">3.1.1. Deployment Algorithm</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e410">3.2. Deploying endpoints via <code class="code">jakarta.websocket.server.ServerContainer</code></a></span></dt></dl></dd><dt><span class="chapter"><a href="#websocket-api">4. WebSocket API Endpoints, Sessions and MessageHandlers</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e440">4.1. Endpoint Classes</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e464">4.1.1. jakarta.websocket.server.ServerEndpoint</a></span></dt><dt><span class="section"><a href="#d0e599">4.1.2. jakarta.websocket.ClientEndpoint</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e641">4.2. Endpoint method-level annotations</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e644">4.2.1. @OnOpen</a></span></dt><dt><span class="section"><a href="#d0e657">4.2.2. @OnClose</a></span></dt><dt><span class="section"><a href="#d0e670">4.2.3. @OnError</a></span></dt><dt><span class="section"><a href="#d0e683">4.2.4. @OnMessage</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e696">4.3. MessageHandlers</a></span></dt></dl></dd><dt><span class="chapter"><a href="#configurations">5. Configurations</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e785">5.1. <code class="code">jakarta.websocket.server.ServerEndpointConfig</code></a></span></dt><dt><span class="section"><a href="#d0e838">5.2. <code class="code">jakarta.websocket.ClientEndpointConfig</code></a></span></dt></dl></dd><dt><span class="chapter"><a href="#lifecycle">6. Endpoint Lifecycle, Sessions, Sending Messages</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e870">6.1. Endpoint Lifecycle</a></span></dt><dt><span class="section"><a href="#d0e890">6.2. <code class="code">jakarta.websocket.Session</code></a></span></dt><dt><span class="section"><a href="#d0e975">6.3. Sending Messages</a></span></dt><dt><span class="section"><a href="#d0e1007">6.4. RemoteEndpoint</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1021">6.4.1. <code class="code">jakarta.websocket.RemoteEndpoint.Basic</code></a></span></dt><dt><span class="section"><a href="#d0e1045">6.4.2. <code class="code">jakarta.websocket.RemoteEndpoint.Async</code></a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#injection">7. Injection Support</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1075">7.1. <code class="code">jakarta.inject.Inject</code> sample</a></span></dt><dt><span class="section"><a href="#d0e1102">7.2. EJB sample</a></span></dt></dl></dd><dt><span class="chapter"><a href="#tyrus-proprietary-config">8. Tyrus proprietary configuration</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1128">8.1. Client-side SSL configuration</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1149">8.1.1. Host verification</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1171">8.2. Asynchronous connectToServer methods</a></span></dt><dt><span class="section"><a href="#d0e1184">8.3. Optimized broadcast</a></span></dt><dt><span class="section"><a href="#d0e1197">8.4. Incoming buffer size</a></span></dt><dt><span class="section"><a href="#d0e1215">8.5. Shared client container</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1237">8.5.1. Custom masking key generator</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1258">8.6. WebSocket Extensions</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1283">8.6.1. ExtendedExtension sample</a></span></dt><dt><span class="section"><a href="#d0e1304">8.6.2. Per Message Deflate Extension</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1311">8.7. Client reconnect</a></span></dt><dt><span class="section"><a href="#d0e1323">8.8. Client behind proxy</a></span></dt><dt><span class="section"><a href="#d0e1331">8.9. JDK 7 client</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1353">8.9.1. SSL configuration</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1373">8.10. Tracing support</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1381">8.10.1. Configuration</a></span></dt><dt><span class="section"><a href="#d0e1447">8.10.2. Tracing Examples</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1475">8.11. Client handshake request and response logging</a></span></dt><dt><span class="section"><a href="#d0e1483">8.12. JMX Monitoring</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1557">8.12.1. Configuration</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1574">8.13. Maximal number of open sessions on server-side</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1593">8.13.1. Maximal number of open sessions per application</a></span></dt><dt><span class="section"><a href="#d0e1615">8.13.2. Maximal number of open sessions per remote address</a></span></dt><dt><span class="section"><a href="#d0e1643">8.13.3. Maximal number of open sessions per endpoint</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1658">8.14. Client HTTP Authentication</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1683">8.14.1. Credentials</a></span></dt><dt><span class="section"><a href="#d0e1691">8.14.2. Auth Configuration</a></span></dt><dt><span class="section"><a href="#d0e1709">8.14.3. User defined authenticator</a></span></dt><dt><span class="section"><a href="#d0e1736">8.14.4. Examples</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1774">8.15. Client HTTP Redirect</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1791">8.15.1. Supported HTTP response codes</a></span></dt><dt><span class="section"><a href="#d0e1816">8.15.2. Configuration</a></span></dt><dt><span class="section"><a href="#d0e1848">8.15.3. Exception handling</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1885">8.16. Client support for HTTP status 503 - Service Unavailable with Retry-After header</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1906">8.16.1. Configuration</a></span></dt></dl></dd></dl></dd></dl></div><div class="list-of-tables"><p><b>List of Tables</b></p><dl><dt>2.1. <a href="#dependencies-table-modules">Tyrus core modules</a></dt><dt>2.2. <a href="#dependencies-table-containers">Tyrus containers</a></dt></dl></div><div class="list-of-examples"><p><b>List of Examples</b></p><dl><dt>1.1. <a href="#websocket-annotated-echo-endpoint">Annotated Echo Endpoint</a></dt><dt>1.2. <a href="#websocket-client-endpoint">Client Endpoint</a></dt><dt>1.3. <a href="#websocket-programmatic-echo-endpoint">Programmatic Echo Endpoint</a></dt><dt>3.1. <a href="#deployment-serverapplicationconfig">Deployment of WAR containing several classes extending <code class="code">jakarta.websocket.server.ServerApplicationConfig</code></a></dt><dt>3.2. <a href="#deployment-servercontainer">Deployment of Annotated Endpoint Using ServerContainer</a></dt><dt>4.1. <a href="#endpoints-echo-endpoint">Echo sample server endpoint.</a></dt><dt>4.2. <a href="#endpoints-serverendpoint-annotation">jakarta.websocket.server.ServerEndpoint with all fields specified</a></dt><dt>4.3. <a href="#d0e510">Specifying URI path parameter</a></dt><dt>4.4. <a href="#d0e528">SampleDecoder</a></dt><dt>4.5. <a href="#d0e546">SampleEncoder</a></dt><dt>4.6. <a href="#d0e604">SampleClientEndpoint</a></dt><dt>4.7. <a href="#d0e651">@OnOpen with Session and EndpointConfig parameters.</a></dt><dt>4.8. <a href="#d0e664">@OnClose with Session and CloseReason parameters.</a></dt><dt>4.9. <a href="#d0e677">@OnError with Session and Throwable parameters.</a></dt><dt>4.10. <a href="#d0e690">@OnError with Session and Throwable parameters.</a></dt><dt>4.11. <a href="#d0e709">MessageHandler basic example</a></dt><dt>5.1. <a href="#d0e822">Configuration for EchoEndpoint Deployment</a></dt><dt>5.2. <a href="#d0e832">ServerEndpointConfigu built using Builder</a></dt><dt>5.3. <a href="#d0e861">ClientEndpointConfig built using Builder</a></dt><dt>6.1. <a href="#lifecycle-echo-sample">Lifecycle echo sample</a></dt><dt>6.2. <a href="#lifecycle-onmessage-sample">Sending message in @OnMessage</a></dt><dt>6.3. <a href="#lifecycle-remote-endpoint-sample">Sending message via RemoteEndpoint.Basic instance</a></dt><dt>6.4. <a href="#lifecycle-remote-endpoint-partial-sample">Method for sending partial text message</a></dt><dt>6.5. <a href="#lifecycle-remote-endpoint-async-future">Sending mesage the async way using Future</a></dt><dt>7.1. <a href="#cdi-simple-bean">Injecting bean into <code class="code">jakarta.websocket.server.ServerEndpoint</code></a></dt><dt>7.2. <a href="#cdi-singleton-bean">Echo sample server endpoint.</a></dt></dl></div><div class="preface"><div class="titlepage"><div><div><h1 class="title"><a name="preface"></a>Preface</h1></div></div></div><p>
This is user guide for Tyrus 2.0.5. We are trying to keep it up to date
as we add new features. Please use also our API documentation linked
from the
<a class="link" href="https://projects.eclipse.org/projects/ee4j.tyrus" target="_top">Tyrus</a> and
<a class="link" href="https://projects.eclipse.org/projects/ee4j.websocket" target="_top">Java API for WebSocket</a>
home pages as an additional source of information about Tyrus features and API.
If you would like to contribute to the guide or have questions
on things not covered in our docs, please contact us at
<a class="link" href="https://dev.eclipse.org/mailman/listinfo/tyrus-dev" target="_top">tyrus-dev@eclipse.org</a>.
</p></div><div lang="en" class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="getting-started"></a>Chapter 1. Getting Started</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#getting-started-wsapi-artifact">1.1. WebSocket Services Using Java API for WebSocket</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e34">1.1.1. Creating Annotated Server Endpoint</a></span></dt><dt><span class="section"><a href="#d0e78">1.1.2. Client Endpoint</a></span></dt><dt><span class="section"><a href="#websocket-programmatic-endpoint">1.1.3. Creating Server Endpoint Programmatically</a></span></dt><dt><span class="section"><a href="#standalone-mode">1.1.4. Tyrus in Standalone Mode</a></span></dt></dl></dd></dl></div><p>
This chapter provides a quick introduction on how to get started building
WebSocket services using Java API for WebSocket and Tyrus. The example described here presents how to implement
simple websocket service as JavaEE web application that can be deployed on any servlet container
supporting Servlet 3.1 and higher. It also discusses starting Tyrus in standalone mode.
</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="getting-started-wsapi-artifact"></a>1.1. WebSocket Services Using Java API for WebSocket</h2></div></div></div><p>
First, to use the Java API for WebSocket in your project you need to depend on the following artifact:
</p><pre class="
 toolbar: false;
 brush: xml;
 gutter: false;"><dependency>
<groupId>jakarta.websocket</groupId>
<artifactId>jakarta.websocket-api</artifactId>
<version>2.0.0</version>
</dependency>
</pre><p>
</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="d0e34"></a>1.1.1. Creating Annotated Server Endpoint</h3></div></div></div><p>
In this section we will create a simple server side websocket endpoint which will echo the received
message back to the sender. We will deploy this endpoint on the container.
</p><p>
In Java API for WebSocket and Tyrus, there are two basic approaches how to create an endpoint - either annotated endpoint,
or programmatic endpoint.
By annotated endpoint we mean endpoint constructed by using annotations (<code class="code">jakarta.websocket.server.ServerEndpoint</code>
for server endpoint and <code class="code">jakarta.websocket.ClientEndpoint</code> for client endpoint), like in
<a class="link" href="#websocket-annotated-echo-endpoint" title="Example 1.1. Annotated Echo Endpoint">"Annotated Echo Endpoint"</a>.
</p><div class="example"><a name="websocket-annotated-echo-endpoint"></a><p class="title"><b>Example 1.1. Annotated Echo Endpoint</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">@ServerEndpoint(value = "/echo")
public class EchoEndpointAnnotated {
@OnMessage
public String onMessage(String message, Session session) {
return message;
}
}
</pre></div></div><p><br class="example-break">
</p><p>
The functionality of the <code class="code">EchoEndpointAnnotated</code> is fairly simple - to send the received message
back to the sender. To turn a POJO (Plain Old Java Object) to WebSocket server endpoint, the annotation
<code class="code">@ServerEndpoint(value = "/echo")</code> needs to be put on the POJO - see line 1. The URI path of the endpoint
is <code class="code">"/echo"</code>. The annotation <code class="code">@OnMessage</code> - line 3 on the method <code class="code">public String
onMessage(String message, Session session)</code> indicates that this method
will be called whenever text message is received. On line 5 in this method the message is sent back to
the user by returning it from the message.
</p><p>
The application containing only the <code class="code">EchoEndpointAnnotated</code> class can be deployed to the container.
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="d0e78"></a>1.1.2. Client Endpoint</h3></div></div></div><p>
Let's create the client part of the application. The client part may be written in JavaScript or any
other technology supporting WebSockets. We will use Java API for WebSocket and Tyrus to demonstrate how to develop
programmatic client endpoint.
The following code is used as a client part to communicate with the <code class="code">EchoEndpoint</code> deployed on server
using Tyrus and Java API for WebSocket.
</p><p>
The example <a class="link" href="#websocket-client-endpoint" title="Example 1.2. Client Endpoint">"Client Endpoint"</a> utilizes the concept
of the programmatic endpoint. By programmatic endpoint we mean endpoint which is created by extending
class <code class="code">jakarta.websocket.Endpoint</code>.
The example is standalone java application which needs to depend on some Tyrus artifacts to work
correctly, see <a class="link" href="#standalone-mode" title="1.1.4. Tyrus in Standalone Mode">"Tyrus Standalone Mode"</a>.
In the example first the <code class="code">CountDownLatch</code> is initialized. It is needed as a bocking data
structure - on line 31 it either waits for 100 seconds, or until it gets counted down (line 22).
On line 9 the <code class="code">jakarta.websocket.ClientEndpointConfig</code> is created - we will need it later
to connect the endpoint to the server. On line 11 the <code class="code">org.glassfish.tyrus.client.ClientManager</code>
is created. it implements the <code class="code">jakarta.websocket.WebSocketContainer</code> and is used to connect
to server. This happens on next line. The client endpoint functionality is contained in the <code class="code">
jakarta.websocket.Endpoint</code> lazy instantiation. In the <code class="code">onOpen</code> method new MessageHandler
is registered (the received message is just printed on the console and the latch is counted down). After
the registration the message is sent to the server (line 25).
</p><div class="example"><a name="websocket-client-endpoint"></a><p class="title"><b>Example 1.2. Client Endpoint</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">public class DocClient {
private static CountDownLatch messageLatch;
private static final String SENT_MESSAGE = "Hello World";
public static void main(String [] args){
try {
messageLatch = new CountDownLatch(1);
final ClientEndpointConfig cec = ClientEndpointConfig.Builder.create().build();
ClientManager client = ClientManager.createClient();
client.connectToServer(new Endpoint() {
@Override
public void onOpen(Session session, EndpointConfig config) {
try {
session.addMessageHandler(new MessageHandler.Whole<String>() {
@Override
public void onMessage(String message) {
System.out.println("Received message: "+message);
messageLatch.countDown();
}
});
session.getBasicRemote().sendText(SENT_MESSAGE);
} catch (IOException e) {
e.printStackTrace();
}
}
}, cec, new URI("ws://localhost:8025/websockets/echo"));
messageLatch.await(100, TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
}
}
}</pre></div></div><p><br class="example-break">
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="websocket-programmatic-endpoint"></a>1.1.3. Creating Server Endpoint Programmatically</h3></div></div></div><p>
Similarly to <a class="link" href="#websocket-client-endpoint" title="Example 1.2. Client Endpoint">"Client Endpoint"</a> the server registered endpoint
may also be the programmatic one:
</p><div class="example"><a name="websocket-programmatic-echo-endpoint"></a><p class="title"><b>Example 1.3. Programmatic Echo Endpoint</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">public class EchoEndpointProgrammatic extends Endpoint {
@Override
public void onOpen(final Session session, EndpointConfig config) {
session.addMessageHandler(new MessageHandler.Whole<String>() {
@Override
public void onMessage(String message) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}</pre></div></div><p><br class="example-break">
</p><p>
The functionality of the <code class="code">EchoEndpointProgrammatic</code> is fairly simple - to send the received message back to the sender.
The programmatic server endpoint needs to extend <code class="code">jakarta.websocket.Endpoint</code> - line 1.
Mehod <code class="code">public void onOpen(final Session session, EndpointConfig config)</code> gets called once new
connection to this endpoin0t is opened. In this method the <code class="code">MessageHandler</code> is registered to the
<code class="code">jakarta.websocket.Session</code> instance, which opened the connection. Method <code class="code">public void
onMessage(String message)</code> gets called once the message is received. On line 8 the message
is sent back to the sender.
</p></div><p>
To see how both annotated and programmatic endpoints may be deployed please check the section Deployment.
In short: you need to put the server endpoint classes into WAR, deploy on server and the endpoints will
be scanned by server and deployed.
</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="standalone-mode"></a>1.1.4. Tyrus in Standalone Mode</h3></div></div></div><p>
</p><p>
To use Tyrus in standalone mode it is necessary to depend on correct Tyrus artifacts.
The following artifacts need to be added to your pom to use Tyrus:
</p><pre class="
 toolbar: false;
 brush: xml;
 gutter: false;"><dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-server</artifactId>
<version>2.0.5</version>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-container-grizzly-server</artifactId>
<version>2.0.5</version>
</dependency></pre><p>
</p><p>
Let's use the very same example like for Java API for WebSocket and deploy the <code class="code">EchoEndpointAnnotated</code> on the
standalone Tyrus server on the hostname "localhost", port 8025 and path "/websockets", so the endpoint
will be available at address "ws://localhost:8025/websockets/echo".
</p><pre class="
 toolbar: false;
 brush: java;
 gutter: false;">public void runServer() {
Server server = new Server("localhost", 8025, "/websockets", null, EchoEndpoint.class);
try {
server.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Please press a key to stop the server.");
reader.readLine();
} catch (Exception e) {
e.printStackTrace();
} finally {
server.stop();
}
}</pre><p>
</p></div></div></div><div lang="en" class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="modules-and-dependencies"></a>Chapter 2. Tyrus Modules and Dependencies</h1></div></div></div><p>
Tyrus is built, assembled and installed using Maven. Tyrus is deployed to maven.org maven repository
at the following location:<a class="link" href="http://search.maven.org/" target="_top">http://search.maven.org/</a>.
Jars, jar sources, jar javadoc and samples are all available on the java.net maven repository.
</p><p>
All Tyrus components are built using Java SE 7 compiler. It means, you will also need at least Java SE 7
to be able to compile and run your application. Developers using maven are likely to find it easier to include
and
manage dependencies of their applications than developers using ant or other build technologies. The following
table provides an overview of all Tyrus modules and their dependencies with links to the respective binaries.
</p><div class="table"><a name="dependencies-table-modules"></a><p class="title"><b>Table 2.1. Tyrus core modules</b></p><div class="table-contents"><table summary="Tyrus core modules" border="1"><colgroup><col width="14%" align="left" class="c1"><col width="35%" align="left" class="c2"><col width="51%" align="left" class="c3"></colgroup><thead><tr><th align="left">Module</th><th align="left">Dependencies</th><th align="left">Description</th></tr></thead><tbody><tr><td align="left">
<a class="link" href="http://search.maven.org/#artifactdetails|org.glassfish.tyrus|tyrus-server|2.0.5|jar" target="_top">
tyrus-server
</a>
</td><td align="left">tyrus-core, tyrus-spi, tyrus-websocket-core</td><td align="left">Basic server functionality</td></tr><tr><td align="left">
<a class="link" href="http://search.maven.org/#artifactdetails|org.glassfish.tyrus|tyrus-core|2.0.5|jar" target="_top">
tyrus-core
</a>
</td><td align="left">tyrus-spi, tyrus-websocket-core</td><td align="left">Core Tyrus functionality</td></tr><tr><td align="left">
<a class="link" href="http://search.maven.org/#artifactdetails|org.glassfish.tyrus|tyrus-client|2.0.5|jar" target="_top">
tyrus-client
</a>
</td><td align="left">tyrus-core, tyrus-spi, tyrus-websocket-core</td><td align="left">Basic client functionality</td></tr><tr><td align="left">
<a class="link" href="http://search.maven.org/#artifactdetails|org.glassfish.tyrus|tyrus-documentation|2.0.5|jar" target="_top">
tyrus-documentation
</a>
</td><td align="left">[nothing]</td><td align="left">Project documentation</td></tr><tr><td align="left">
<a class="link" href="http://search.maven.org/#artifactdetails|org.glassfish.tyrus|tyrus-websocket-core|2.0.5|jar" target="_top">
tyrus-websocket-core
</a>
</td><td align="left">[nothing]</td><td align="left">The WebSocket protocol</td></tr><tr><td align="left">
<a class="link" href="http://search.maven.org/remotecontent?filepath=org/glassfish/tyrus/bundles/tyrus-samples/2.0.5/tyrus-samples-2.0.5-all.zip" target="_top">
tyrus-samples
</a>
</td><td align="left">tyrus-server, tyrus-client, tyrus-container-grizzly, tyrus-core, tyrus-spi,
tyrus-websocket-core
</td><td align="left">Samples of using Java API for WebSocket and Tyrus</td></tr><tr><td align="left">
<a class="link" href="http://search.maven.org/#artifactdetails|org.glassfish.tyrus|tyrus-spi|2.0.5|jar" target="_top">
tyrus-spi
</a>
</td><td align="left">[nothing]</td><td align="left">SPI</td></tr></tbody></table></div></div><br class="table-break"><div class="table"><a name="dependencies-table-containers"></a><p class="title"><b>Table 2.2. Tyrus containers</b></p><div class="table-contents"><table summary="Tyrus containers" border="1"><colgroup><col width="14%" align="left" class="c1"><col width="35%" align="left" class="c2"><col width="51%" align="left" class="c3"></colgroup><thead><tr><th align="left">Module</th><th align="left">Dependencies</th><th align="left">Description</th></tr></thead><tbody><tr><td align="left">
<a class="link" href="http://search.maven.org/#artifactdetails|org.glassfish.tyrus|tyrus-container-glassfish-cdi|2.0.5|jar" target="_top">
tyrus-container-glassfish-cdi
</a>
</td><td align="left">tyrus-spi</td><td align="left">CDI support</td></tr><tr><td align="left">
<a class="link" href="http://search.maven.org/#artifactdetails|org.glassfish.tyrus|tyrus-container-glassfish-ejb|2.0.5|jar" target="_top">
tyrus-container-glassfish-ejb
</a>
</td><td align="left">tyrus-spi</td><td align="left">EJB support</td></tr><tr><td align="left">
<a class="link" href="http://search.maven.org/#artifactdetails|org.glassfish.tyrus|tyrus-container-grizzly|2.0.5|jar" target="_top">
tyrus-container-grizzly
</a>
</td><td align="left">tyrus-core, tyrus-spi, tyrus-websocket-core</td><td align="left">Grizzly integration for Tyrus client and standalone server usage</td></tr><tr><td align="left">
<a class="link" href="http://search.maven.org/#artifactdetails|org.glassfish.tyrus|tyrus-container-servlet|2.0.5|bundle" target="_top">
tyrus-container-servlet
</a>
</td><td align="left">tyrus-server, tyrus-core, tyrus-spi, tyrus-websocket-core</td><td align="left">Servlet support for integration into web containers</td></tr></tbody></table></div></div><br class="table-break"></div><div lang="en" class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="deployment"></a>Chapter 3. Deploying WebSocket Endpoints</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#d0e334">3.1. Deploying Endpoints as a WAR file</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e359">3.1.1. Deployment Algorithm</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e410">3.2. Deploying endpoints via <code class="code">jakarta.websocket.server.ServerContainer</code></a></span></dt></dl></div><p>
Deploying WebSocket endpoints can be done in two ways. Either deploying via putting the endpoint in the WAR
file, or using the ServerContainer methods to deploy the programmatic endpoint in the deployment phase.
</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e334"></a>3.1. Deploying Endpoints as a WAR file</h2></div></div></div><p>
The classes that are scanned for in WAR are the following ones:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: opencircle; "><li class="listitem" style="list-style-type: circle"><p>
Classes that implement the <code class="code">jakarta.websocket.ServerApplicationConfig</code>.
</p></li><li class="listitem" style="list-style-type: circle"><p>
Classes annotated with <code class="code">jakarta.websocket.server.ServerEndpoint</code>.
</p></li><li class="listitem" style="list-style-type: circle"><p>
Classes that extend <code class="code">jakarta.websocket.Endpoint</code>.
</p></li></ul></div><p>
</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="d0e359"></a>3.1.1. Deployment Algorithm</h3></div></div></div><p>
</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">
If one or more classes implementing ServerApplicationConfiguration are present in the WAR file, Tyrus deploys endpoints
provided by all of these classes. Tyrus doesn't deploy any other classes present in the WAR (annotated by
<code class="code">jakarta.websocket.server.ServerEndpoint</code> or extending <code class="code">jakarta.websocket.Endpoint</code>).
</li><li class="listitem">
If no class implementing ServerApplicationConfiguration is present, Tyrus deploys all classes annotated
with @ServerEndpoint or extending Endpoint present in the WAR.
</li></ol></div><p>
</p></div><p>
Let's have the following classes in the WAR:
</p><div class="example"><a name="deployment-serverapplicationconfig"></a><p class="title"><b>Example 3.1. Deployment of WAR containing several classes extending <code class="code">jakarta.websocket.server.ServerApplicationConfig</code></b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">public class MyApplicationConfigOne implements ServerApplicationConfig {
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> endpointClasses);
Set<Class<? extends Endpoint>> s = new HashSet<Class<? extends Endpoint>>;
s.add(ProgrammaticEndpointOne.class);
return s;
}
public Set<Class> getAnnotatedEndpointClasses(Set<Class<?>> scanned);
Set<Class<?>> s = new HashSet<Class<?>>;
s.add(AnnotatedEndpointOne.class);
return s;
}
}
public class MyApplicationConfigTwo implements ServerApplicationConfig {
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> endpointClasses);
Set<Class<? extends Endpoint>> s = new HashSet<Class<? extends Endpoint>>;
s.add(ProgrammaticEndpointTwo.class);
return s;
}
public Set<Class> getAnnotatedEndpointClasses(Set<Class<?>> scanned);
Set<Class<?>> s = new HashSet<Class<?>>;
s.add(AnnotatedEndpointTwo.class);
return s;
}
}
@ServerEndpoint(value = "/annotatedone")
public class AnnotatedEndpointOne {
...
}
@ServerEndpoint(value = "/annotatedtwo")
public class AnnotatedEndpointTwo {
...
}
@ServerEndpoint(value = "/annotatedthree")
public class AnnotatedEndpointThree {
...
}
public class ProgrammaticEndpointOne extends Endpoint {
...
}
public class ProgrammaticEndpointTwo extends Endpoint {
...
}
public class ProgrammaticEndpointThree extends Endpoint {
...
}</pre></div></div><p><br class="example-break">
According to the deployment algorithm classes <code class="code">AnnotatedEndpointOne</code>, <code class="code">AnnotatedEndpointTwo</code>,
<code class="code">ProgrammaticEndpointOne</code> and <code class="code">ProgrammaticEndpointTwo</code> will be deployed.
<code class="code">AnnotatedEndpointThree</code> and <code class="code">ProgrammaticEndpointThree</code> will not be
deployed, as these are not returned by the respective
methods of <code class="code">MyApplicationConfigOne</code> nor <code class="code">MyApplicationConfigTwo</code>.
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e410"></a>3.2. Deploying endpoints via <code class="code">jakarta.websocket.server.ServerContainer</code></h2></div></div></div><p>
Endpoints may be deployed using <code class="code">jakarta.websocket.server.ServerContainer</code> during the application initialization phase.
For websocket enabled web containers, developers may obtain a reference to the ServerContainer instance by
retrieving it as an attribute named <code class="code">jakarta.websocket.server.ServerContainer</code> on the ServletContext, see
the following example for annotated endpoint:
</p><div class="example"><a name="deployment-servercontainer"></a><p class="title"><b>Example 3.2. Deployment of Annotated Endpoint Using ServerContainer</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">@WebListener
@ServerEndpoint("/annotated")
public class MyServletContextListenerAnnotated implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
final ServerContainer serverContainer = (ServerContainer) servletContextEvent.getServletContext()
.getAttribute("jakarta.websocket.server.ServerContainer");
try {
serverContainer.addEndpoint(MyServletContextListenerAnnotated.class);
} catch (DeploymentException e) {
e.printStackTrace();
}
}
@OnMessage
public String onMessage(String message) {
return message;
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}</pre></div></div><p><br class="example-break">
</p></div></div><div lang="en" class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="websocket-api"></a>Chapter 4. WebSocket API Endpoints, Sessions and MessageHandlers</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#d0e440">4.1. Endpoint Classes</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e464">4.1.1. jakarta.websocket.server.ServerEndpoint</a></span></dt><dt><span class="section"><a href="#d0e599">4.1.2. jakarta.websocket.ClientEndpoint</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e641">4.2. Endpoint method-level annotations</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e644">4.2.1. @OnOpen</a></span></dt><dt><span class="section"><a href="#d0e657">4.2.2. @OnClose</a></span></dt><dt><span class="section"><a href="#d0e670">4.2.3. @OnError</a></span></dt><dt><span class="section"><a href="#d0e683">4.2.4. @OnMessage</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e696">4.3. MessageHandlers</a></span></dt></dl></div><p>This chapter presents an overview of the core WebSocket API concepts - endpoints, configurations and message
handlers.</p><p>The JAVA API for WebSocket specification draft can be found online <a class="link" href="http://jcp.org/aboutJava/communityprocess/pfd/jsr356/index.html" target="_top">here</a>.
</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e440"></a>4.1. Endpoint Classes</h2></div></div></div><p>
<span class="emphasis"><em>Server endpoint classes</em></span>
are POJOs (Plain Old Java Objects) that are annotated with <code class="code">jakarta.websocket.server.ServerEndpoint</code>.
Similarly, <span class="emphasis"><em>client endpoint classes</em></span> are POJOs annotated with jakarta.websocket.ClientEndpoint.
This section shows how to use Tyrus to annotate Java objects to create WebSocket web services.
</p><p>The following code example is a simple example of a WebSocket endpoint using annotations. The example
code shown here is from echo sample which ships with Tyrus.
</p><p>
</p><div class="example"><a name="endpoints-echo-endpoint"></a><p class="title"><b>Example 4.1. Echo sample server endpoint.</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">@ServerEndpoint("/echo")
public class EchoEndpoint {
@OnOpen
public void onOpen(Session session) throws IOException {
session.getBasicRemote().sendText("onOpen");
}
@OnMessage
public String echo(String message) {
return message + " (from your server)";
}
@OnError
public void onError(Throwable t) {
t.printStackTrace();
}
@OnClose
public void onClose(Session session) {
}
}</pre></div></div><p><br class="example-break">
Let's explain the JAVA API for WebSocket annotations.
</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="d0e464"></a>4.1.1. jakarta.websocket.server.ServerEndpoint</h3></div></div></div><p>jakarta.websocket.server.ServerEndpoint has got one mandatory field - <span class="emphasis"><em>value</em></span> and four optional fields.
See the example below.</p><p>
</p><div class="example"><a name="endpoints-serverendpoint-annotation"></a><p class="title"><b>Example 4.2. jakarta.websocket.server.ServerEndpoint with all fields specified</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">@ServerEndpoint(
value = "/sample",
decoders = ChatDecoder.class,
encoders = DisconnectResponseEncoder.class,
subprotocols = {"subprtotocol1", "subprotocol2"},
configurator = Configurator.class
)
public class SampleEndpoint {
@OnMessage
public SampleResponse receiveMessage(SampleType message, Session session) {
return new SampleResponse(message);
}
}</pre></div></div><p><br class="example-break">
</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="d0e480"></a>4.1.1.1. value</h4></div></div></div><p>
Denotes a relative URI path at which the server endpoint will be deployed. In the example
<a class="link" href="#endpoints-serverendpoint-annotation" title="Example 4.2. jakarta.websocket.server.ServerEndpoint with all fields specified">"jakarta.websocket.server.ServerEndpoint with all fields specified"</a>, the
Java class will be hosted at the URI path
<code class="literal">/sample</code>. The field <span class="emphasis"><em>value</em></span> must begin with a '/' and may or may
not end in a '/', it makes no difference. Thus request URLs that end or do not end in a '/' will both
be matched. WebSocket API for JAVA supports level 1 URI templates.
</p><p>
<span class="emphasis"><em>URI path templates</em></span>
are URIs with variables embedded within the URI syntax. These variables are substituted at runtime in
order for a resource to respond to a request based on the substituted URI. Variables are denoted by
curly braces. For example, look at the following @ServerEndpoint annotation:
</p><pre class="
 toolbar: false;
 brush: java;
 gutter: false;">@ServerEndpoint("/users/{username}")</pre><p>
In this type of example, a user will be prompted to enter their name, and then a Tyrus web
service configured
to respond to requests to this URI path template will respond. For example, if the user entered their
username as "Galileo", the web service will respond to the following URL:
<code class="literal">http://example.com/users/Galileo</code>
</p><p>To obtain the value of the username variable the <code class="code">jakarta.websocket.server.PathParam</code> may be used on method parameter
of methods annotated with one of @OnOpen, @OnMessage, @OnError, @OnClose.
</p><div class="example"><a name="d0e510"></a><p class="title"><b>Example 4.3. Specifying URI path parameter</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">@ServerEndpoint("/users/{username}")
public class UserEndpoint {
@OnMessage
public String getUser(String message, @PathParam("username") String userName) {
...
}
}</pre></div></div><p><br class="example-break">
</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="d0e516"></a>4.1.1.2. decoders</h4></div></div></div><p>
Contains list of classes that will be used to decode incoming messages for the endpoint. By decoding
we mean transforming from text / binary websocket message to some user defined type. Each decoder
needs to implement the Decoder interface.
</p><p>
<code class="code">SampleDecoder</code> in the following example decodes String message and produces
SampleType message - see decode method on line 4.
</p><p>
</p><div class="example"><a name="d0e528"></a><p class="title"><b>Example 4.4. SampleDecoder</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">public class SampleDecoder implements Decoder.Text<SampleType> {
@Override
public SampleType decode(String s) {
return new SampleType(s);
}
@Override
public boolean willDecode(String s) {
return s.startsWith(SampleType.PREFIX);
}
@Override
public void init(EndpointConfig config) {
// do nothing.
}
@Override
public void destroy() {
// do nothing.
}
}</pre></div></div><p><br class="example-break">
</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="d0e534"></a>4.1.1.3. encoders</h4></div></div></div><p>
Contains list of classes that will be used to encode outgoing messages. By encoding we mean
transforming message from user defined type to text or binary type. Each encoder needs
to implement the Encoder interface.
</p><p>
<code class="code">SampleEncoder</code> in the following example decodes String message and produces
SampleType message - see decode method on line 4.
</p><p>
</p><div class="example"><a name="d0e546"></a><p class="title"><b>Example 4.5. SampleEncoder</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">public class SampleEncoder implements Encoder.Text<SampleType> {
@Override
public String encode(SampleType message) {
return data.toString();
}
@Override
public void init(EndpointConfig config) {
// do nothing.
}
@Override
public void destroy() {
// do nothing.
}
}</pre></div></div><p><br class="example-break">
</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="d0e552"></a>4.1.1.4. subprotocols</h4></div></div></div><p>
List of names (Strings) of supported sub-protocols. The first protocol in this list that matches
with sub-protocols provided by the client side is used.
</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="d0e557"></a>4.1.1.5. configurator</h4></div></div></div><p>
Users may provide their own implementation of ServerEndpointConfiguration.Configurator. It allows
them to control some algorithms used by Tyrus in the connection initialization phase:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: opencircle; "><li class="listitem" style="list-style-type: circle"><p>
<code class="code">public String getNegotiatedSubprotocol(List<String> supported, List<String> requested)</code>
allows the user to provide their own algorithm for selection of used subprotocol.
</p></li><li class="listitem" style="list-style-type: circle"><p>
<code class="code">public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested)</code>
allows the user to provide their own algorithm for selection of used Extensions.
</p></li><li class="listitem" style="list-style-type: circle"><p>
<code class="code">public boolean checkOrigin(String originHeaderValue)</code>.
allows the user to specify the origin checking algorithm.
</p></li><li class="listitem" style="list-style-type: circle"><p>
<code class="code">public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) </code>.
allows the user to modify the handshake response that will be sent back to the client.
</p></li><li class="listitem" style="list-style-type: circle"><p>
<code class="code">public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException </code>.
allows the user to provide the way how the instance of an Endpoint is created
</p></li></ul></div><p>
</p><p>
</p><pre class="
 toolbar: false;
 brush: java;
 ">public class ConfiguratorTest extends ServerEndpointConfig.Configurator{
public String getNegotiatedSubprotocol(List<String> supported, List<String> requested) {
// Plug your own algorithm here
}
public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested) {
// Plug your own algorithm here
}
public boolean checkOrigin(String originHeaderValue) {
// Plug your own algorithm here
}
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
// Plug your own algorithm here
}
public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {
// Plug your own algorithm here
}
}</pre><p>
</p></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="d0e599"></a>4.1.2. jakarta.websocket.ClientEndpoint</h3></div></div></div><p>The @ClientEndpoint class-level annotation is used to turn a POJO into WebSocket client endpoint.
In the following sample the client sends text message "Hello!" and prints out each received message.
</p><div class="example"><a name="d0e604"></a><p class="title"><b>Example 4.6. SampleClientEndpoint</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">@ClientEndpoint(
decoders = SampleDecoder.class,
encoders = SampleEncoder.class,
subprotocols = {"subprtotocol1", "subprotocol2"},
configurator = ClientConfigurator.class)
public class SampleClientEndpoint {
@OnOpen
public void onOpen(Session p) {
try {
p.getBasicRemote().sendText("Hello!");
} catch (IOException e) {
e.printStackTrace();
}
}
@OnMessage
public void onMessage(String message) {
System.out.println(String.format("%s %s", "Received message: ", message));
}
}
</pre></div></div><p><br class="example-break">
</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="d0e610"></a>4.1.2.1. decoders</h4></div></div></div><p>
Contains list of classes that will be used decode incoming messages for the endpoint. By decoding
we mean transforming from text / binary websocket message to some user defined type. Each decoder
needs to implement the Decoder interface.
</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="d0e615"></a>4.1.2.2. encoders</h4></div></div></div><p>
Contains list of classes that will be used to encode outgoing messages. By encoding we mean
transforming message from user defined type to text or binary type. Each encoder needs
to implement the Encoder interface.
</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="d0e620"></a>4.1.2.3. subprotocols</h4></div></div></div><p>
List of names (Strings) of supported sub-protocols.
</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="d0e625"></a>4.1.2.4. configurator</h4></div></div></div><p>
Users may provide their own implementation of ClientEndpointConfiguration.Configurator. It allows
them to control some algorithms used by Tyrus in the connection initialization phase. Method
<span class="emphasis"><em>beforeRequest</em></span> allows the user to change the request headers constructed by
Tyrus. Method <span class="emphasis"><em>afterResponse</em></span> allows the user to process the handshake response.
</p><p>
</p><pre class="
 toolbar: false;
 brush: java;
 ">public class Configurator {
public void beforeRequest(Map<String, List<String>> headers) {
//affect the headers before request is sent
}
public void afterResponse(HandshakeResponse hr) {
//process the handshake response
}
}</pre><p>
</p></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e641"></a>4.2. Endpoint method-level annotations</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="d0e644"></a>4.2.1. @OnOpen</h3></div></div></div><p>This annotation may be used on certain methods of @ServerEndpoint or @ClientEndpoint, but only once
per endpoint. It is used to decorate a method which is called once new connection is established.
The connection is represented by the optional Session parameter. The other optional parameter
is EndpointConfig, which represents the passed configuration object. Note that the EndpointConfig
allows the user to access the user properties.
</p><p>
</p><div class="example"><a name="d0e651"></a><p class="title"><b>Example 4.7. @OnOpen with Session and EndpointConfig parameters.</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">@ServerEndpoint("/sample")
public class EchoEndpoint {
private Map<String, Object> properties;
@OnOpen
public void onOpen(Session session, EndpointConfig config) throws IOException {
session.getBasicRemote().sendText("onOpen");
properties = config.getUserProperties();
}
}</pre></div></div><p><br class="example-break">
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="d0e657"></a>4.2.2. @OnClose</h3></div></div></div><p>This annotation may be used on any method of @ServerEndpoint or @ClientEndpoint, but only once
per endpoint. It is used to decorate a method which is called once the connection is being closed.
The method may have one Session parameter, one CloseReason parameter and parameters
annotated with @PathParam.
</p><p>
</p><div class="example"><a name="d0e664"></a><p class="title"><b>Example 4.8. @OnClose with Session and CloseReason parameters.</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">@ServerEndpoint("/sample")
public class EchoEndpoint {
@OnClose
public void onClose(Session session, CloseReason reason) throws IOException {
//prepare the endpoint for closing.
}
}</pre></div></div><p><br class="example-break">
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="d0e670"></a>4.2.3. @OnError</h3></div></div></div><p>This annotation may be used on any method of @ServerEndpoint or @ClientEndpoint, but only once
per endpoint. It is used to decorate a method which is called once Exception is being thrown by
any method annotated with @OnOpen, @OnMessage and @OnClose.
The method may have optional Session parameter and Throwable parameters.
</p><p>
</p><div class="example"><a name="d0e677"></a><p class="title"><b>Example 4.9. @OnError with Session and Throwable parameters.</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">@ServerEndpoint("/sample")
public class EchoEndpoint {
@OnError
public void onError(Session session, Throwable t) {
t.printStackTrace();
}
}</pre></div></div><p><br class="example-break">
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="d0e683"></a>4.2.4. @OnMessage</h3></div></div></div><p>This annotation may be used on certain methods of @ServerEndpoint or @ClientEndpoint, but
only once per endpoint. It is used to decorate a method which is called once new message is received.
</p><p>
</p><div class="example"><a name="d0e690"></a><p class="title"><b>Example 4.10. @OnError with Session and Throwable parameters.</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">@ServerEndpoint("/sample")
public class EchoEndpoint {
@OnMessage
public void onMessage(Session session, String message) {
System.out.println("Received message: " + message);
}
}</pre></div></div><p><br class="example-break">
</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e696"></a>4.3. MessageHandlers</h2></div></div></div><p>
Implementing the <code class="code">jakarta.websocket.MessageHandler</code> interface is one of the ways how to receive messages
on endpoints (both server and client). It is aimed primarily on programmatic endpoints, as the annotated ones
use the method level annotation <code class="code">jakarta.websocket.OnMessage</code> to denote the method which
receives messages.
</p><p>
The MessageHandlers get registered on the Session instance:
</p><div class="example"><a name="d0e709"></a><p class="title"><b>Example 4.11. MessageHandler basic example</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">public class MyEndpoint extends Endpoint {
@Override
public void onOpen(Session session, EndpointConfig EndpointConfig) {
session.addMessageHandler(new MessageHandler.Whole<String>() {
@Override
public void onMessage(String message) {
System.out.println("Received message: "+message);
}
});
}
}</pre></div></div><p><br class="example-break">
</p><p>
There are two orthogonal criterions which classify MessageHandlers.
According the WebSocket Protocol (RFC 6455) the message may be sent either complete, or in chunks. In Java API for WebSocket this fact is reflected
by the interface which the handler implements. Whole messages are processed by handler which implements
<code class="code">jakarta.websocket.MessageHandler.Whole</code> interface. Partial
messages are processed by handlers that implement <code class="code">jakarta.websocket.MessageHandler.Partial</code>
interface. However, if user registers just the whole message handler, it doesn't mean that the handler will
process solely whole messages. If partial message is received, the parts are cached by Tyrus until the final
part is received. Then the whole message is passed to the handler. Similarly, if the user registers just the
partial message handler and whole message is received, it is passed directly to the handler.
</p><p>
The second criterion is the data type of the message. WebSocket Protocol (RFC 6455) defines four message data type - text message,
According to Java API for WebSocket the text messages will be processed by MessageHandlers with the following types:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: opencircle; "><li class="listitem" style="list-style-type: circle"><p>
<span class="emphasis"><em>java.lang.String</em></span>
</p></li><li class="listitem" style="list-style-type: circle"><p>
<span class="emphasis"><em>java.io.Reader</em></span>
</p></li><li class="listitem" style="list-style-type: circle"><p>
any developer object for which there is a corresponding <span class="emphasis"><em>jakarta.websocket.Decoder.Text</em></span>
or <span class="emphasis"><em>jakarta.websocket.Decoder.TextStream</em></span>.
</p></li></ul></div><p>
The binary messages will be processed by MessageHandlers with the following types:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: opencircle; "><li class="listitem" style="list-style-type: circle"><p>
<span class="emphasis"><em>java.nio.ByteBuffer</em></span>
</p></li><li class="listitem" style="list-style-type: circle"><p>
<span class="emphasis"><em>java.io.InputStream</em></span>
</p></li><li class="listitem" style="list-style-type: circle"><p>
any developer object for which there is a corresponding <span class="emphasis"><em>jakarta.websocket.Decoder.Binary</em></span>
or <span class="emphasis"><em>jakarta.websocket.Decoder.BinaryStream</em></span>.
</p></li></ul></div><p>
</p><p>
The Java API for WebSocket limits the registration of MessageHandlers per Session to be one MessageHandler per native
websocket message type. In other words, the developer can only register at most one MessageHandler for
incoming text messages, one MessageHandler for incoming binary messages, and one MessageHandler for
incoming pong messages. This rule holds for both whole and partial message handlers, i.e there may be one
text MessageHandler - either whole, or partial, not both.
</p></div></div><div lang="en" class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="configurations"></a>Chapter 5. Configurations</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#d0e785">5.1. <code class="code">jakarta.websocket.server.ServerEndpointConfig</code></a></span></dt><dt><span class="section"><a href="#d0e838">5.2. <code class="code">jakarta.websocket.ClientEndpointConfig</code></a></span></dt></dl></div><p>
<code class="code">jakarta.websocket.server.ServerEndpointConfig</code> and <code class="code">jakarta.websocket.ClientEndpointConfig</code> objects
are used to provide the user the ability to configure websocket endpoints. Both server and client endpoints have some
part of configuration in common, namely encoders, decoders, and user properties. The user properties may developers
use to store the application specific data. For the developer's convenience the builders are provided for both
ServerEndpointConfig and ClientEndpointConfig.
</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e785"></a>5.1. <code class="code">jakarta.websocket.server.ServerEndpointConfig</code></h2></div></div></div><p>
The <code class="code">jakarta.websocket.server.ServerEndpointConfig</code> is used when deploying the endpoint either via
implementing the <code class="code">jakarta.websocket.server.ServerApplicationConfig</code>, or via registering the programmatic endpoint
at the <code class="code">jakarta.websocket.server.ServerContainer</code> instance. It allows the user to create the configuration
programmatically.
</p><p>
The following example is used to deploy the EchoEndpoint programmatically. In the method
<code class="code">getEndpointClass()</code> the user has to specify the class of the deployed endpoint. In
the example Tyrus will create an instance of <code class="code">EchoEndpoint</code> and deploy it.
This is the way how to tie together endpoint and it's configuration. In the method
<code class="code">getPath()</code> the user specifies that that the endpoint instance will be deployed at the
path "/echo". In the method <code class="code">public List<String> getSubprotocols()</code> the user
specifies that the supported subprotocols are "echo1" and "echo2". The method <code class="code">getExtensions()</code>
defines the extensions the endpoint supports. Similarly the example configuration does not use any configurator.
Method <code class="code">public List<Class<? extends Encoder>> getEncoders()</code> defines the encoders
used by the endpoint. The decoders and user properties map are defined in similar fashion.
</p><p>
If the endpoint class which is about to be deployed is an annotated endpoint, note that the endpoint configuration
will be taken from configuration object, not from the annotation on the endpoint class.
</p><div class="example"><a name="d0e822"></a><p class="title"><b>Example 5.1. Configuration for EchoEndpoint Deployment</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">public class EchoEndpointConfig implements ServerEndpointConfig{
private final Map<String, Object> userProperties = new HashMap<String, Object>();
@Override
public Class<?> getEndpointClass() {
return EchoEndpoint.class;
}
@Override
public String getPath() {
return "/echo";
}
@Override
public List<String> getSubprotocols() {
return Arrays.asList("echo1","echo2");
}
@Override
public List<Extension> getExtensions() {
return null;
}
@Override
public Configurator getConfigurator() {
return null;
}
@Override
public List<Class<? extends Encoder>> getEncoders() {
return Arrays.asList(SampleEncoder.class);
}
@Override
public List<Class<? extends Decoder>> getDecoders() {
return Arrays.asList(SampleDecoder.class);
}
@Override
public Map<String, Object> getUserProperties() {
return userProperties;
}
}</pre></div></div><br class="example-break"><p>
To make the development easy the <span class="emphasis"><em>jakarta.websocket.server.ServerEndpointConfig</em></span> provides a builder to construct
the configuration object:
</p><div class="example"><a name="d0e832"></a><p class="title"><b>Example 5.2. ServerEndpointConfigu built using Builder</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">ServerEndpointConfig config = ServerEndpointConfig.Builder.create(EchoEndpoint.class,"/echo").
decoders(Arrays.<Class<? extends Decoder>>asList(JsonDecoder.class)).
encoders(Arrays.<Class< extends Encoder>>asList(JsonEncoder.class)).build();</pre></div></div><p><br class="example-break">
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e838"></a>5.2. <code class="code">jakarta.websocket.ClientEndpointConfig</code></h2></div></div></div><p>
The <code class="code">jakarta.websocket.ClientEndpointConfig</code> is used when deploying the programmatic client endpoint
via registering the programmatic endpoint at the <code class="code">WebSocketContainer</code> instance. Some of
the configuration methods come from the <code class="code">EndpointConfig</code>class, which is extended by both
<code class="code">jakarta.websocket.server.ServerEndpointConfig</code> and <code class="code">jakarta.websocket.ClientEndpointConfig</code>. Then there are methods
for configuring the preferred subprotocols the client endpoint wants to use and supported extensions. It is
also possible to use the ClientEndpointConfig.Configurator in order to be able to affect the endpoint behaviour
before and after request.
</p><p>
Similarly to the ServerEndpointConfig, there is a Builder provided to construct the configuration easily:
</p><div class="example"><a name="d0e861"></a><p class="title"><b>Example 5.3. ClientEndpointConfig built using Builder</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">ClientEndpointConfig.Builder.create().
decoders(Arrays.<Class<? extends Decoder>>asList(JsonDecoder.class)).
encoders(Arrays.<Class<? extends Encoder>>asList(JsonEncoder.class)).
preferredSubprotocols(Arrays.asList("echo1", "echo2")).build();</pre></div></div><br class="example-break"></div></div><div lang="en" class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="lifecycle"></a>Chapter 6. Endpoint Lifecycle, Sessions, Sending Messages</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#d0e870">6.1. Endpoint Lifecycle</a></span></dt><dt><span class="section"><a href="#d0e890">6.2. <code class="code">jakarta.websocket.Session</code></a></span></dt><dt><span class="section"><a href="#d0e975">6.3. Sending Messages</a></span></dt><dt><span class="section"><a href="#d0e1007">6.4. RemoteEndpoint</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1021">6.4.1. <code class="code">jakarta.websocket.RemoteEndpoint.Basic</code></a></span></dt><dt><span class="section"><a href="#d0e1045">6.4.2. <code class="code">jakarta.websocket.RemoteEndpoint.Async</code></a></span></dt></dl></dd></dl></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e870"></a>6.1. Endpoint Lifecycle</h2></div></div></div><p>
As mentioned before, the endpoint in Java API for WebSocket is represented either by instance of <code class="code">jakarta.websocket.Endpoint</code>,
or by class annotated with either <code class="code">jakarta.websocket.server.ServerEndpoint</code> or
<code class="code">jakarta.websocket.ClientEndpoint</code>. Unless otherwise defined by developer provided configurator
(defined in instance of <code class="code">jakarta.websocket.server.ServerEndpointConfig</code> or
<code class="code">jakarta.websocket.ClientEndpointConfig</code>, Tyrus uses one endpoint instance per VM per connected
peer. Therefore one endpoint instance typically handles connections from one peer.
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e890"></a>6.2. <code class="code">jakarta.websocket.Session</code></h2></div></div></div><p>
The sequence of interactions between an endpoint instance and remote peer is in Java API for WebSocket modelled by
<code class="code">jakarta.websocket.Session</code> instance. This interaction starts by mandatory open notification,
continues by 0 - n websocket messages and is finished by mandatory closing notification.
</p><p>
The <code class="code">jakarta.websocket.Session</code> instance is passed by Tyrus to the user in the following methods
for programmatic endpoints:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: opencircle; "><li class="listitem" style="list-style-type: circle"><p>
<code class="code">public void onOpen(Session session, EndpointConfig config)</code>
</p></li><li class="listitem" style="list-style-type: circle"><p>
<code class="code">public void onClose(Session session, CloseReason closeReason)</code>
</p></li><li class="listitem" style="list-style-type: circle"><p>
<code class="code">public void onError(Session session, Throwable thr)</code>
</p></li></ul></div><p>
</p><p>
The <code class="code">jakarta.websocket.Session</code> instance is passed by Tyrus to the user in the methods
annotated by following annotations for annotated endpoints:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: opencircle; "><li class="listitem" style="list-style-type: circle"><p>
method annotated with <code class="code">jakarta.websocket.OnOpen</code>
</p></li><li class="listitem" style="list-style-type: circle"><p>
method annotated with <code class="code">jakarta.websocket.OnMessage</code>
</p></li><li class="listitem" style="list-style-type: circle"><p>
method annotated with <code class="code">jakarta.websocket.OnClose</code>
</p></li><li class="listitem" style="list-style-type: circle"><p>
method annotated with <code class="code">jakarta.websocket.OnError</code>
</p></li></ul></div><p>
In each of the methods annotated with the preceeding annotations the user may use parameter of type
<code class="code">jakarta.websocket.Session</code>. In the following example the developer wants to send a message in
the method annotated with <code class="code">jakarta.websocket.OnOpen</code>. As we will demonstrate later, the developer
needs the session instance to do so. According to Java API for WebSocket Session is one of the allowed parameters in
methods annotated with <code class="code">jakarta.websocket.OnOpen</code>. Once the annotated method gets called,
Tyrus passes in the correct instance of <code class="code">jakarta.websocket.Session</code>.
</p><p>
</p><div class="example"><a name="lifecycle-echo-sample"></a><p class="title"><b>Example 6.1. Lifecycle echo sample</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">@ServerEndpoint("/echo")
public class EchoEndpoint {
@OnOpen
public void onOpen(Session session) throws IOException {
session.getBasicRemote().sendText("onOpen");
}
@OnMessage
public String echo(String message) {
return message;
}
@OnError
public void onError(Throwable t) {
t.printStackTrace();
}
}</pre></div></div><p><br class="example-break">
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e975"></a>6.3. Sending Messages</h2></div></div></div><p>
Generally there are two ways how to send message to the peer endpoint. First one is usable for annotated
endpoints only. The user may send the message by returning the message content from the method annotated
with <code class="code">jakarta.websocket.OnMessage</code>. In the following example the message m is sent back to the
remote endpoint.
</p><p>
</p><div class="example"><a name="lifecycle-onmessage-sample"></a><p class="title"><b>Example 6.2. Sending message in @OnMessage</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">@OnMessage
public String echo(String m) {
return m;
}</pre></div></div><p><br class="example-break">
</p><p>
The other option how to send a message is to obtain the <code class="code">jakarta.websocket.RemoteEndpoint</code> instance
via the <code class="code">jakarta.websocket.Session</code> instance. See the following example:
</p><p>
</p><div class="example"><a name="lifecycle-remote-endpoint-sample"></a><p class="title"><b>Example 6.3. Sending message via RemoteEndpoint.Basic instance</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">@OnMessage
public void echo(String message, Session session) {
session.getBasicRemote().sendText(message);
}</pre></div></div><p><br class="example-break">
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e1007"></a>6.4. RemoteEndpoint</h2></div></div></div><p>
The interface <code class="code">jakarta.websocket.RemoteEndpoint</code>, part of Java API for WebSocket, is designed to represent the
other end of the communication (related to the endpoint), so the developer uses it to send the message.
There are two basic interfaces the user may use - <code class="code">jakarta.websocket.RemoteEndpoint$Basic</code> and
<code class="code">jakarta.websocket.RemoteEndpoint$Async</code>.
</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1021"></a>6.4.1. <code class="code">jakarta.websocket.RemoteEndpoint.Basic</code></h3></div></div></div><p>
This representation of the peer of a web socket conversation is used to send synchronous messages. The point
of completion of the send is defined when all the supplied data has been written to the underlying connection.
The methods for sending messages on the
<code class="code">jakarta.websocket.RemoteEndpoint$Basic</code> block until this point of completion is reached, except for
<code class="code">jakarta.websocket.RemoteEndpoint$Basic#getSendStream()</code> and
<code class="code">jakarta.websocket.RemoteEndpoint$Basic#getSendWriter()</code> which present traditional blocking I/O streams
to write messages. See the example
<a class="link" href="#lifecycle-remote-endpoint-sample" title="Example 6.3. Sending message via RemoteEndpoint.Basic instance">"Sending message via RemoteEndpoint.Basic instance"</a>
to see how the whole text message is send. The following example demonstrates a method which sends the
partial text method to the peer:
</p><div class="example"><a name="lifecycle-remote-endpoint-partial-sample"></a><p class="title"><b>Example 6.4. Method for sending partial text message</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">public void sendPartialTextMessage(String message, Boolean isLast, Session session){
try {
session.getBasicRemote().sendText(message, isLast);
} catch (IOException e) {
e.printStackTrace();
}
}</pre></div></div><p><br class="example-break">
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1045"></a>6.4.2. <code class="code">jakarta.websocket.RemoteEndpoint.Async</code></h3></div></div></div><p>
This representation of the peer of a web socket conversation has the ability to send messages
asynchronously. The point of completion of the send is defined when all the supplied data has been
written to the underlying connection. The completion handlers for the asynchronous methods are always
called with a different thread from that which initiated the send.
</p><div class="example"><a name="lifecycle-remote-endpoint-async-future"></a><p class="title"><b>Example 6.5. Sending mesage the async way using Future</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">public void sendWholeAsyncMessage(String message, Session session){
Future<Void> future = session.getAsyncRemote().sendText(message);
}</pre></div></div><p><br class="example-break">
</p></div></div></div><div lang="en" class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="injection"></a>Chapter 7. Injection Support</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#d0e1075">7.1. <code class="code">jakarta.inject.Inject</code> sample</a></span></dt><dt><span class="section"><a href="#d0e1102">7.2. EJB sample</a></span></dt></dl></div><p>
As required in Java API for WebSocket, Tyrus supports full field, method and constructor injection using <code class="code">jakarta.inject.Inject</code>
into all websocket endpoint classes as well as the use of the interceptors on these classes.
Except this, Tyrus also supports some of the EJB annotations. Currently <code class="code">jakarta.ejb.Stateful</code>,
<code class="code">jakarta.ejb.Singleton</code> and <code class="code">jakarta.ejb.Stateless</code> annotations are supported.
</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e1075"></a>7.1. <code class="code">jakarta.inject.Inject</code> sample</h2></div></div></div><p>
The following example presents how to inject a bean to the <code class="code">jakarta.websocket.server.ServerEndpoint</code>
annotated class using <code class="code">jakarta.inject.Inject</code>. Class <code class="code">InjectedSimpleBean</code> gets injected
into class <code class="code">SimpleEndpoint</code> on line 15.
</p><div class="example"><a name="cdi-simple-bean"></a><p class="title"><b>Example 7.1. Injecting bean into <code class="code">jakarta.websocket.server.ServerEndpoint</code></b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">public class InjectedSimpleBean {
private static final String TEXT = " (from your server)";
public String getText() {
return TEXT;
}
}
@ServerEndpoint(value = "/simple")
public class SimpleEndpoint {
private boolean postConstructCalled = false;
@Inject
InjectedSimpleBean bean;
@OnMessage
public String echo(String message) {
return String.format("%s%s", message, bean.getText());
}
}</pre></div></div><p><br class="example-break">
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e1102"></a>7.2. EJB sample</h2></div></div></div><p>
The following sample presents how to turn <code class="code">jakarta.websocket.server.ServerEndpoint</code> annotated class
into <code class="code">jakarta.ejb.Singleton</code> and use interceptor on it.
</p><div class="example"><a name="cdi-singleton-bean"></a><p class="title"><b>Example 7.2. Echo sample server endpoint.</b></p><div class="example-contents"><pre class="
 toolbar: false;
 brush: java;
 ">@ServerEndpoint(value = "/singleton")
@Singleton
@Interceptors(LoggingInterceptor.class)
public class SingletonEndpoint {
int counter = 0;
public static boolean interceptorCalled = false;
@OnMessage
public String echo(String message) {
return interceptorCalled ? String.format("%s%s", message, counter++) : "LoggingInterceptor not called.";
}
}
public class LoggingInterceptor {
@AroundInvoke
public Object manageTransaction(InvocationContext ctx) throws Exception {
SingletonEndpoint.interceptorCalled = true;
Logger.getLogger(getClass().getName()).info("LOGGING.");
return ctx.proceed();
}
}
</pre></div></div><p><br class="example-break">
</p></div></div><div lang="en" class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="tyrus-proprietary-config"></a>Chapter 8. Tyrus proprietary configuration</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="#d0e1128">8.1. Client-side SSL configuration</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1149">8.1.1. Host verification</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1171">8.2. Asynchronous connectToServer methods</a></span></dt><dt><span class="section"><a href="#d0e1184">8.3. Optimized broadcast</a></span></dt><dt><span class="section"><a href="#d0e1197">8.4. Incoming buffer size</a></span></dt><dt><span class="section"><a href="#d0e1215">8.5. Shared client container</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1237">8.5.1. Custom masking key generator</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1258">8.6. WebSocket Extensions</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1283">8.6.1. ExtendedExtension sample</a></span></dt><dt><span class="section"><a href="#d0e1304">8.6.2. Per Message Deflate Extension</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1311">8.7. Client reconnect</a></span></dt><dt><span class="section"><a href="#d0e1323">8.8. Client behind proxy</a></span></dt><dt><span class="section"><a href="#d0e1331">8.9. JDK 7 client</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1353">8.9.1. SSL configuration</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1373">8.10. Tracing support</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1381">8.10.1. Configuration</a></span></dt><dt><span class="section"><a href="#d0e1447">8.10.2. Tracing Examples</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1475">8.11. Client handshake request and response logging</a></span></dt><dt><span class="section"><a href="#d0e1483">8.12. JMX Monitoring</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1557">8.12.1. Configuration</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1574">8.13. Maximal number of open sessions on server-side</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1593">8.13.1. Maximal number of open sessions per application</a></span></dt><dt><span class="section"><a href="#d0e1615">8.13.2. Maximal number of open sessions per remote address</a></span></dt><dt><span class="section"><a href="#d0e1643">8.13.3. Maximal number of open sessions per endpoint</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1658">8.14. Client HTTP Authentication</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1683">8.14.1. Credentials</a></span></dt><dt><span class="section"><a href="#d0e1691">8.14.2. Auth Configuration</a></span></dt><dt><span class="section"><a href="#d0e1709">8.14.3. User defined authenticator</a></span></dt><dt><span class="section"><a href="#d0e1736">8.14.4. Examples</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1774">8.15. Client HTTP Redirect</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1791">8.15.1. Supported HTTP response codes</a></span></dt><dt><span class="section"><a href="#d0e1816">8.15.2. Configuration</a></span></dt><dt><span class="section"><a href="#d0e1848">8.15.3. Exception handling</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e1885">8.16. Client support for HTTP status 503 - Service Unavailable with Retry-After header</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1906">8.16.1. Configuration</a></span></dt></dl></dd></dl></div><p>Following settings do have influence on Tyrus behaviour and are <span class="emphasis"><em>NOT</em></span> part of WebSocket
specification. If you are using following configurable options, your application might not be easily transferable to
other WebSocket API implementation.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e1128"></a>8.1. Client-side SSL configuration</h2></div></div></div><p>When accessing "wss" URLs, Tyrus client will pick up whatever keystore and truststore is actually set for current JVM instance, but
that might not be always convenient. WebSocket API does not have this feature (yet, see <a class="link" href="https://java.net/jira/browse/WEBSOCKET_SPEC-210" target="_top">WEBSOCKET_SPEC-210</a>),
so Tyrus exposed two SSL configuration classes <a class="link" href="https://grizzly.java.net/docs/2.3/apidocs/org/glassfish/grizzly/ssl/SSLEngineConfigurator.html" target="_top">SSLEngineConfigurator</a>
and <a class="link" href="https://tyrus.java.net/apidocs/2.0.5/org/glassfish/tyrus/client/SslEngineConfigurator.html" target="_top">SslEngineConfigurator</a>
, which can be used for specifying all SSL parameters to be used with current client instance. The former configuration class
belongs to Grizzly configuration API and therefore works only with Grizzly client. The latter configuration class
works with both Grizzly and JDK client and offers some extensions over the Grizzly SSLEngineConfigurator
allowing more control of host verification during the SSL handshake. For more details
please refer to the following subsection dealing with host verification.
Additionally, WebSocket API does not have anything like a client, only WebSocketContainer and it does not have any properties, so you need to use Tyrus specific class -
<a class="link" href="https://tyrus.java.net/apidocs/2.0.5/org/glassfish/tyrus/client/ClientManager.html" target="_top">ClientManager</a>.</p><pre class="
 toolbar: false;
 brush: java;
 ">final ClientManager client = ClientManager.createClient();
System.getProperties().put("javax.net.debug", "all");
System.getProperties().put(SSLContextConfigurator.KEY_STORE_FILE, "...");
System.getProperties().put(SSLContextConfigurator.TRUST_STORE_FILE, "...");
System.getProperties().put(SSLContextConfigurator.KEY_STORE_PASSWORD, "...");
System.getProperties().put(SSLContextConfigurator.TRUST_STORE_PASSWORD, "...");
final SSLContextConfigurator defaultConfig = new SSLContextConfigurator();
defaultConfig.retrieve(System.getProperties());
// or setup SSLContextConfigurator using its API.
SSLEngineConfigurator sslEngineConfigurator =
new SSLEngineConfigurator(defaultConfig, true, false, false);
client.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR,
sslEngineConfigurator);
client.connectToServer(... , ClientEndpointConfig.Builder.create().build(),
new URI("wss://localhost:8181/sample-echo/echo"));
}</pre><p>
If there seems to be a problem with Tyrus SSL connection, it is strongly recommended to use -Djavax.net.debug=all
system property as it provides invaluable information for troubleshooting.
</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1149"></a>8.1.1. Host verification</h3></div></div></div><p>
One of the key steps when establishing SSL connections is verifying that the host on the certificate
sent by the server matches the host Tyrus client tries to connect to and thus preventing a possibility of
a man-in-the-middle attack. Host verification is turned on by default in Tyrus, which means that Tyrus
will automatically check that the host provided in the URI in
</p><pre class="
 toolbar: false;
 brush: java;
 ">client.connectToServer(... , new URI("wss://target-server:8181/application/endpoint"));
</pre><p> matches exactly the host the certificate has been issued for. Exact match is
the key word in the previous sentence as host can be either hostname or IP address and those two cannot be used
interchangeably. For instance when a certificate has been issued for "localhost", establishing an SSL connection
to "wss://127.0.0.1:8181/application/endpoint" will fail as the host does not match the one in the certificate.
</p><p>
The default host verification can be too restrictive for some cases and therefore Tyrus provides users
with means to to either disable the host verification (highly unrecommended in production) or to implement
their own host verifier. Providing custom host verifier will disable the default one. It is also important
to note that Grizzly specific
<a class="link" href="https://grizzly.java.net/docs/2.3/apidocs/org/glassfish/grizzly/ssl/SSLEngineConfigurator.html" target="_top">SSLEngineConfigurator</a>
does not provide these options and for modifying the default host name verification policy
<a class="link" href="https://tyrus.java.net/apidocs/2.0.5/org/glassfish/tyrus/client/SslEngineConfigurator.html" target="_top">SslEngineConfigurator</a>
must be used instead. The following sample shows how to disable host name verification:
</p><pre class="
 toolbar: false;
 brush: java;
 ">SslEngineConfigurator sslEngineConfigurator = new SslEngineConfigurator(new SslContextConfigurator());
sslEngineConfigurator.setHostVerificationEnabled(false)
client.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
</pre><p>
The following sample shows how to register a custom host verifier:
</p><pre class="
 toolbar: false;
 brush: java;
 ">SslEngineConfigurator sslEngineConfigurator = new SslEngineConfigurator(new SslContextConfigurator());
sslEngineConfigurator.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String host, SSLSession sslSession) {
Certificate certificate = sslSession.getPeerCertificates()[0];