< prev index next >
1 /*
2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package java.net.http;
26
27 import java.io.IOException;
28 import java.net.ProtocolException;
29 import java.net.URI;
30 import java.nio.ByteBuffer;
31 import java.util.Map;
32 import java.util.Objects;
33 import java.util.Optional;
34 import java.util.concurrent.CompletableFuture;
35 import java.util.concurrent.CompletionStage;
36 import java.util.concurrent.Future;
37 import java.util.concurrent.TimeUnit;
38 import java.util.stream.Stream;
39
40 /**
41 * A WebSocket client conforming to RFC 6455.
42 *
43 * <p> A {@code WebSocket} provides full-duplex communication over a TCP
44 * connection.
45 *
46 * <p> To create a {@code WebSocket} use a {@linkplain #newBuilder(URI, Listener)
47 * builder}. Once a {@code WebSocket} is obtained, it's ready to send and
48 * receive messages. When the {@code WebSocket} is no longer
49 * needed it must be closed: a Close message must both be {@linkplain
50 * #sendClose() sent} and {@linkplain Listener#onClose(WebSocket, Optional,
51 * String) received}. Or to close abruptly, {@link #abort()} is called. Once
52 * closed it remains closed, cannot be reopened.
53 *
54 * <p> Messages of type {@code X} are sent through the {@code WebSocket.sendX}
55 * methods and received through {@link WebSocket.Listener}{@code .onX} methods
56 * asynchronously. Each of the methods begins the operation and returns a {@link
57 * CompletionStage} which completes when the operation has completed.
58 *
59 * <p> Messages are received only if {@linkplain #request(long) requested}.
60 *
61 * <p> One outstanding send operation is permitted: if another send operation is
62 * initiated before the previous one has completed, an {@link
63 * IllegalStateException IllegalStateException} will be thrown. When sending, a
64 * message should not be modified until the returned {@code CompletableFuture}
65 * completes (either normally or exceptionally).
66 *
67 * <p> Messages can be sent and received as a whole or in parts. A whole message
68 * is a sequence of one or more messages in which the last message is marked
69 * when it is sent or received.
70 *
71 * <p> If the message is contained in a {@link ByteBuffer}, bytes are considered
72 * arranged from the {@code buffer}'s {@link ByteBuffer#position() position} to
73 * the {@code buffer}'s {@link ByteBuffer#limit() limit}.
74 *
75 * <p> All message exchange is run by the threads belonging to the {@linkplain
76 * HttpClient#executorService() executor service} of {@code WebSocket}'s {@link
77 * HttpClient}.
78 *
79 * <p> Unless otherwise noted, passing a {@code null} argument to a constructor
80 * or method of this type will cause a {@link NullPointerException
81 * NullPointerException} to be thrown.
82 *
83 * @since 9
84 */
85 public interface WebSocket {
86
87 /**
88 * Creates a builder of {@code WebSocket}s connected to the given URI and
89 * receiving events with the given {@code Listener}.
90 *
91 * <p> Equivalent to:
92 * <pre>{@code
93 * WebSocket.newBuilder(uri, HttpClient.getDefault())
94 * }</pre>
95 *
96 * @param uri
97 * the WebSocket URI as defined in the WebSocket Protocol
98 * (with "ws" or "wss" scheme)
99 *
100 * @param listener
101 * the listener
102 *
103 * @throws IllegalArgumentException
104 * if the {@code uri} is not a WebSocket URI
105 * @throws SecurityException
106 * if running under a security manager and the caller does
107 * not have permission to access the
108 * {@linkplain HttpClient#getDefault() default HttpClient}
109 *
110 * @return a builder
111 */
112 static Builder newBuilder(URI uri, Listener listener) {
113 return newBuilder(uri, HttpClient.getDefault(), listener);
114 }
115
116 /**
117 * Creates a builder of {@code WebSocket}s connected to the given URI and
118 * receiving events with the given {@code Listener}.
119 *
120 * <p> Providing a custom {@code client} allows for finer control over the
121 * opening handshake.
122 *
123 * <p> <b>Example</b>
124 * <pre>{@code
125 * HttpClient client = HttpClient.create()
126 * .proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
127 * .build();
128 * ...
129 * WebSocket.newBuilder(URI.create("ws://websocket.example.com"), client, listener)...
130 * }</pre>
131 *
132 * @param uri
133 * the WebSocket URI as defined in the WebSocket Protocol
134 * (with "ws" or "wss" scheme)
135 *
136 * @param client
137 * the HttpClient
138 * @param listener
139 * the listener
140 *
141 * @throws IllegalArgumentException
142 * if the uri is not a WebSocket URI
143 *
144 * @return a builder
145 */
146 static Builder newBuilder(URI uri, HttpClient client, Listener listener) {
147 return new WebSocketBuilderImpl(uri, client, listener);
148 }
149
150 /**
151 * A builder for creating {@code WebSocket} instances.
152 *
153 * <p> To build a {@code WebSocket}, instantiate a builder, configure it
154 * as required by calling intermediate methods (the ones that return the
155 * builder itself), then finally call {@link #buildAsync()} to get a {@link
156 * CompletableFuture} with resulting {@code WebSocket}.
157 *
158 * <p> If an intermediate method has not been called, an appropriate
159 * default value (or behavior) will be used. Unless otherwise noted, a
160 * repeated call to an intermediate method overwrites the previous value (or
161 * overrides the previous behaviour), if no exception is thrown.
162 *
163 * <p> Instances of {@code Builder} may not be safe for use by multiple
164 * threads.
165 *
166 * @since 9
167 */
168 interface Builder {
169
170 /**
171 * Adds the given name-value pair to the list of additional headers for
172 * the opening handshake.
173 *
174 * <p> Headers defined in WebSocket Protocol are not allowed to be added.
175 *
176 * @param name
177 * the header name
178 * @param value
179 * the header value
180 *
181 * @return this builder
182 *
183 * @throws IllegalArgumentException
184 * if the {@code name} is a WebSocket defined header name
185 */
186 Builder header(String name, String value);
187
188 /**
189 * Includes a request for the given subprotocols during the opening
190 * handshake.
191 *
192 * <p> Among the requested subprotocols at most one will be chosen by
193 * the server. When the {@code WebSocket} is connected, the subprotocol
194 * in use is available from {@link WebSocket#getSubprotocol}.
195 * Subprotocols may be specified in the order of preference.
196 *
197 * <p> Each of the given subprotocols must conform to the relevant
198 * rules defined in the WebSocket Protocol.
199 *
200 * @param mostPreferred
201 * the most preferred subprotocol
202 * @param lesserPreferred
203 * the lesser preferred subprotocols, with the least preferred
204 * at the end
205 *
206 * @return this builder
207 *
208 * @throws IllegalArgumentException
209 * if any of the WebSocket Protocol rules relevant to
210 * subprotocols are violated
211 */
212 Builder subprotocols(String mostPreferred, String... lesserPreferred);
213
214 /**
215 * Sets a timeout for the opening handshake.
216 *
217 * <p> If the opening handshake is not finished within the specified
218 * timeout then {@link #buildAsync()} completes exceptionally with a
219 * {@code HttpTimeoutException}.
220 *
221 * <p> If the timeout is not specified then it's deemed infinite.
222 *
223 * @param timeout
224 * the maximum time to wait
225 * @param unit
226 * the time unit of the timeout argument
227 *
228 * @return this builder
229 *
230 * @throws IllegalArgumentException
231 * if the {@code timeout} is negative
232 */
233 Builder connectTimeout(long timeout, TimeUnit unit);
234
235 /**
236 * Builds a {@code WebSocket}.
237 *
238 * <p> Returns immediately with a {@code CompletableFuture<WebSocket>}
239 * which completes with the {@code WebSocket} when it is connected, or
240 * completes exceptionally if an error occurs.
241 *
242 * <p> {@code CompletableFuture} may complete exceptionally with the
243 * following errors:
244 * <ul>
245 * <li> {@link IOException}
246 * if an I/O error occurs
247 * <li> {@link InterruptedException}
248 * if the operation was interrupted
249 * <li> {@link SecurityException}
250 * if a security manager is set, and the caller does not
251 * have a {@link java.net.URLPermission} for the WebSocket URI
252 * <li> {@link WebSocketHandshakeException}
253 * if the opening handshake fails
254 * </ul>
255 *
256 * @return a {@code CompletableFuture} of {@code WebSocket}
257 */
258 CompletableFuture<WebSocket> buildAsync();
259 }
260
261 /**
262 * A listener for events and messages on a {@code WebSocket}.
263 *
264 * <p> Each method below corresponds to a type of event.
265 * <ul>
266 * <li> {@link #onOpen onOpen} <br>
267 * This method is always the first to be invoked.
268 * <li> {@link #onText(WebSocket, WebSocket.Text, WebSocket.MessagePart)
269 * onText}, {@link #onBinary(WebSocket, ByteBuffer, WebSocket.MessagePart)
270 * onBinary}, {@link #onPing(WebSocket, ByteBuffer) onPing} and {@link
271 * #onPong(WebSocket, ByteBuffer) onPong} <br>
272 * These methods are invoked zero or more times after {@code onOpen}.
273 * <li> {@link #onClose(WebSocket, Optional, String) onClose}, {@link
274 * #onError(WebSocket, Throwable) onError} <br>
275 * Only one of these methods is invoked, and that method is invoked last and
276 * at most once.
277 * </ul>
278 *
279 * <pre><code>
280 * onOpen (onText|onBinary|onPing|onPong)* (onClose|onError)?
281 * </code></pre>
282 *
283 * <p> Messages received by the {@code Listener} conform to the WebSocket
284 * Protocol, otherwise {@code onError} with a {@link ProtocolException} is
285 * invoked.
286 *
287 * <p> If a whole message is received, then the corresponding method
288 * ({@code onText} or {@code onBinary}) will be invoked with {@link
289 * WebSocket.MessagePart#WHOLE WHOLE} marker. Otherwise the method will be
290 * invoked with {@link WebSocket.MessagePart#FIRST FIRST}, zero or more
291 * times with {@link WebSocket.MessagePart#FIRST PART} and, finally, with
292 * {@link WebSocket.MessagePart#LAST LAST} markers.
293 *
294 * <pre><code>
295 * WHOLE|(FIRST PART* LAST)
296 * </code></pre>
297 *
298 * <p> All methods are invoked in a sequential (and
299 * <a href="../../../java/util/concurrent/package-summary.html#MemoryVisibility">
300 * happens-before</a>) order, one after another, possibly by different
301 * threads. If any of the methods above throws an exception, {@code onError}
302 * is then invoked with that exception. Exceptions thrown from {@code
303 * onError} or {@code onClose} are ignored.
304 *
305 * <p> When the method returns, the message is deemed received. After this
306 * another messages may be received.
307 *
308 * <p> These invocations begin asynchronous processing which might not end
309 * with the invocation. To provide coordination, methods of {@code
310 * Listener} return a {@link CompletionStage CompletionStage}. The {@code
311 * CompletionStage} signals the {@code WebSocket} that the
312 * processing of a message has ended. For
313 * convenience, methods may return {@code null}, which means
314 * the same as returning an already completed {@code CompletionStage}. If
315 * the returned {@code CompletionStage} completes exceptionally, then {@link
316 * #onError(WebSocket, Throwable) onError} will be invoked with the
317 * exception.
318 *
319 * <p> Control of the message passes to the {@code Listener} with the
320 * invocation of the method. Control of the message returns to the {@code
321 * WebSocket} at the earliest of, either returning {@code null} from the
322 * method, or the completion of the {@code CompletionStage} returned from
323 * the method. The {@code WebSocket} does not access the message while it's
324 * not in its control. The {@code Listener} must not access the message
325 * after its control has been returned to the {@code WebSocket}.
326 *
327 * <p> It is the responsibility of the listener to make additional
328 * {@linkplain WebSocket#request(long) message requests}, when ready, so
329 * that messages are received eventually.
330 *
331 * <p> Methods above are never invoked with {@code null}s as their
332 * arguments.
333 *
334 * @since 9
335 */
336 interface Listener {
337
338 /**
339 * Notifies the {@code Listener} that it is connected to the provided
340 * {@code WebSocket}.
341 *
342 * <p> The {@code onOpen} method does not correspond to any message
343 * from the WebSocket Protocol. It is a synthetic event. It is the first
344 * {@code Listener}'s method to be invoked. No other {@code Listener}'s
345 * methods are invoked before this one. The method is usually used to
346 * make an initial {@linkplain WebSocket#request(long) request} for
347 * messages.
348 *
349 * <p> If an exception is thrown from this method then {@link
350 * #onError(WebSocket, Throwable) onError} will be invoked with the
351 * exception.
352 *
353 * @implSpec The default implementation {@linkplain WebSocket#request(long)
354 * requests one message}.
355 *
356 * @param webSocket
357 * the WebSocket
358 */
359 default void onOpen(WebSocket webSocket) { webSocket.request(1); }
360
361 /**
362 * Receives a Text message.
363 *
364 * <p> The {@code onText} method is invoked zero or more times between
365 * {@code onOpen} and ({@code onClose} or {@code onError}).
366 *
367 * <p> This message may be a partial UTF-16 sequence. However, the
368 * concatenation of all messages through the last will be a whole UTF-16
369 * sequence.
370 *
371 * <p> If an exception is thrown from this method or the returned {@code
372 * CompletionStage} completes exceptionally, then {@link
373 * #onError(WebSocket, Throwable) onError} will be invoked with the
374 * exception.
375 *
376 * @implSpec The default implementation {@linkplain WebSocket#request(long)
377 * requests one more message}.
378 *
379 * @param webSocket
380 * the WebSocket
381 * @param message
382 * the message
383 * @param part
384 * the part
385 *
386 * @return a CompletionStage that completes when the message processing
387 * is done; or {@code null} if already done
388 */
389 default CompletionStage<?> onText(WebSocket webSocket,
390 Text message,
391 MessagePart part) {
392 webSocket.request(1);
393 return null;
394 }
395
396 /**
397 * Receives a Binary message.
398 *
399 * <p> The {@code onBinary} method is invoked zero or more times
400 * between {@code onOpen} and ({@code onClose} or {@code onError}).
401 *
402 * <p> If an exception is thrown from this method or the returned {@code
403 * CompletionStage} completes exceptionally, then {@link
404 * #onError(WebSocket, Throwable) onError} will be invoked with this
405 * exception.
406 *
407 * @implSpec The default implementation {@linkplain WebSocket#request(long)
408 * requests one more message}.
409 *
410 * @param webSocket
411 * the WebSocket
412 * @param message
413 * the message
414 * @param part
415 * the part
416 *
417 * @return a CompletionStage that completes when the message processing
418 * is done; or {@code null} if already done
419 */
420 default CompletionStage<?> onBinary(WebSocket webSocket,
421 ByteBuffer message,
422 MessagePart part) {
423 webSocket.request(1);
424 return null;
425 }
426
427 /**
428 * Receives a Ping message.
429 *
430 * <p> A Ping message may be sent or received by either client or
431 * server. It may serve either as a keepalive or as a means to verify
432 * that the remote endpoint is still responsive.
433 *
434 * <p> The message will consist of not more than {@code 125} bytes:
435 * {@code message.remaining() <= 125}.
436 *
437 * <p> The {@code onPing} is invoked zero or more times in between
438 * {@code onOpen} and ({@code onClose} or {@code onError}).
439 *
440 * <p> If an exception is thrown from this method or the returned {@code
441 * CompletionStage} completes exceptionally, then {@link
442 * #onError(WebSocket, Throwable) onError} will be invoked with this
443 * exception.
444 *
445 * @implNote
446 *
447 * <p> Replies with a Pong message if the previous Pong has been sent
448 * and requests one more message when this send has completed. Otherwise
449 * requests one more message.
450 *
451 * <p> The purpose of this is to not allow uncontrolled build-up of the
452 * outgoing queue in case where rate with which Pings are received is
453 * greater than rate with which Pongs are sent.
454 *
455 * @param webSocket
456 * the WebSocket
457 * @param message
458 * the message
459 *
460 * @return a CompletionStage that completes when the message processing
461 * is done; or {@code null} if already done
462 */
463 default CompletionStage<?> onPing(WebSocket webSocket,
464 ByteBuffer message) {
465 WebSocketImpl ws = (WebSocketImpl) webSocket;
466 CompletionStage<?> f = ws.sendPongIfNoOutstanding(message);
467 f.thenRun(() -> webSocket.request(1));
468 return f;
469 }
470
471 /**
472 * Receives a Pong message.
473 *
474 * <p> A Pong message may be unsolicited or may be received in response
475 * to a previously sent Ping. In the latter case, the contents of the
476 * Pong is identical to the originating Ping.
477 *
478 * <p> The message will consist of not more than {@code 125} bytes:
479 * {@code message.remaining() <= 125}.
480 *
481 * <p> The {@code onPong} method is invoked zero or more times in
482 * between {@code onOpen} and ({@code onClose} or {@code onError}).
483 *
484 * <p> If an exception is thrown from this method or the returned {@code
485 * CompletionStage} completes exceptionally, then {@link
486 * #onError(WebSocket, Throwable) onError} will be invoked with this
487 * exception.
488 *
489 * @implSpec The default implementation {@linkplain WebSocket#request(long)
490 * requests one more message}.
491 *
492 * @param webSocket
493 * the WebSocket
494 * @param message
495 * the message
496 *
497 * @return a CompletionStage that completes when the message processing
498 * is done; or {@code null} if already done
499 */
500 default CompletionStage<?> onPong(WebSocket webSocket,
501 ByteBuffer message) {
502 webSocket.request(1);
503 return null;
504 }
505
506 /**
507 * Receives a Close message.
508 *
509 * <p> Once a Close message is received, the server will not send any
510 * more messages.
511 *
512 * <p> A Close message may consist of a close code and a reason for
513 * closing. The reason will have a UTF-8 representation not longer than
514 * {@code 123} bytes. The reason may be useful for debugging or passing
515 * information relevant to the connection but is not necessarily human
516 * readable.
517 *
518 * <p> {@code onClose} is the last invocation on the {@code Listener}.
519 * It is invoked at most once, but after {@code onOpen}. If an exception
520 * is thrown from this method, it is ignored.
521 *
522 * @implSpec The default implementation does nothing.
523 *
524 * @param webSocket
525 * the WebSocket
526 * @param code
527 * an {@code Optional} describing the close code, or
528 * an empty {@code Optional} if the message doesn't contain it
529 * @param reason
530 * the reason of close; can be empty
531 */
532 default void onClose(WebSocket webSocket, Optional<CloseCode> code,
533 String reason) { }
534
535 /**
536 * Notifies an I/O or protocol error has occurred on the {@code
537 * WebSocket}.
538 *
539 * <p> The {@code onError} method does not correspond to any message
540 * from the WebSocket Protocol. It is a synthetic event. {@code onError}
541 * is the last invocation on the {@code Listener}. It is invoked at most
542 * once but after {@code onOpen}. If an exception is thrown from this
543 * method, it is ignored.
544 *
545 * <p> The WebSocket Protocol requires some errors occurs in the
546 * incoming destination must be fatal to the connection. In such cases
547 * the implementation takes care of closing the {@code WebSocket}. By
548 * the time {@code onError} is invoked, no more messages can be sent on
549 * this {@code WebSocket}.
550 *
551 * @apiNote Errors associated with send operations ({@link
552 * WebSocket#sendText(CharSequence, boolean) sendText}, {@link
553 * #sendBinary(ByteBuffer, boolean) sendBinary}, {@link
554 * #sendPing(ByteBuffer) sendPing}, {@link #sendPong(ByteBuffer)
555 * sendPong} and {@link #sendClose(CloseCode, CharSequence) sendClose})
556 * are reported to the {@code CompletionStage} operations return.
557 *
558 * @implSpec The default implementation does nothing.
559 *
560 * @param webSocket
561 * the WebSocket
562 * @param error
563 * the error
564 */
565 default void onError(WebSocket webSocket, Throwable error) { }
566 }
567
568 /**
569 * A marker used by {@link WebSocket.Listener} for partial message
570 * receiving.
571 *
572 * @since 9
573 */
574 enum MessagePart {
575
576 /**
577 * The first part of a message in a sequence.
578 */
579 FIRST,
580
581 /**
582 * A middle part of a message in a sequence.
583 */
584 PART,
585
586 /**
587 * The last part of a message in a sequence.
588 */
589 LAST,
590
591 /**
592 * A whole message. The message consists of a single part.
593 */
594 WHOLE;
595
596 /**
597 * Tells whether a part of a message received with this marker is the
598 * last part.
599 *
600 * @return {@code true} if LAST or WHOLE, {@code false} otherwise
601 */
602 public boolean isLast() { return this == LAST || this == WHOLE; }
603 }
604
605 /**
606 * Sends a Text message with bytes from the given {@code ByteBuffer}.
607 *
608 * <p> Returns immediately with a {@code CompletableFuture<Void>} which
609 * completes normally when the message has been sent, or completes
610 * exceptionally if an error occurs.
611 *
612 * <p> This message may be a partial UTF-8 sequence. However, the
613 * concatenation of all messages through the last must be a whole UTF-8
614 * sequence.
615 *
616 * <p> The {@code ByteBuffer} should not be modified until the returned
617 * {@code CompletableFuture} completes (either normally or exceptionally).
618 *
619 * <p> The returned {@code CompletableFuture} can complete exceptionally
620 * with:
621 * <ul>
622 * <li> {@link IOException}
623 * if an I/O error occurs during this operation; or the
624 * {@code WebSocket} closes while this operation is in progress;
625 * or the {@code message} is a malformed UTF-8 sequence
626 * </ul>
627 *
628 * @param message
629 * the message
630 * @param isLast
631 * {@code true} if this is the final part of the message,
632 * {@code false} otherwise
633 *
634 * @return a CompletableFuture of Void
635 *
636 * @throws IllegalStateException
637 * if the WebSocket is closed
638 * @throws IllegalStateException
639 * if a Close message has been sent already
640 * @throws IllegalStateException
641 * if there is an outstanding send operation
642 * @throws IllegalStateException
643 * if a previous Binary message
644 * was not sent with {@code isLast == true}
645 */
646 CompletableFuture<Void> sendText(ByteBuffer message, boolean isLast);
647
648 /**
649 * Sends a Text message with characters from the given {@code
650 * CharSequence}.
651 *
652 * <p> Returns immediately with a {@code CompletableFuture<Void>} which
653 * completes normally when the message has been sent, or completes
654 * exceptionally if an error occurs.
655 *
656 * <p> This message may be a partial UTF-16 sequence. However, the
657 * concatenation of all messages through the last must be a whole UTF-16
658 * sequence.
659 *
660 * <p> The {@code CharSequence} should not be modified until the returned
661 * {@code CompletableFuture} completes (either normally or exceptionally).
662 *
663 * <p> The returned {@code CompletableFuture} can complete exceptionally
664 * with:
665 * <ul>
666 * <li> {@link IOException}
667 * if an I/O error occurs during this operation; or the
668 * {@code WebSocket} closes while this operation is in progress;
669 * or the {@code message} is a malformed UTF-16 sequence
670 * </ul>
671 *
672 * @param message
673 * the message
674 * @param isLast
675 * {@code true} if this is the final part of the message
676 * {@code false} otherwise
677 *
678 * @return a CompletableFuture of Void
679 *
680 * @throws IllegalStateException
681 * if the WebSocket is closed
682 * @throws IllegalStateException
683 * if a Close message has been already sent
684 * @throws IllegalStateException
685 * if there is an outstanding send operation
686 * @throws IllegalStateException
687 * if a previous Binary message was not sent
688 * with {@code isLast == true}
689 */
690 CompletableFuture<Void> sendText(CharSequence message, boolean isLast);
691
692 /**
693 * Sends a whole Text message with characters from the given {@code
694 * CharSequence}.
695 *
696 * <p> This is a convenience method. For the general case, use {@link
697 * #sendText(CharSequence, boolean)}.
698 *
699 * <p> Returns immediately with a {@code CompletableFuture<Void>} which
700 * completes normally when the message has been sent, or completes
701 * exceptionally if an error occurs.
702 *
703 * <p> The {@code CharSequence} should not be modified until the returned
704 * {@code CompletableFuture} completes (either normally or exceptionally).
705 *
706 * <p> The returned {@code CompletableFuture} can complete exceptionally
707 * with:
708 * <ul>
709 * <li> {@link IOException}
710 * if an I/O error occurs during this operation; or the
711 * {@code WebSocket} closes while this operation is in progress;
712 * or the message is a malformed UTF-16 sequence
713 * </ul>
714 *
715 * @param message
716 * the message
717 *
718 * @return a CompletableFuture of Void
719 *
720 * @throws IllegalStateException
721 * if the WebSocket is closed
722 * @throws IllegalStateException
723 * if a Close message has been already sent
724 * @throws IllegalStateException
725 * if there is an outstanding send operation
726 * @throws IllegalStateException
727 * if a previous Binary message was not sent
728 * with {@code isLast == true}
729 */
730 default CompletableFuture<Void> sendText(CharSequence message) {
731 return sendText(message, true);
732 }
733
734 /**
735 * Sends a whole Text message with characters from {@code
736 * CharacterSequence}s provided by the given {@code Stream}.
737 *
738 * <p> This is a convenience method. For the general case use {@link
739 * #sendText(CharSequence, boolean)}.
740 *
741 * <p> Returns immediately with a {@code CompletableFuture<Void>} which
742 * completes normally when the message has been sent, or completes
743 * exceptionally if an error occurs.
744 *
745 * <p> Streamed character sequences should not be modified until the
746 * returned {@code CompletableFuture} completes (either normally or
747 * exceptionally).
748 *
749 * <p> The returned {@code CompletableFuture} can complete exceptionally
750 * with:
751 * <ul>
752 * <li> {@link IOException}
753 * if an I/O error occurs during this operation; or the
754 * {@code WebSocket} closes while this operation is in progress;
755 * or the message is a malformed UTF-16 sequence
756 * </ul>
757 *
758 * @param message
759 * the message
760 *
761 * @return a CompletableFuture of Void
762 *
763 * @throws IllegalStateException
764 * if the WebSocket is closed
765 * @throws IllegalStateException
766 * if a Close message has been already sent
767 * @throws IllegalStateException
768 * if there is an outstanding send operation
769 * @throws IllegalStateException
770 * if a previous Binary message was not sent
771 * with {@code isLast == true}
772 */
773 CompletableFuture<Void> sendText(Stream<? extends CharSequence> message);
774
775 /**
776 * Sends a Binary message with bytes from the given {@code ByteBuffer}.
777 *
778 * <p> Returns immediately with a {@code CompletableFuture<Void>} which
779 * completes normally when the message has been sent, or completes
780 * exceptionally if an error occurs.
781 *
782 * <p> The returned {@code CompletableFuture} can complete exceptionally
783 * with:
784 * <ul>
785 * <li> {@link IOException}
786 * if an I/O error occurs during this operation or the
787 * {@code WebSocket} closes while this operation is in progress
788 * </ul>
789 *
790 * @param message
791 * the message
792 * @param isLast
793 * {@code true} if this is the final part of the message,
794 * {@code false} otherwise
795 *
796 * @return a CompletableFuture of Void
797 *
798 * @throws IllegalStateException
799 * if the WebSocket is closed
800 * @throws IllegalStateException
801 * if a Close message has been already sent
802 * @throws IllegalStateException
803 * if there is an outstanding send operation
804 * @throws IllegalStateException
805 * if a previous Text message was not sent
806 * with {@code isLast == true}
807 */
808 CompletableFuture<Void> sendBinary(ByteBuffer message, boolean isLast);
809
810 /**
811 * Sends a Binary message with bytes from the given {@code byte[]}.
812 *
813 * <p> Returns immediately with a {@code CompletableFuture<Void>} which
814 * completes normally when the message has been sent, or completes
815 * exceptionally if an error occurs.
816 *
817 * <p> The returned {@code CompletableFuture} can complete exceptionally
818 * with:
819 * <ul>
820 * <li> {@link IOException}
821 * if an I/O error occurs during this operation or the
822 * {@code WebSocket} closes while this operation is in progress
823 * </ul>
824 *
825 * @implSpec This is equivalent to:
826 * <pre>{@code
827 * sendBinary(ByteBuffer.wrap(message), isLast)
828 * }</pre>
829 *
830 * @param message
831 * the message
832 * @param isLast
833 * {@code true} if this is the final part of the message,
834 * {@code false} otherwise
835 *
836 * @return a CompletableFuture of Void
837 *
838 * @throws IllegalStateException
839 * if the WebSocket is closed
840 * @throws IllegalStateException
841 * if a Close message has been already sent
842 * @throws IllegalStateException
843 * if there is an outstanding send operation
844 * @throws IllegalStateException
845 * if a previous Text message was not sent
846 * with {@code isLast == true}
847 */
848 default CompletableFuture<Void> sendBinary(byte[] message, boolean isLast) {
849 Objects.requireNonNull(message, "message");
850 return sendBinary(ByteBuffer.wrap(message), isLast);
851 }
852
853 /**
854 * Sends a Ping message.
855 *
856 * <p> Returns immediately with a {@code CompletableFuture<Void>} which
857 * completes normally when the message has been sent, or completes
858 * exceptionally if an error occurs.
859 *
860 * <p> A Ping message may be sent or received by either client or server.
861 * It may serve either as a keepalive or as a means to verify that the
862 * remote endpoint is still responsive.
863 *
864 * <p> The message must consist of not more than {@code 125} bytes: {@code
865 * message.remaining() <= 125}.
866 *
867 * <p> The returned {@code CompletableFuture} can complete exceptionally
868 * with:
869 * <ul>
870 * <li> {@link IOException}
871 * if an I/O error occurs during this operation or the
872 * {@code WebSocket} closes while this operation is in progress
873 * </ul>
874 *
875 * @param message
876 * the message
877 *
878 * @return a CompletableFuture of Void
879 *
880 * @throws IllegalStateException
881 * if the WebSocket is closed
882 * @throws IllegalStateException
883 * if a Close message has been already sent
884 * @throws IllegalStateException
885 * if there is an outstanding send operation
886 * @throws IllegalArgumentException
887 * if {@code message.remaining() > 125}
888 */
889 CompletableFuture<Void> sendPing(ByteBuffer message);
890
891 /**
892 * Sends a Pong message.
893 *
894 * <p> Returns immediately with a {@code CompletableFuture<Void>} which
895 * completes normally when the message has been sent, or completes
896 * exceptionally if an error occurs.
897 *
898 * <p> A Pong message may be unsolicited or may be sent in response to a
899 * previously received Ping. In latter case the contents of the Pong is
900 * identical to the originating Ping.
901 *
902 * <p> The message must consist of not more than {@code 125} bytes: {@code
903 * message.remaining() <= 125}.
904 *
905 * <p> The returned {@code CompletableFuture} can complete exceptionally
906 * with:
907 * <ul>
908 * <li> {@link IOException}
909 * if an I/O error occurs during this operation or the
910 * {@code WebSocket} closes while this operation is in progress
911 * </ul>
912 *
913 * @param message
914 * the message
915 *
916 * @return a CompletableFuture of Void
917 *
918 * @throws IllegalStateException
919 * if the WebSocket is closed
920 * @throws IllegalStateException
921 * if a Close message has been already sent
922 * @throws IllegalStateException
923 * if there is an outstanding send operation
924 * @throws IllegalArgumentException
925 * if {@code message.remaining() > 125}
926 */
927 CompletableFuture<Void> sendPong(ByteBuffer message);
928
929 /**
930 * Sends a Close message with the given close code and the reason.
931 *
932 * <p> Returns immediately with a {@code CompletableFuture<Void>} which
933 * completes normally when the message has been sent, or completes
934 * exceptionally if an error occurs.
935 *
936 * <p> A Close message may consist of a close code and a reason for closing.
937 * The reason must have a valid UTF-8 representation not longer than {@code
938 * 123} bytes. The reason may be useful for debugging or passing information
939 * relevant to the connection but is not necessarily human readable.
940 *
941 * <p> The returned {@code CompletableFuture} can complete exceptionally
942 * with:
943 * <ul>
944 * <li> {@link IOException}
945 * if an I/O error occurs during this operation or the
946 * {@code WebSocket} closes while this operation is in progress
947 * </ul>
948 *
949 * @param code
950 * the close code
951 * @param reason
952 * the reason; can be empty
953 *
954 * @return a CompletableFuture of Void
955 *
956 * @throws IllegalStateException
957 * if the WebSocket is closed
958 * @throws IllegalStateException
959 * if a Close message has been already sent
960 * @throws IllegalStateException
961 * if there is an outstanding send operation
962 * @throws IllegalArgumentException
963 * if the {@code reason} doesn't have a valid UTF-8
964 * representation not longer than {@code 123} bytes
965 */
966 CompletableFuture<Void> sendClose(CloseCode code, CharSequence reason);
967
968 /**
969 * Sends an empty Close message.
970 *
971 * <p> Returns immediately with a {@code CompletableFuture<Void>} which
972 * completes normally when the message has been sent, or completes
973 * exceptionally if an error occurs.
974 *
975 * <p> The returned {@code CompletableFuture} can complete exceptionally
976 * with:
977 * <ul>
978 * <li> {@link IOException}
979 * if an I/O error occurs during this operation or the
980 * {@code WebSocket} closes while this operation is in progress
981 * </ul>
982 *
983 * @return a CompletableFuture of Void
984 *
985 * @throws IllegalStateException
986 * if the WebSocket is closed
987 * @throws IllegalStateException
988 * if a Close message has been already sent
989 * @throws IllegalStateException
990 * if there is an outstanding send operation
991 */
992 CompletableFuture<Void> sendClose();
993
994 /**
995 * Requests {@code n} more messages to be received by the {@link Listener
996 * Listener}.
997 *
998 * <p> The actual number might be fewer if either of the endpoints decide to
999 * close the connection before that or an error occurs.
1000 *
1001 * <p> A {@code WebSocket} that has just been created, hasn't requested
1002 * anything yet. Usually the initial request for messages is done in {@link
1003 * Listener#onOpen(java.net.http.WebSocket) Listener.onOpen}.
1004 *
1005 * If all requested messages have been received, and the server sends more,
1006 * then these messages are queued.
1007 *
1008 * @implNote This implementation does not distinguish between partial and
1009 * whole messages, because it's not known beforehand how a message will be
1010 * received.
1011 * <p> If a server sends more messages than requested, the implementation
1012 * queues up these messages on the TCP connection and may eventually force
1013 * the sender to stop sending through TCP flow control.
1014 *
1015 * @param n
1016 * the number of messages
1017 *
1018 * @throws IllegalArgumentException
1019 * if {@code n < 0}
1020 *
1021 * @return resulting unfulfilled demand with this request taken into account
1022 */
1023 // TODO return void as it's breaking encapsulation (leaking info when exactly something deemed delivered)
1024 // or demand behaves after LONG.MAX_VALUE
1025 long request(long n);
1026
1027 /**
1028 * Returns a {@linkplain Builder#subprotocols(String, String...) subprotocol}
1029 * in use.
1030 *
1031 * @return a subprotocol, or {@code null} if there is none
1032 */
1033 String getSubprotocol();
1034
1035 /**
1036 * Tells whether the {@code WebSocket} is closed.
1037 *
1038 * <p> A {@code WebSocket} deemed closed when either the underlying socket
1039 * is closed or the closing handshake is completed.
1040 *
1041 * @return {@code true} if the {@code WebSocket} is closed,
1042 * {@code false} otherwise
1043 */
1044 boolean isClosed();
1045
1046 /**
1047 * Closes the {@code WebSocket} abruptly.
1048 *
1049 * <p> This method closes the underlying TCP connection. If the {@code
1050 * WebSocket} is already closed then invoking this method has no effect.
1051 *
1052 * @throws IOException
1053 * if an I/O error occurs
1054 */
1055 void abort() throws IOException;
1056
1057 /**
1058 * A {@code WebSocket} close status code.
1059 *
1060 * <p> Some codes <a href="https://tools.ietf.org/html/rfc6455#section-7.4">
1061 * specified</a> in the WebSocket Protocol are defined as named constants
1062 * here. Others can be {@linkplain #of(int) retrieved on demand}.
1063 *
1064 * <p> This is a
1065 * <a href="../../lang/doc-files/ValueBased.html">value-based</a> class;
1066 * use of identity-sensitive operations (including reference equality
1067 * ({@code ==}), identity hash code, or synchronization) on instances of
1068 * {@code CloseCode} may have unpredictable results and should be avoided.
1069 *
1070 * @since 9
1071 */
1072 final class CloseCode {
1073
1074 /**
1075 * Indicates a normal close, meaning that the purpose for which the
1076 * connection was established has been fulfilled.
1077 *
1078 * <p> Numerical representation: {@code 1000}
1079 */
1080 public static final CloseCode NORMAL_CLOSURE
1081 = new CloseCode(1000, "NORMAL_CLOSURE");
1082
1083 /**
1084 * Indicates that an endpoint is "going away", such as a server going
1085 * down or a browser having navigated away from a page.
1086 *
1087 * <p> Numerical representation: {@code 1001}
1088 */
1089 public static final CloseCode GOING_AWAY
1090 = new CloseCode(1001, "GOING_AWAY");
1091
1092 /**
1093 * Indicates that an endpoint is terminating the connection due to a
1094 * protocol error.
1095 *
1096 * <p> Numerical representation: {@code 1002}
1097 */
1098 public static final CloseCode PROTOCOL_ERROR
1099 = new CloseCode(1002, "PROTOCOL_ERROR");
1100
1101 /**
1102 * Indicates that an endpoint is terminating the connection because it
1103 * has received a type of data it cannot accept (e.g., an endpoint that
1104 * understands only text data MAY send this if it receives a binary
1105 * message).
1106 *
1107 * <p> Numerical representation: {@code 1003}
1108 */
1109 public static final CloseCode CANNOT_ACCEPT
1110 = new CloseCode(1003, "CANNOT_ACCEPT");
1111
1112 /**
1113 * Indicates that an endpoint is terminating the connection because it
1114 * has received data within a message that was not consistent with the
1115 * type of the message (e.g., non-UTF-8 [RFC3629] data within a text
1116 * message).
1117 *
1118 * <p> Numerical representation: {@code 1007}
1119 */
1120 public static final CloseCode NOT_CONSISTENT
1121 = new CloseCode(1007, "NOT_CONSISTENT");
1122
1123 /**
1124 * Indicates that an endpoint is terminating the connection because it
1125 * has received a message that violates its policy. This is a generic
1126 * status code that can be returned when there is no other more suitable
1127 * status code (e.g., {@link #CANNOT_ACCEPT} or {@link #TOO_BIG}) or if
1128 * there is a need to hide specific details about the policy.
1129 *
1130 * <p> Numerical representation: {@code 1008}
1131 */
1132 public static final CloseCode VIOLATED_POLICY
1133 = new CloseCode(1008, "VIOLATED_POLICY");
1134
1135 /**
1136 * Indicates that an endpoint is terminating the connection because it
1137 * has received a message that is too big for it to process.
1138 *
1139 * <p> Numerical representation: {@code 1009}
1140 */
1141 public static final CloseCode TOO_BIG
1142 = new CloseCode(1009, "TOO_BIG");
1143
1144 /**
1145 * Indicates that an endpoint is terminating the connection because it
1146 * encountered an unexpected condition that prevented it from fulfilling
1147 * the request.
1148 *
1149 * <p> Numerical representation: {@code 1011}
1150 */
1151 public static final CloseCode UNEXPECTED_CONDITION
1152 = new CloseCode(1011, "UNEXPECTED_CONDITION");
1153
1154 private static final Map<Integer, CloseCode> cached = Map.ofEntries(
1155 entry(NORMAL_CLOSURE),
1156 entry(GOING_AWAY),
1157 entry(PROTOCOL_ERROR),
1158 entry(CANNOT_ACCEPT),
1159 entry(NOT_CONSISTENT),
1160 entry(VIOLATED_POLICY),
1161 entry(TOO_BIG),
1162 entry(UNEXPECTED_CONDITION)
1163 );
1164
1165 /**
1166 * Returns a {@code CloseCode} from its numerical representation.
1167 *
1168 * <p> The given {@code code} should be in the range {@code 1000 <= code
1169 * <= 4999}, and should not be equal to any of the following codes:
1170 * {@code 1004}, {@code 1005}, {@code 1006} and {@code 1015}.
1171 *
1172 * @param code
1173 * numerical representation
1174 *
1175 * @return a close code corresponding to the provided numerical value
1176 *
1177 * @throws IllegalArgumentException
1178 * if {@code code} violates any of the requirements above
1179 */
1180 public static CloseCode of(int code) {
1181 if (code < 1000 || code > 4999) {
1182 throw new IllegalArgumentException("Out of range: " + code);
1183 }
1184 if (code == 1004 || code == 1005 || code == 1006 || code == 1015) {
1185 throw new IllegalArgumentException("Reserved: " + code);
1186 }
1187 CloseCode closeCode = cached.get(code);
1188 return closeCode != null ? closeCode : new CloseCode(code, "");
1189 }
1190
1191 private final int code;
1192 private final String description;
1193
1194 private CloseCode(int code, String description) {
1195 assert description != null;
1196 this.code = code;
1197 this.description = description;
1198 }
1199
1200 /**
1201 * Returns a numerical representation of this close code.
1202 *
1203 * @return a numerical representation
1204 */
1205 public int getCode() {
1206 return code;
1207 }
1208
1209 /**
1210 * Compares this close code to the specified object.
1211 *
1212 * @param o
1213 * the object to compare this {@code CloseCode} against
1214 *
1215 * @return {@code true} iff the argument is a close code with the same
1216 * {@linkplain #getCode() numerical representation} as this one
1217 */
1218 @Override
1219 public boolean equals(Object o) {
1220 if (this == o) {
1221 return true;
1222 }
1223 if (!(o instanceof CloseCode)) {
1224 return false;
1225 }
1226 CloseCode that = (CloseCode) o;
1227 return code == that.code;
1228 }
1229
1230 @Override
1231 public int hashCode() {
1232 return code;
1233 }
1234
1235 /**
1236 * Returns a human-readable representation of this close code.
1237 *
1238 * @apiNote The representation is not designed to be parsed; the format
1239 * may change unexpectedly.
1240 *
1241 * @return a string representation
1242 */
1243 @Override
1244 public String toString() {
1245 return code + (description.isEmpty() ? "" : (": " + description));
1246 }
1247
1248 private static Map.Entry<Integer, CloseCode> entry(CloseCode cc) {
1249 return Map.entry(cc.getCode(), cc);
1250 }
1251 }
1252
1253 /**
1254 * A character sequence that provides access to the characters UTF-8 decoded
1255 * from a message in a {@code ByteBuffer}.
1256 *
1257 * @since 9
1258 */
1259 interface Text extends CharSequence {
1260
1261 // Methods from the CharSequence below are mentioned explicitly for the
1262 // purpose of documentation, so when looking at javadoc it immediately
1263 // obvious what methods Text has
1264
1265 @Override
1266 int length();
1267
1268 @Override
1269 char charAt(int index);
1270
1271 @Override
1272 CharSequence subSequence(int start, int end);
1273
1274 /**
1275 * Returns a string containing the characters in this sequence in the
1276 * same order as this sequence. The length of the string will be the
1277 * length of this sequence.
1278 *
1279 * @return a string consisting of exactly this sequence of characters
1280 */
1281 @Override
1282 // TODO: remove the explicit javadoc above when:
1283 // (JDK-8144034 has been resolved) AND (the comment is still identical
1284 // to CharSequence#toString)
1285 String toString();
1286
1287 /**
1288 * Returns a read-only {@code ByteBuffer} containing the message encoded
1289 * in UTF-8.
1290 *
1291 * @return a read-only ByteBuffer
1292 */
1293 ByteBuffer asByteBuffer();
1294 }
1295 }
< prev index next >