1 /* 2 * Copyright (c) 2015, 2017, 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 26 package jdk.incubator.http; 27 28 import java.io.IOException; 29 import java.net.ProtocolException; 30 import java.net.URI; 31 import java.nio.ByteBuffer; 32 import java.time.Duration; 33 import java.util.concurrent.CompletableFuture; 34 import java.util.concurrent.CompletionStage; 35 36 /** 37 * A WebSocket client conforming to RFC 6455. 38 * {@Incubating} 39 * 40 * <p> A {@code WebSocket} provides full-duplex communication over a TCP 41 * connection. 42 * 43 * <p> To create a {@code WebSocket} use a {@linkplain HttpClient#newWebSocketBuilder( 44 * URI, Listener) builder}. Once a {@code WebSocket} is built, it's ready 45 * to send and receive messages. When the {@code WebSocket} is no longer needed 46 * it must be closed: a Close message must both be {@linkplain #sendClose 47 * sent} and {@linkplain Listener#onClose(WebSocket, int, String) received}. 48 * The {@code WebSocket} may be also closed {@linkplain #abort() abruptly}. 49 * 50 * <p> Once closed the {@code WebSocket} remains {@linkplain #isClosed() closed} 51 * and cannot be reopened. 52 * 53 * <p> Messages of type {@code X} (where {@code X} is one of: Text, Binary, 54 * Ping, Pong or Close) are sent and received asynchronously through the {@code 55 * WebSocket.send{X}} and {@link WebSocket.Listener}{@code .on{X}} methods 56 * respectively. Each method returns a {@link CompletionStage} which completes 57 * when the operation has completed. 58 * 59 * <p> Note that messages (of any type) are received only if {@linkplain 60 * #request(long) requested}. 61 * 62 * <p> One outstanding send operation is permitted. No further send operation 63 * can be initiated before the previous one has completed. When sending, a 64 * message must not be modified until the returned {@link CompletableFuture} 65 * completes (either normally or exceptionally). 66 * 67 * <p> Text and Binary messages can be sent and received as a whole or in parts. 68 * A whole message is transferred as a sequence of one or more invocations of a 69 * corresponding method where the last invocation is identified via an 70 * additional method argument. 71 * 72 * <p> If the message is contained in a {@link ByteBuffer}, bytes are considered 73 * arranged from the {@code buffer}'s {@link ByteBuffer#position() position} to 74 * the {@code buffer}'s {@link ByteBuffer#limit() limit}. 75 * 76 * <p> Unless otherwise stated, {@code null} parameter values will cause methods 77 * and constructors to throw {@link NullPointerException}. 78 * 79 * @implNote This implementation's methods do not block before returning 80 * a {@code CompletableFuture}. 81 * 82 * @since 9 83 */ 84 public interface WebSocket { 85 86 /** 87 * The WebSocket Close message status code (<code>{@value}</code>), 88 * indicating normal closure, meaning that the purpose for which the 89 * connection was established has been fulfilled. 90 * 91 * @see #sendClose(int, String) 92 * @see Listener#onClose(WebSocket, int, String) 93 */ 94 int NORMAL_CLOSURE = 1000; 95 96 /** 97 * A builder for creating {@code WebSocket} instances. 98 * {@Incubating} 99 * 100 * <p> To build a {@code WebSocket}, {@linkplain HttpClient#newWebSocketBuilder( 101 * URI, Listener) create} a builder, configure it as required by 102 * calling intermediate methods (the ones that return the builder itself), 103 * then finally call {@link #buildAsync()} to get a {@link 104 * CompletableFuture} with resulting {@code WebSocket}. 105 * 106 * <p> If an intermediate method has not been called, an appropriate 107 * default value (or behavior) will be used. Unless otherwise noted, a 108 * repeated call to an intermediate method overwrites the previous value (or 109 * overrides the previous behaviour). 110 * 111 * <p> Instances of {@code Builder} are not safe for use by multiple threads 112 * without external synchronization. 113 * 114 * @since 9 115 */ 116 interface Builder { 117 118 /** 119 * Adds the given name-value pair to the list of additional headers for 120 * the opening handshake. 121 * 122 * <p> Headers defined in WebSocket Protocol are not allowed to be added. 123 * 124 * @param name 125 * the header name 126 * @param value 127 * the header value 128 * 129 * @return this builder 130 */ 131 Builder header(String name, String value); 132 133 /** 134 * Includes a request for the given subprotocols during the opening 135 * handshake. 136 * 137 * <p> Among the requested subprotocols at most one will be chosen by 138 * the server. This subprotocol will be available from {@link 139 * WebSocket#getSubprotocol}. Subprotocols are specified in the order of 140 * preference. 141 * 142 * <p> Each of the given subprotocols must conform to the relevant 143 * rules defined in the WebSocket Protocol. 144 * 145 * <p> If this method is not invoked then no subprotocols are requested. 146 * 147 * @param mostPreferred 148 * the most preferred subprotocol 149 * @param lesserPreferred 150 * the lesser preferred subprotocols, with the least preferred 151 * at the end 152 * 153 * @return this builder 154 */ 155 Builder subprotocols(String mostPreferred, String... lesserPreferred); 156 157 /** 158 * Sets a timeout for the opening handshake. 159 * 160 * <p> If the opening handshake does not complete within the specified 161 * duration then the {@code CompletableFuture} returned from {@link 162 * #buildAsync()} completes exceptionally with a {@link 163 * HttpTimeoutException}. 164 * 165 * <p> If this method is not invoked then the timeout is deemed infinite. 166 * 167 * @param timeout 168 * the timeout, non-{@linkplain Duration#isNegative() negative}, 169 * non-{@linkplain Duration#ZERO ZERO} 170 * 171 * @return this builder 172 */ 173 Builder connectTimeout(Duration timeout); 174 175 /** 176 * Builds a {@code WebSocket}. 177 * 178 * <p> Returns a {@code CompletableFuture<WebSocket>} which completes 179 * normally with the {@code WebSocket} when it is connected or completes 180 * exceptionally if an error occurs. 181 * 182 * <p> {@code CompletableFuture} may complete exceptionally with the 183 * following errors: 184 * <ul> 185 * <li> {@link IOException} - 186 * if an I/O error occurs 187 * <li> {@link WebSocketHandshakeException} - 188 * if the opening handshake fails 189 * <li> {@link HttpTimeoutException} - 190 * if the opening handshake does not complete within 191 * the specified {@linkplain #connectTimeout(Duration) duration} 192 * <li> {@link InterruptedException} - 193 * if the operation was interrupted 194 * <li> {@link SecurityException} - 195 * if a security manager is set, and the caller does not 196 * have a {@link java.net.URLPermission} for the WebSocket URI 197 * <li> {@link IllegalArgumentException} - 198 * if any of the additional {@link #header(String, String) 199 * headers} are illegal; 200 * or if any of the WebSocket Protocol rules relevant to {@link 201 * #subprotocols(String, String...) subprotocols} are violated; 202 * or if the {@link #connectTimeout(Duration) connect timeout} 203 * is invalid; 204 * </ul> 205 * 206 * @return a {@code CompletableFuture} with the {@code WebSocket} 207 */ 208 CompletableFuture<WebSocket> buildAsync(); 209 } 210 211 /** 212 * A listener for events and messages on a {@code WebSocket}. 213 * {@Incubating} 214 * 215 * <p> Each method of {@code Listener} corresponds to a type of event or a 216 * type of message. The {@code WebSocket} argument of the method is the 217 * {@code WebSocket} the event has occurred (the message has been received) 218 * on. All methods with the same {@code WebSocket} argument are invoked in a 219 * sequential 220 * (and <a href="../../../java/util/concurrent/package-summary.html#MemoryVisibility">happens-before</a>) 221 * order, one after another, possibly by different threads. 222 * 223 * <ul> 224 * <li> {@link #onOpen(WebSocket) onOpen} <br> 225 * This method is invoked first. 226 * <li> {@link #onText(WebSocket, CharSequence, WebSocket.MessagePart) 227 * onText}, {@link #onBinary(WebSocket, ByteBuffer, WebSocket.MessagePart) 228 * onBinary}, {@link #onPing(WebSocket, ByteBuffer) onPing} and {@link 229 * #onPong(WebSocket, ByteBuffer) onPong} <br> 230 * These methods are invoked zero or more times after {@code onOpen}. 231 * <li> {@link #onClose(WebSocket, int, String) onClose}, {@link 232 * #onError(WebSocket, Throwable) onError} <br> 233 * Only one of these methods is invoked, and that method is invoked last. 234 * </ul> 235 * 236 * <p> Messages received by the {@code Listener} conform to the WebSocket 237 * Protocol, otherwise {@code onError} with a {@link ProtocolException} is 238 * invoked. 239 * 240 * <p> If a whole message is received, then the corresponding method 241 * ({@code onText} or {@code onBinary}) will be invoked with {@link 242 * WebSocket.MessagePart#WHOLE WHOLE} marker. Otherwise the method will be 243 * invoked with {@link WebSocket.MessagePart#FIRST FIRST}, zero or more 244 * times with {@link WebSocket.MessagePart#PART PART} and, finally, with 245 * {@link WebSocket.MessagePart#LAST LAST} markers. 246 * 247 * If any of the methods above throws an exception, {@code onError} is then 248 * invoked with the same {@code WebSocket} and this exception. Exceptions 249 * thrown from {@code onError} or {@code onClose} are ignored. 250 * 251 * <p> When the method returns, the message is deemed received (in 252 * particular, if contained in a {@code ByteBuffer buffer}, the data is 253 * deemed received completely regardless of the result {@code 254 * buffer.hasRemaining()} upon the method's return. After this further 255 * messages may be received. 256 * 257 * <p> These invocations begin asynchronous processing which might not end 258 * with the invocation. To provide coordination, methods of {@code Listener} 259 * return a {@link CompletionStage CompletionStage}. 260 * The {@code CompletionStage} signals the {@code WebSocket} that the 261 * processing of a message has ended. For convenience, methods may return 262 * {@code null}, which (by convention) means the same as returning an 263 * already completed (normally) {@code CompletionStage}. 264 * If the returned {@code CompletionStage} completes exceptionally, then 265 * {@link #onError(WebSocket, Throwable) onError} will be invoked with the 266 * same {@code WebSocket} and this exception. 267 * 268 * <p> Control of the message passes to the {@code Listener} with the 269 * invocation of the method. Control of the message returns to the {@code 270 * WebSocket} at the earliest of, either returning {@code null} from the 271 * method, or the completion of the {@code CompletionStage} returned from 272 * the method. The {@code WebSocket} does not access the message while it's 273 * not in its control. The {@code Listener} must not access the message 274 * after its control has been returned to the {@code WebSocket}. 275 * 276 * <p> A {@code WebSocket} implementation never invokes {@code Listener}'s 277 * methods with {@code null}s as their arguments. 278 * 279 * @since 9 280 */ 281 interface Listener { 282 283 /** 284 * Notifies the {@code Listener} that it is connected to the provided 285 * {@code WebSocket}. 286 * 287 * <p> The {@code onOpen} method does not correspond to any message from 288 * the WebSocket Protocol. It is a synthetic event and the first {@code 289 * Listener}'s method to be invoked. 290 * 291 * <p> This method is usually used to make an initial {@linkplain 292 * WebSocket#request(long) request} for messages. 293 * 294 * <p> If an exception is thrown from this method then {@link 295 * #onError(WebSocket, Throwable) onError} will be invoked with the same 296 * {@code WebSocket} and this exception. 297 * 298 * @implSpec The default implementation of this method behaves as if: 299 * 300 * <pre>{@code 301 * webSocket.request(1); 302 * }</pre> 303 * 304 * @param webSocket 305 * the WebSocket 306 */ 307 default void onOpen(WebSocket webSocket) { webSocket.request(1); } 308 309 /** 310 * Receives a Text message. 311 * 312 * <p> The {@code onText} method is invoked zero or more times between 313 * {@code onOpen} and ({@code onClose} or {@code onError}). 314 * 315 * <p> This message may be a partial UTF-16 sequence. However, the 316 * concatenation of all messages through the last will be a whole UTF-16 317 * sequence. 318 * 319 * <p> If an exception is thrown from this method or the returned {@code 320 * CompletionStage} completes exceptionally, then {@link 321 * #onError(WebSocket, Throwable) onError} will be invoked with the same 322 * {@code WebSocket} and this exception. 323 * 324 * @implSpec The default implementation of this method behaves as if: 325 * 326 * <pre>{@code 327 * webSocket.request(1); 328 * return null; 329 * }</pre> 330 * 331 * @implNote This implementation passes only complete UTF-16 sequences 332 * to the {@code onText} method. 333 * 334 * @param webSocket 335 * the WebSocket 336 * @param message 337 * the message 338 * @param part 339 * the part 340 * 341 * @return a {@code CompletionStage} which completes when the message 342 * processing is done; or {@code null} if already done 343 */ 344 default CompletionStage<?> onText(WebSocket webSocket, 345 CharSequence message, 346 MessagePart part) { 347 webSocket.request(1); 348 return null; 349 } 350 351 /** 352 * Receives a Binary message. 353 * 354 * <p> The {@code onBinary} method is invoked zero or more times 355 * between {@code onOpen} and ({@code onClose} or {@code onError}). 356 * 357 * <p> If an exception is thrown from this method or the returned {@code 358 * CompletionStage} completes exceptionally, then {@link 359 * #onError(WebSocket, Throwable) onError} will be invoked with the same 360 * {@code WebSocket} and this exception. 361 * 362 * @implSpec The default implementation of this method behaves as if: 363 * 364 * <pre>{@code 365 * webSocket.request(1); 366 * return null; 367 * }</pre> 368 * 369 * @param webSocket 370 * the WebSocket 371 * @param message 372 * the message 373 * @param part 374 * the part 375 * 376 * @return a {@code CompletionStage} which completes when the message 377 * processing is done; or {@code null} if already done 378 */ 379 default CompletionStage<?> onBinary(WebSocket webSocket, 380 ByteBuffer message, 381 MessagePart part) { 382 webSocket.request(1); 383 return null; 384 } 385 386 /** 387 * Receives a Ping message. 388 * 389 * <p> A Ping message may be sent or received by either client or 390 * server. It may serve either as a keepalive or as a means to verify 391 * that the remote endpoint is still responsive. 392 * 393 * <p> The {@code WebSocket} handles Ping messages by replying with 394 * appropriate Pong messages using a strategy of its choice, but within 395 * the boundaries of the WebSocket Protocol. The {@code WebSocket} may 396 * invoke {@code onPing} after handling a Ping message, before doing so 397 * or in parallel with it. In other words no particular ordering is 398 * guaranteed. If an error occurs while implementation handles this Ping 399 * message, then {@code onError} will be invoked with this error. For 400 * more details on handling Ping messages see RFC 6455 sections 401 * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">5.5.2. Ping</a> 402 * and 403 * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">5.5.3. Pong</a>. 404 * 405 * <p> The message will consist of not more than {@code 125} bytes: 406 * {@code message.remaining() <= 125}. 407 * 408 * <p> The {@code onPing} is invoked zero or more times in between 409 * {@code onOpen} and ({@code onClose} or {@code onError}). 410 * 411 * <p> If an exception is thrown from this method or the returned {@code 412 * CompletionStage} completes exceptionally, then {@link 413 * #onError(WebSocket, Throwable) onError} will be invoked with this 414 * exception. 415 * 416 * @implSpec The default implementation of this method behaves as if: 417 * 418 * <pre>{@code 419 * webSocket.request(1); 420 * return null; 421 * }</pre> 422 * 423 * @param webSocket 424 * the WebSocket 425 * @param message 426 * the message 427 * 428 * @return a {@code CompletionStage} which completes when the message 429 * processing is done; or {@code null} if already done 430 */ 431 default CompletionStage<?> onPing(WebSocket webSocket, 432 ByteBuffer message) { 433 webSocket.request(1); 434 return null; 435 } 436 437 /** 438 * Receives a Pong message. 439 * 440 * <p> A Pong message may be unsolicited or may be received in response 441 * to a previously sent Ping. In the latter case, the contents of the 442 * Pong is identical to the originating Ping. 443 * 444 * <p> The message will consist of not more than {@code 125} bytes: 445 * {@code message.remaining() <= 125}. 446 * 447 * <p> The {@code onPong} method is invoked zero or more times in 448 * between {@code onOpen} and ({@code onClose} or {@code onError}). 449 * 450 * <p> If an exception is thrown from this method or the returned {@code 451 * CompletionStage} completes exceptionally, then {@link 452 * #onError(WebSocket, Throwable) onError} will be invoked with this 453 * exception. 454 * 455 * @implSpec The default implementation of this method behaves as if: 456 * 457 * <pre>{@code 458 * webSocket.request(1); 459 * return null; 460 * }</pre> 461 * 462 * @param webSocket 463 * the WebSocket 464 * @param message 465 * the message 466 * 467 * @return a {@code CompletionStage} which completes when the message 468 * processing is done; or {@code null} if already done 469 */ 470 default CompletionStage<?> onPong(WebSocket webSocket, 471 ByteBuffer message) { 472 webSocket.request(1); 473 return null; 474 } 475 476 /** 477 * Receives a Close message. 478 * 479 * <p> A Close message consists of a status code and a reason for 480 * closing. The status code is an integer in the range {@code 1000 <= 481 * code <= 65535}. The {@code reason} is a short string that has an 482 * UTF-8 representation not longer than {@code 123} bytes. For more 483 * details on Close message, status codes and reason see RFC 6455 sections 484 * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">5.5.1. Close</a> 485 * and 486 * <a href="https://tools.ietf.org/html/rfc6455#section-7.4">7.4. Status Codes</a>. 487 * 488 * <p> After the returned {@code CompletionStage} has completed 489 * (normally or exceptionally), the {@code WebSocket} completes the 490 * closing handshake by replying with an appropriate Close message. 491 * 492 * <p> This implementation replies with a Close message that has the 493 * same code this message has and an empty reason. 494 * 495 * <p> {@code onClose} is the last invocation on the {@code Listener}. 496 * It is invoked at most once, but after {@code onOpen}. If an exception 497 * is thrown from this method, it is ignored. 498 * 499 * <p> The {@code WebSocket} will close at the earliest of completion of 500 * the returned {@code CompletionStage} or sending a Close message. In 501 * particular, if a Close message has been {@linkplain WebSocket#sendClose 502 * sent} before, then this invocation completes the closing handshake 503 * and by the time this method is invoked, the {@code WebSocket} will 504 * have been closed. 505 * 506 * @implSpec The default implementation of this method behaves as if: 507 * 508 * <pre>{@code 509 * return null; 510 * }</pre> 511 * 512 * @param webSocket 513 * the WebSocket 514 * @param statusCode 515 * the status code 516 * @param reason 517 * the reason 518 * 519 * @return a {@code CompletionStage} which completes when the {@code 520 * WebSocket} can be closed; or {@code null} if it can be closed immediately 521 * 522 * @see #NORMAL_CLOSURE 523 */ 524 default CompletionStage<?> onClose(WebSocket webSocket, 525 int statusCode, 526 String reason) { 527 return null; 528 } 529 530 /** 531 * Notifies an I/O or protocol error has occurred. 532 * 533 * <p> The {@code onError} method does not correspond to any message 534 * from the WebSocket Protocol. It is a synthetic event and the last 535 * {@code Listener}'s method to be invoked. It is invoked at most once 536 * but after {@code onOpen}. If an exception is thrown from this method, 537 * it is ignored. 538 * 539 * <p> Note that the WebSocket Protocol requires <i>some</i> errors 540 * occur in the incoming destination must be fatal to the connection. In 541 * such cases the implementation takes care of <i>Failing the WebSocket 542 * Connection</i>: by the time {@code onError} is invoked, the {@code 543 * WebSocket} will have been closed. Any outstanding or subsequent send 544 * operation will complete exceptionally with an {@code IOException}. 545 * For more details on Failing the WebSocket Connection see RFC 6455 546 * section <a href="https://tools.ietf.org/html/rfc6455#section-7.1.7">7.1.7. Fail the WebSocket Connection</a>. 547 * 548 * @apiNote Errors associated with sending messages are reported to the 549 * {@code CompletableFuture}s {@code sendX} methods return, rather than 550 * to this this method. 551 * 552 * @implSpec The default implementation of this method does nothing. 553 * 554 * @param webSocket 555 * the WebSocket 556 * @param error 557 * the error 558 */ 559 default void onError(WebSocket webSocket, Throwable error) { } 560 } 561 562 /** 563 * A marker used by {@link WebSocket.Listener} in cases where a partial 564 * message may be received. 565 * {@Incubating} 566 * 567 * @see Listener#onText(WebSocket, CharSequence, MessagePart) 568 * @see Listener#onBinary(WebSocket, ByteBuffer, MessagePart) 569 * 570 * @since 9 571 */ 572 enum MessagePart { 573 574 /** 575 * The first part of a message in a sequence. 576 */ 577 FIRST, 578 579 /** 580 * A middle part of a message in a sequence. 581 */ 582 PART, 583 584 /** 585 * The last part of a message in a sequence. 586 */ 587 LAST, 588 589 /** 590 * A whole message consisting of a single part. 591 */ 592 WHOLE 593 } 594 595 /** 596 * Sends a Text message with characters from the given {@code CharSequence}. 597 * 598 * <p> Returns a {@code CompletableFuture<WebSocket>} which completes 599 * normally when the message has been sent or completes exceptionally if an 600 * error occurs. 601 * 602 * <p> The {@code CharSequence} must not be modified until the returned 603 * {@code CompletableFuture} completes (either normally or exceptionally). 604 * 605 * <p> The returned {@code CompletableFuture} can complete exceptionally 606 * with: 607 * <ul> 608 * <li> {@link IllegalArgumentException} - 609 * if {@code message} is a malformed UTF-16 sequence 610 * <li> {@link IllegalStateException} - 611 * if the {@code WebSocket} is closed; 612 * or if a Close message has been sent; 613 * or if there is an outstanding send operation; 614 * or if a previous Binary message was sent with {@code isLast == false} 615 * <li> {@link IOException} - 616 * if an I/O error occurs during this operation; 617 * or if the {@code WebSocket} has been closed due to an error; 618 * </ul> 619 * 620 * @implNote This implementation does not accept partial UTF-16 sequences. 621 * In case such a sequence is passed, a returned {@code CompletableFuture} 622 * completes exceptionally with {@code IOException}. 623 * 624 * @param message 625 * the message 626 * @param isLast 627 * {@code true} if this is the last part of the message, 628 * {@code false} otherwise 629 * 630 * @return a {@code CompletableFuture} with this {@code WebSocket} 631 */ 632 CompletableFuture<WebSocket> sendText(CharSequence message, boolean isLast); 633 634 /** 635 * Sends a Binary message with bytes from the given {@code ByteBuffer}. 636 * 637 * <p> Returns a {@code CompletableFuture<WebSocket>} which completes 638 * normally when the message has been sent or completes exceptionally if an 639 * error occurs. 640 * 641 * <p> The returned {@code CompletableFuture} can complete exceptionally 642 * with: 643 * <ul> 644 * <li> {@link IllegalStateException} - 645 * if the {@code WebSocket} is closed; 646 * or if a Close message has been sent; 647 * or if there is an outstanding send operation; 648 * or if a previous Text message was sent with {@code isLast == false} 649 * <li> {@link IOException} - 650 * if an I/O error occurs during this operation; 651 * or if the {@code WebSocket} has been closed due to an error 652 * </ul> 653 * 654 * @param message 655 * the message 656 * @param isLast 657 * {@code true} if this is the last part of the message, 658 * {@code false} otherwise 659 * 660 * @return a {@code CompletableFuture} with this {@code WebSocket} 661 */ 662 CompletableFuture<WebSocket> sendBinary(ByteBuffer message, boolean isLast); 663 664 /** 665 * Sends a Ping message with bytes from the given ByteBuffer. 666 * 667 * <p> Returns a {@code CompletableFuture<WebSocket>} which completes 668 * normally when the message has been sent or completes exceptionally if an 669 * error occurs. 670 * 671 * <p> A Ping message may be sent or received by either client or server. 672 * It may serve either as a keepalive or as a means to verify that the 673 * remote endpoint is still responsive. 674 * 675 * <p> The message must consist of not more than {@code 125} bytes: {@code 676 * message.remaining() <= 125}. 677 * 678 * <p> The returned {@code CompletableFuture} can complete exceptionally 679 * with: 680 * <ul> 681 * <li> {@link IllegalArgumentException} - 682 * if {@code message.remaining() > 125} 683 * <li> {@link IllegalStateException} - 684 * if the {@code WebSocket} is closed; 685 * or if a Close message has been sent; 686 * or if there is an outstanding send operation 687 * <li> {@link IOException} - 688 * if an I/O error occurs during this operation; 689 * or if the {@code WebSocket} has been closed due to an error 690 * </ul> 691 * 692 * @param message 693 * the message 694 * 695 * @return a {@code CompletableFuture} with this {@code WebSocket} 696 */ 697 CompletableFuture<WebSocket> sendPing(ByteBuffer message); 698 699 /** 700 * Sends a Pong message with bytes from the given ByteBuffer. 701 * 702 * <p> Returns a {@code CompletableFuture<WebSocket>} which completes 703 * normally when the message has been sent or completes exceptionally if an 704 * error occurs. 705 * 706 * <p> A Pong message may be unsolicited or may be sent in response to a 707 * previously received Ping. In latter case the contents of the Pong must be 708 * identical to the originating Ping. 709 * 710 * <p> The message must consist of not more than {@code 125} bytes: {@code 711 * message.remaining() <= 125}. 712 * 713 * <p> The returned {@code CompletableFuture} can complete exceptionally 714 * with: 715 * <ul> 716 * <li> {@link IllegalArgumentException} - 717 * if {@code message.remaining() > 125} 718 * <li> {@link IllegalStateException} - 719 * if the {@code WebSocket} is closed; 720 * or if a Close message has been sent; 721 * or if there is an outstanding send operation 722 * <li> {@link IOException} - 723 * if an I/O error occurs during this operation; 724 * or if the {@code WebSocket} has been closed due to an error 725 * </ul> 726 * 727 * @param message 728 * the message 729 * 730 * @return a {@code CompletableFuture} with this {@code WebSocket} 731 */ 732 CompletableFuture<WebSocket> sendPong(ByteBuffer message); 733 734 /** 735 * Sends a Close message with the given status code and the reason. 736 * 737 * <p> When this method has been invoked, no further messages can be sent. 738 * 739 * <p> The {@code statusCode} is an integer in the range {@code 1000 <= code 740 * <= 4999}. However, not all status codes may be legal in some 741 * implementations. Regardless of an implementation, 742 * <code>{@value jdk.incubator.http.WebSocket#NORMAL_CLOSURE}</code> 743 * is always legal and {@code 1002}, {@code 1003}, {@code 1005}, {@code 744 * 1006}, {@code 1007}, {@code 1009}, {@code 1010}, {@code 1012}, {@code 745 * 1013} and {@code 1015} are always illegal codes. 746 * 747 * <p> The {@code reason} is a short string that must have an UTF-8 748 * representation not longer than {@code 123} bytes. For more details on 749 * Close message, status codes and reason see RFC 6455 sections 750 * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">5.5.1. Close</a> 751 * and 752 * <a href="https://tools.ietf.org/html/rfc6455#section-7.4">7.4. Status Codes</a>. 753 * 754 * <p> The method returns a {@code CompletableFuture<WebSocket>} which 755 * completes normally when the message has been sent or completes 756 * exceptionally if an error occurs. 757 * 758 * <p> The returned {@code CompletableFuture} can complete exceptionally 759 * with: 760 * <ul> 761 * <li> {@link IllegalArgumentException} - 762 * if the {@code statusCode} has an illegal value; 763 * or if {@code reason} doesn't have an UTF-8 representation of 764 * length {@code <= 123} 765 * <li> {@link IOException} - 766 * if an I/O error occurs during this operation; 767 * or the {@code WebSocket} has been closed due to an error 768 * </ul> 769 * 770 * <p> If this method has already been invoked or the {@code WebSocket} is 771 * closed, then subsequent invocations of this method have no effect and the 772 * returned {@code CompletableFuture} completes normally. 773 * 774 * <p> If a Close message has been {@linkplain Listener#onClose(WebSocket, 775 * int, String) received} before, then this invocation completes the closing 776 * handshake and by the time the returned {@code CompletableFuture} 777 * completes, the {@code WebSocket} will have been closed. 778 * 779 * @param statusCode 780 * the status code 781 * @param reason 782 * the reason 783 * 784 * @return a {@code CompletableFuture} with this {@code WebSocket} 785 */ 786 CompletableFuture<WebSocket> sendClose(int statusCode, String reason); 787 788 /** 789 * Allows {@code n} more messages to be received by the {@link Listener 790 * Listener}. 791 * 792 * <p> The actual number of received messages might be fewer if a Close 793 * message is received, the {@code WebSocket} closes or an error occurs. 794 * 795 * <p> A {@code WebSocket} that has just been built, hasn't requested 796 * anything yet. Usually the initial request for messages is made in {@link 797 * Listener#onOpen(jdk.incubator.http.WebSocket) Listener.onOpen}. 798 * 799 * <p> If the {@code WebSocket} is closed then invoking this method has no 800 * effect. 801 * 802 * @implNote This implementation does not distinguish between partial and 803 * whole messages, because it's not known beforehand how a message will be 804 * received. 805 * 806 * <p> If a server sends more messages than requested, this implementation 807 * queues up these messages on the TCP connection and may eventually force 808 * the sender to stop sending through TCP flow control. 809 * 810 * @param n 811 * the number of messages 812 * 813 * @throws IllegalArgumentException 814 * if {@code n < 0} 815 */ 816 void request(long n); 817 818 /** 819 * Returns a {@linkplain Builder#subprotocols(String, String...) subprotocol} 820 * which has been chosen for this {@code WebSocket}. 821 * 822 * @return a subprotocol, or an empty {@code String} if there is none 823 */ 824 String getSubprotocol(); 825 826 /** 827 * Tells whether the {@code WebSocket} is closed. 828 * 829 * <p> When a {@code WebSocket} is closed no further messages can be sent or 830 * received. 831 * 832 * @return {@code true} if the {@code WebSocket} is closed, 833 * {@code false} otherwise 834 */ 835 boolean isClosed(); 836 837 /** 838 * Closes the {@code WebSocket} abruptly. 839 * 840 * <p> This method may be invoked at any time. This method closes the 841 * underlying TCP connection and puts the {@code WebSocket} into a closed 842 * state. 843 * 844 * <p> As the result {@link Listener#onClose(WebSocket, int, String) 845 * Listener.onClose} will be invoked unless either {@code onClose} or {@link 846 * Listener#onError(WebSocket, Throwable) onError} has been invoked before. 847 * In which case no additional invocation will happen. 848 * 849 * <p> If the {@code WebSocket} is already closed then invoking this method 850 * has no effect. 851 * 852 * @throws IOException 853 * if an I/O error occurs 854 */ 855 void abort() throws IOException; 856 }