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.time.Duration;
  32 import java.util.Map;
  33 import java.util.Optional;
  34 import java.util.concurrent.CompletableFuture;
  35 import java.util.concurrent.CompletionStage;
  36 
  37 /**
  38  * A WebSocket client conforming to RFC 6455.
  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 #newBuilder(URI, Listener)
  44  * builder}. Once a {@code WebSocket} is obtained, it's ready to send and
  45  * receive messages. When the {@code WebSocket} is no longer
  46  * needed it must be closed: a Close message must both be {@linkplain
  47  * #sendClose() sent} and {@linkplain Listener#onClose(WebSocket, Optional,
  48  * String) received}. Otherwise, invoke {@link #abort() abort} to close abruptly.
  49  *
  50  * <p> Once closed the {@code WebSocket} remains closed and cannot be reopened.
  51  *
  52  * <p> Messages of type {@code X} are sent through the {@code WebSocket.sendX}
  53  * methods and received through {@link WebSocket.Listener}{@code .onX} methods
  54  * asynchronously. Each of the methods returns a {@link CompletionStage} which
  55  * completes when the operation has completed.
  56  *
  57  * <p> Messages are received only if {@linkplain #request(long) requested}.
  58  *
  59  * <p> One outstanding send operation is permitted: if another send operation is
  60  * initiated before the previous one has completed, an {@link
  61  * IllegalStateException IllegalStateException} will be thrown. When sending, a
  62  * message should not be modified until the returned {@code CompletableFuture}
  63  * completes (either normally or exceptionally).
  64  *
  65  * <p> Messages can be sent and received as a whole or in parts. A whole message
  66  * is a sequence of one or more messages in which the last message is marked
  67  * when it is sent or received.
  68  *
  69  * <p> If the message is contained in a {@link ByteBuffer}, bytes are considered
  70  * arranged from the {@code buffer}'s {@link ByteBuffer#position() position} to
  71  * the {@code buffer}'s {@link ByteBuffer#limit() limit}.
  72  *
  73  * <p> Unless otherwise noted, passing a {@code null} argument to a constructor
  74  * or method of this type will cause a {@link NullPointerException
  75  * NullPointerException} to be thrown.
  76  *
  77  * @implNote The default implementation's methods do not block before returning
  78  * a {@code CompletableFuture}.
  79  *
  80  * @since 9
  81  */
  82 public interface WebSocket {
  83 
  84     /**
  85      * Creates a builder of {@code WebSocket}s connected to the given URI and
  86      * receiving events with the given {@code Listener}.
  87      *
  88      * <p> Equivalent to:
  89      * <pre>{@code
  90      *     WebSocket.newBuilder(uri, HttpClient.getDefault())
  91      * }</pre>
  92      *
  93      * @param uri
  94      *         the WebSocket URI as defined in the WebSocket Protocol
  95      *         (with "ws" or "wss" scheme)
  96      *
  97      * @param listener
  98      *         the listener
  99      *
 100      * @throws IllegalArgumentException
 101      *         if the {@code uri} is not a WebSocket URI
 102      * @throws SecurityException
 103      *         if running under a security manager and the caller does
 104      *         not have permission to access the
 105      *         {@linkplain HttpClient#getDefault() default HttpClient}
 106      *
 107      * @return a builder
 108      */
 109     static Builder newBuilder(URI uri, Listener listener) {
 110         return newBuilder(uri, HttpClient.getDefault(), listener);
 111     }
 112 
 113     /**
 114      * Creates a builder of {@code WebSocket}s connected to the given URI and
 115      * receiving events with the given {@code Listener}.
 116      *
 117      * <p> Providing a custom {@code client} allows for finer control over the
 118      * opening handshake.
 119      *
 120      * <p> <b>Example</b>
 121      * <pre>{@code
 122      *     HttpClient client = HttpClient.create()
 123      *             .proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
 124      *             .build();
 125      *     ...
 126      *     WebSocket.newBuilder(URI.create("ws://websocket.example.com"), client, listener)...
 127      * }</pre>
 128      *
 129      * @param uri
 130      *         the WebSocket URI as defined in the WebSocket Protocol
 131      *         (with "ws" or "wss" scheme)
 132      *
 133      * @param client
 134      *         the HttpClient
 135      * @param listener
 136      *         the listener
 137      *
 138      * @throws IllegalArgumentException
 139      *         if the uri is not a WebSocket URI
 140      *
 141      * @return a builder
 142      */
 143     static Builder newBuilder(URI uri, HttpClient client, Listener listener) {
 144         return new WSBuilder(uri, client, listener);
 145     }
 146 
 147     /**
 148      * A builder for creating {@code WebSocket} instances.
 149      *
 150      * <p> To build a {@code WebSocket}, instantiate a builder, configure it
 151      * as required by calling intermediate methods (the ones that return the
 152      * builder itself), then finally call {@link #buildAsync()} to get a {@link
 153      * CompletableFuture} with resulting {@code WebSocket}.
 154      *
 155      * <p> If an intermediate method has not been called, an appropriate
 156      * default value (or behavior) will be used. Unless otherwise noted, a
 157      * repeated call to an intermediate method overwrites the previous value (or
 158      * overrides the previous behaviour), if no exception is thrown.
 159      *
 160      * <p> Instances of {@code Builder} may not be safe for use by multiple
 161      * threads.
 162      *
 163      * @since 9
 164      */
 165     interface Builder {
 166 
 167         /**
 168          * Adds the given name-value pair to the list of additional headers for
 169          * the opening handshake.
 170          *
 171          * <p> Headers defined in WebSocket Protocol are not allowed to be added.
 172          *
 173          * @param name
 174          *         the header name
 175          * @param value
 176          *         the header value
 177          *
 178          * @return this builder
 179          *
 180          * @throws IllegalArgumentException
 181          *         if the {@code name} is a WebSocket defined header name
 182          */
 183         Builder header(String name, String value);
 184 
 185         /**
 186          * Includes a request for the given subprotocols during the opening
 187          * handshake.
 188          *
 189          * <p> Among the requested subprotocols at most one will be chosen by
 190          * the server. When the {@code WebSocket} is connected, the subprotocol
 191          * in use is available from {@link WebSocket#getSubprotocol}.
 192          * Subprotocols may be specified in the order of preference.
 193          *
 194          * <p> Each of the given subprotocols must conform to the relevant
 195          * rules defined in the WebSocket Protocol.
 196          *
 197          * @param mostPreferred
 198          *         the most preferred subprotocol
 199          * @param lesserPreferred
 200          *         the lesser preferred subprotocols, with the least preferred
 201          *         at the end
 202          *
 203          * @return this builder
 204          *
 205          * @throws IllegalArgumentException
 206          *         if any of the WebSocket Protocol rules relevant to
 207          *         subprotocols are violated
 208          */
 209         Builder subprotocols(String mostPreferred, String... lesserPreferred);
 210 
 211         /**
 212          * Sets a timeout for the opening handshake.
 213          *
 214          * <p> If the opening handshake is not finished within the specified
 215          * amount of time then {@link #buildAsync()} completes exceptionally
 216          * with a {@code HttpTimeoutException}.
 217          *
 218          * <p> If this method is not invoked then the timeout is deemed infinite.
 219          *
 220          * @param timeout
 221          *         the timeout
 222          *
 223          * @return this builder
 224          */
 225         Builder connectTimeout(Duration timeout);
 226 
 227         /**
 228          * Builds a {@code WebSocket}.
 229          *
 230          * <p> Returns a {@code CompletableFuture<WebSocket>} which completes
 231          * normally with the {@code WebSocket} when it is connected or completes
 232          * exceptionally if an error occurs.
 233          *
 234          * <p> {@code CompletableFuture} may complete exceptionally with the
 235          * following errors:
 236          * <ul>
 237          * <li> {@link IOException}
 238          *          if an I/O error occurs
 239          * <li> {@link InterruptedException}
 240          *          if the operation was interrupted
 241          * <li> {@link SecurityException}
 242          *          if a security manager is set, and the caller does not
 243          *          have a {@link java.net.URLPermission} for the WebSocket URI
 244          * <li> {@link WebSocketHandshakeException}
 245          *          if the opening handshake fails
 246          * </ul>
 247          *
 248          * @return a {@code CompletableFuture} with the {@code WebSocket}
 249          */
 250         CompletableFuture<WebSocket> buildAsync();
 251     }
 252 
 253     /**
 254      * A listener for events and messages on a {@code WebSocket}.
 255      *
 256      * <p> Each method below corresponds to a type of event.
 257      * <ul>
 258      * <li> {@link #onOpen onOpen} <br>
 259      * This method is always the first to be invoked.
 260      * <li> {@link #onText(WebSocket, CharSequence, WebSocket.MessagePart)
 261      * onText}, {@link #onBinary(WebSocket, ByteBuffer, WebSocket.MessagePart)
 262      * onBinary}, {@link #onPing(WebSocket, ByteBuffer) onPing} and {@link
 263      * #onPong(WebSocket, ByteBuffer) onPong} <br>
 264      * These methods are invoked zero or more times after {@code onOpen}.
 265      * <li> {@link #onClose(WebSocket, Optional, String) onClose}, {@link
 266      * #onError(WebSocket, Throwable) onError} <br>
 267      * Only one of these methods is invoked, and that method is invoked last and
 268      * at most once.
 269      * </ul>
 270      *
 271      * <pre><code>
 272      *     onOpen (onText|onBinary|onPing|onPong)* (onClose|onError)?
 273      * </code></pre>
 274      *
 275      * <p> Messages received by the {@code Listener} conform to the WebSocket
 276      * Protocol, otherwise {@code onError} with a {@link ProtocolException} is
 277      * invoked.
 278      *
 279      * <p> If a whole message is received, then the corresponding method
 280      * ({@code onText} or {@code onBinary}) will be invoked with {@link
 281      * WebSocket.MessagePart#WHOLE WHOLE} marker. Otherwise the method will be
 282      * invoked with {@link WebSocket.MessagePart#FIRST FIRST}, zero or more
 283      * times with {@link WebSocket.MessagePart#FIRST PART} and, finally, with
 284      * {@link WebSocket.MessagePart#LAST LAST} markers.
 285      *
 286      * <pre><code>
 287      *     WHOLE|(FIRST PART* LAST)
 288      * </code></pre>
 289      *
 290      * <p> All methods are invoked in a sequential (and
 291      * <a href="../../../java/util/concurrent/package-summary.html#MemoryVisibility">
 292      * happens-before</a>) order, one after another, possibly by different
 293      * threads. If any of the methods above throws an exception, {@code onError}
 294      * is then invoked with that exception. Exceptions thrown from {@code
 295      * onError} or {@code onClose} are ignored.
 296      *
 297      * <p> When the method returns, the message is deemed received. After this
 298      * another messages may be received.
 299      *
 300      * <p> These invocations begin asynchronous processing which might not end
 301      * with the invocation. To provide coordination, methods of {@code
 302      * Listener} return a {@link CompletionStage CompletionStage}. The {@code
 303      * CompletionStage} signals the {@code WebSocket} that the
 304      * processing of a message has ended. For
 305      * convenience, methods may return {@code null}, which means
 306      * the same as returning an already completed {@code CompletionStage}. If
 307      * the returned {@code CompletionStage} completes exceptionally, then {@link
 308      * #onError(WebSocket, Throwable) onError} will be invoked with the
 309      * exception.
 310      *
 311      * <p> Control of the message passes to the {@code Listener} with the
 312      * invocation of the method. Control of the message returns to the {@code
 313      * WebSocket} at the earliest of, either returning {@code null} from the
 314      * method, or the completion of the {@code CompletionStage} returned from
 315      * the method. The {@code WebSocket} does not access the message while it's
 316      * not in its control. The {@code Listener} must not access the message
 317      * after its control has been returned to the {@code WebSocket}.
 318      *
 319      * <p> It is the responsibility of the listener to make additional
 320      * {@linkplain WebSocket#request(long) message requests}, when ready, so
 321      * that messages are received eventually.
 322      *
 323      * <p> Methods above are never invoked with {@code null}s as their
 324      * arguments.
 325      *
 326      * @since 9
 327      */
 328     interface Listener {
 329 
 330         /**
 331          * Notifies the {@code Listener} that it is connected to the provided
 332          * {@code WebSocket}.
 333          *
 334          * <p> The {@code onOpen} method does not correspond to any message
 335          * from the WebSocket Protocol. It is a synthetic event. It is the first
 336          * {@code Listener}'s method to be invoked. No other {@code Listener}'s
 337          * methods are invoked before this one. The method is usually used to
 338          * make an initial {@linkplain WebSocket#request(long) request} for
 339          * messages.
 340          *
 341          * <p> If an exception is thrown from this method then {@link
 342          * #onError(WebSocket, Throwable) onError} will be invoked with the
 343          * exception.
 344          *
 345          * @implSpec The default implementation {@linkplain WebSocket#request(long)
 346          * requests one message}.
 347          *
 348          * @param webSocket
 349          *         the WebSocket
 350          */
 351         default void onOpen(WebSocket webSocket) { webSocket.request(1); }
 352 
 353         /**
 354          * Receives a Text message.
 355          *
 356          * <p> The {@code onText} method is invoked zero or more times between
 357          * {@code onOpen} and ({@code onClose} or {@code onError}).
 358          *
 359          * <p> This message may be a partial UTF-16 sequence. However, the
 360          * concatenation of all messages through the last will be a whole UTF-16
 361          * sequence.
 362          *
 363          * <p> If an exception is thrown from this method or the returned {@code
 364          * CompletionStage} completes exceptionally, then {@link
 365          * #onError(WebSocket, Throwable) onError} will be invoked with the
 366          * exception.
 367          *
 368          * @implSpec The default implementation {@linkplain WebSocket#request(long)
 369          * requests one more message}.
 370          *
 371          * @implNote This implementation passes only complete UTF-16 sequences
 372          * to the {@code onText} method.
 373          *
 374          * @param webSocket
 375          *         the WebSocket
 376          * @param message
 377          *         the message
 378          * @param part
 379          *         the part
 380          *
 381          * @return a CompletionStage that completes when the message processing
 382          * is done; or {@code null} if already done
 383          */
 384         default CompletionStage<?> onText(WebSocket webSocket,
 385                                           CharSequence message,
 386                                           MessagePart part) {
 387             webSocket.request(1);
 388             return null;
 389         }
 390 
 391         /**
 392          * Receives a Binary message.
 393          *
 394          * <p> The {@code onBinary} method is invoked zero or more times
 395          * between {@code onOpen} and ({@code onClose} or {@code onError}).
 396          *
 397          * <p> If an exception is thrown from this method or the returned {@code
 398          * CompletionStage} completes exceptionally, then {@link
 399          * #onError(WebSocket, Throwable) onError} will be invoked with this
 400          * exception.
 401          *
 402          * @implSpec The default implementation {@linkplain WebSocket#request(long)
 403          * requests one more message}.
 404          *
 405          * @param webSocket
 406          *         the WebSocket
 407          * @param message
 408          *         the message
 409          * @param part
 410          *         the part
 411          *
 412          * @return a CompletionStage that completes when the message processing
 413          * is done; or {@code null} if already done
 414          */
 415         default CompletionStage<?> onBinary(WebSocket webSocket,
 416                                             ByteBuffer message,
 417                                             MessagePart part) {
 418             webSocket.request(1);
 419             return null;
 420         }
 421 
 422         /**
 423          * Receives a Ping message.
 424          *
 425          * <p> A Ping message may be sent or received by either client or
 426          * server. It may serve either as a keepalive or as a means to verify
 427          * that the remote endpoint is still responsive.
 428          *
 429          * <p> The message will consist of not more than {@code 125} bytes:
 430          * {@code message.remaining() <= 125}.
 431          *
 432          * <p> The {@code onPing} is invoked zero or more times in between
 433          * {@code onOpen} and ({@code onClose} or {@code onError}).
 434          *
 435          * <p> If an exception is thrown from this method or the returned {@code
 436          * CompletionStage} completes exceptionally, then {@link
 437          * #onError(WebSocket, Throwable) onError} will be invoked with this
 438          * exception.
 439          *
 440          * @implNote
 441          *
 442          * <p> Replies with a Pong message and requests one more message when
 443          * the Pong has been sent.
 444          *
 445          * @param webSocket
 446          *         the WebSocket
 447          * @param message
 448          *         the message
 449          *
 450          * @return a CompletionStage that completes when the message processing
 451          * is done; or {@code null} if already done
 452          */
 453         default CompletionStage<?> onPing(WebSocket webSocket,
 454                                           ByteBuffer message) {
 455             return webSocket.sendPong(message).thenRun(() -> webSocket.request(1));
 456         }
 457 
 458         /**
 459          * Receives a Pong message.
 460          *
 461          * <p> A Pong message may be unsolicited or may be received in response
 462          * to a previously sent Ping. In the latter case, the contents of the
 463          * Pong is identical to the originating Ping.
 464          *
 465          * <p> The message will consist of not more than {@code 125} bytes:
 466          * {@code message.remaining() <= 125}.
 467          *
 468          * <p> The {@code onPong} method is invoked zero or more times in
 469          * between {@code onOpen} and ({@code onClose} or {@code onError}).
 470          *
 471          * <p> If an exception is thrown from this method or the returned {@code
 472          * CompletionStage} completes exceptionally, then {@link
 473          * #onError(WebSocket, Throwable) onError} will be invoked with this
 474          * exception.
 475          *
 476          * @implSpec The default implementation {@linkplain WebSocket#request(long)
 477          * requests one more message}.
 478          *
 479          * @param webSocket
 480          *         the WebSocket
 481          * @param message
 482          *         the message
 483          *
 484          * @return a CompletionStage that completes when the message processing
 485          * is done; or {@code null} if already done
 486          */
 487         default CompletionStage<?> onPong(WebSocket webSocket,
 488                                           ByteBuffer message) {
 489             webSocket.request(1);
 490             return null;
 491         }
 492 
 493         /**
 494          * Receives a Close message.
 495          *
 496          * <p> Once a Close message is received, the server will not send any
 497          * more messages.
 498          *
 499          * <p> A Close message may consist of a status code and a reason for
 500          * closing. The reason will have a UTF-8 representation not longer than
 501          * {@code 123} bytes. The reason may be useful for debugging or passing
 502          * information relevant to the connection but is not necessarily human
 503          * readable.
 504          *
 505          * <p> {@code onClose} is the last invocation on the {@code Listener}.
 506          * It is invoked at most once, but after {@code onOpen}. If an exception
 507          * is thrown from this method, it is ignored.
 508          *
 509          * @implSpec The default implementation does nothing.
 510          *
 511          * @param webSocket
 512          *         the WebSocket
 513          * @param code
 514          *         an {@code Optional} describing the close code, or
 515          *         an empty {@code Optional} if the message doesn't contain it
 516          * @param reason
 517          *         the reason of close; can be empty
 518          */
 519         default void onClose(WebSocket webSocket, Optional<CloseCode> code,
 520                              String reason) { }
 521 
 522         /**
 523          * Notifies an I/O or protocol error has occurred on the {@code
 524          * WebSocket}.
 525          *
 526          * <p> The {@code onError} method does not correspond to any message
 527          * from the WebSocket Protocol. It is a synthetic event. {@code onError}
 528          * is the last invocation on the {@code Listener}. It is invoked at most
 529          * once but after {@code onOpen}. If an exception is thrown from this
 530          * method, it is ignored.
 531          *
 532          * <p> The WebSocket Protocol requires some errors occurs in the
 533          * incoming destination must be fatal to the connection. In such cases
 534          * the implementation takes care of closing the {@code WebSocket}. By
 535          * the time {@code onError} is invoked, no more messages can be sent on
 536          * this {@code WebSocket}.
 537          *
 538          * @apiNote Errors associated with {@code sendX} methods are reported to
 539          * the {@code CompletableFuture} these methods return.
 540          *
 541          * @implSpec The default implementation does nothing.
 542          *
 543          * @param webSocket
 544          *         the WebSocket
 545          * @param error
 546          *         the error
 547          */
 548         default void onError(WebSocket webSocket, Throwable error) { }
 549     }
 550 
 551     /**
 552      * A marker used by {@link WebSocket.Listener} in cases where a partial
 553      * message may be received.
 554      *
 555      * @since 9
 556      */
 557     enum MessagePart {
 558 
 559         /**
 560          * The first part of a message in a sequence.
 561          */
 562         FIRST,
 563 
 564         /**
 565          * A middle part of a message in a sequence.
 566          */
 567         PART,
 568 
 569         /**
 570          * The last part of a message in a sequence.
 571          */
 572         LAST,
 573 
 574         /**
 575          * A whole message consisting of a single part.
 576          */
 577         WHOLE
 578     }
 579 
 580     /**
 581      * Sends a Text message with characters from the given {@code CharSequence}.
 582      *
 583      * <p> Returns a {@code CompletableFuture<WebSocket>} which completes
 584      * normally when the message has been sent or completes exceptionally if an
 585      * error occurs.
 586      *
 587      * <p> The {@code CharSequence} should not be modified until the returned
 588      * {@code CompletableFuture} completes (either normally or exceptionally).
 589      *
 590      * <p> The returned {@code CompletableFuture} can complete exceptionally
 591      * with:
 592      * <ul>
 593      * <li> {@link IOException}
 594      *          if an I/O error occurs during this operation
 595      * <li> {@link IllegalStateException}
 596      *          if the {@code WebSocket} closes while this operation is in progress;
 597      *          or if a Close message has been sent already;
 598      *          or if there is an outstanding send operation;
 599      *          or if a previous Binary message was not sent with {@code isLast == true}
 600      * </ul>
 601      *
 602      * @implNote This implementation does not accept partial UTF-16
 603      * sequences. In case such a sequence is passed, a returned {@code
 604      * CompletableFuture} completes exceptionally.
 605      *
 606      * @param message
 607      *         the message
 608      * @param isLast
 609      *         {@code true} if this is the last part of the message,
 610      *         {@code false} otherwise
 611      *
 612      * @return a CompletableFuture with this WebSocket
 613      *
 614      * @throws IllegalArgumentException
 615      *         if {@code message} is a malformed (or an incomplete) UTF-16 sequence
 616      */
 617     CompletableFuture<WebSocket> sendText(CharSequence message, boolean isLast);
 618 
 619     /**
 620      * Sends a whole Text message with characters from the given {@code
 621      * CharSequence}.
 622      *
 623      * <p> This is a convenience method. For the general case, use {@link
 624      * #sendText(CharSequence, boolean)}.
 625      *
 626      * <p> Returns a {@code CompletableFuture<WebSocket>} which completes
 627      * normally when the message has been sent or completes exceptionally if an
 628      * error occurs.
 629      *
 630      * <p> The {@code CharSequence} should not be modified until the returned
 631      * {@code CompletableFuture} completes (either normally or exceptionally).
 632      *
 633      * <p> The returned {@code CompletableFuture} can complete exceptionally
 634      * with:
 635      * <ul>
 636      * <li> {@link IOException}
 637      *          if an I/O error occurs during this operation
 638      * <li> {@link IllegalStateException}
 639      *          if the {@code WebSocket} closes while this operation is in progress;
 640      *          or if a Close message has been sent already;
 641      *          or if there is an outstanding send operation;
 642      *          or if a previous Binary message was not sent with {@code isLast == true}
 643      * </ul>
 644      *
 645      * @param message
 646      *         the message
 647      *
 648      * @return a CompletableFuture with this WebSocket
 649      *
 650      * @throws IllegalArgumentException
 651      *         if {@code message} is a malformed (or an incomplete) UTF-16 sequence
 652      */
 653     default CompletableFuture<WebSocket> sendText(CharSequence message) {
 654         return sendText(message, true);
 655     }
 656 
 657     /**
 658      * Sends a Binary message with bytes from the given {@code ByteBuffer}.
 659      *
 660      * <p> Returns a {@code CompletableFuture<WebSocket>} which completes
 661      * normally when the message has been sent or completes exceptionally if an
 662      * error occurs.
 663      *
 664      * <p> The returned {@code CompletableFuture} can complete exceptionally
 665      * with:
 666      * <ul>
 667      * <li> {@link IOException}
 668      *          if an I/O error occurs during this operation
 669      * <li> {@link IllegalStateException}
 670      *          if the {@code WebSocket} closes while this operation is in progress;
 671      *          or if a Close message has been sent already;
 672      *          or if there is an outstanding send operation;
 673      *          or if a previous Text message was not sent with {@code isLast == true}
 674      * </ul>
 675      *
 676      * @param message
 677      *         the message
 678      * @param isLast
 679      *         {@code true} if this is the last part of the message,
 680      *         {@code false} otherwise
 681      *
 682      * @return a CompletableFuture with this WebSocket
 683      */
 684     CompletableFuture<WebSocket> sendBinary(ByteBuffer message, boolean isLast);
 685 
 686     /**
 687      * Sends a Ping message.
 688      *
 689      * <p> Returns a {@code CompletableFuture<WebSocket>} which completes
 690      * normally when the message has been sent or completes exceptionally if an
 691      * error occurs.
 692      *
 693      * <p> A Ping message may be sent or received by either client or server.
 694      * It may serve either as a keepalive or as a means to verify that the
 695      * remote endpoint is still responsive.
 696      *
 697      * <p> The message must consist of not more than {@code 125} bytes: {@code
 698      * message.remaining() <= 125}.
 699      *
 700      * <p> The returned {@code CompletableFuture} can complete exceptionally
 701      * with:
 702      * <ul>
 703      * <li> {@link IOException}
 704      *          if an I/O error occurs during this operation
 705      * <li> {@link IllegalStateException}
 706      *          if the {@code WebSocket} closes while this operation is in progress;
 707      *          or if a Close message has been sent already;
 708      *          or if there is an outstanding send operation
 709      * </ul>
 710      *
 711      * @param message
 712      *         the message
 713      *
 714      * @return a CompletableFuture with this WebSocket
 715      *
 716      * @throws IllegalArgumentException
 717      *         if {@code message.remaining() > 125}
 718      */
 719     CompletableFuture<WebSocket> sendPing(ByteBuffer message);
 720 
 721     /**
 722      * Sends a Pong message.
 723      *
 724      * <p> Returns a {@code CompletableFuture<WebSocket>} which completes
 725      * normally when the message has been sent or completes exceptionally if an
 726      * error occurs.
 727      *
 728      * <p> A Pong message may be unsolicited or may be sent in response to a
 729      * previously received Ping. In latter case the contents of the Pong is
 730      * identical to the originating Ping.
 731      *
 732      * <p> The message must consist of not more than {@code 125} bytes: {@code
 733      * message.remaining() <= 125}.
 734      *
 735      * <p> The returned {@code CompletableFuture} can complete exceptionally
 736      * with:
 737      * <ul>
 738      * <li> {@link IOException}
 739      *          if an I/O error occurs during this operation
 740      * <li> {@link IllegalStateException}
 741      *          if the {@code WebSocket} closes while this operation is in progress;
 742      *          or if a Close message has been sent already;
 743      *          or if there is an outstanding send operation
 744      * </ul>
 745      *
 746      * @param message
 747      *         the message
 748      *
 749      * @return a CompletableFuture with this WebSocket
 750      *
 751      * @throws IllegalArgumentException
 752      *         if {@code message.remaining() > 125}
 753      */
 754     CompletableFuture<WebSocket> sendPong(ByteBuffer message);
 755 
 756     /**
 757      * Sends a Close message with the given close code and the reason.
 758      *
 759      * <p> Returns a {@code CompletableFuture<WebSocket>} which completes
 760      * normally when the message has been sent or completes exceptionally if an
 761      * error occurs.
 762      *
 763      * <p> A Close message may consist of a status code and a reason for
 764      * closing. The reason must have a UTF-8 representation not longer than
 765      * {@code 123} bytes. The reason may be useful for debugging or passing
 766      * information relevant to the connection but is not necessarily human
 767      * readable.
 768      *
 769      * <p> The returned {@code CompletableFuture} can complete exceptionally
 770      * with:
 771      * <ul>
 772      * <li> {@link IOException}
 773      *          if an I/O error occurs during this operation
 774      * <li> {@link IllegalStateException}
 775      *          if the {@code WebSocket} closes while this operation is in progress;
 776      *          or if a Close message has been sent already;
 777      *          or if there is an outstanding send operation
 778      * </ul>
 779      *
 780      * @param code
 781      *         the close code
 782      * @param reason
 783      *         the reason; can be empty
 784      *
 785      * @return a CompletableFuture with this WebSocket
 786      *
 787      * @throws IllegalArgumentException
 788      *         if {@code reason} doesn't have an UTF-8 representation not longer
 789      *         than {@code 123} bytes
 790      */
 791     CompletableFuture<WebSocket> sendClose(CloseCode code, CharSequence reason);
 792 
 793     /**
 794      * Sends an empty Close message.
 795      *
 796      * <p> Returns a {@code CompletableFuture<WebSocket>} which completes
 797      * normally when the message has been sent or completes exceptionally if an
 798      * error occurs.
 799      *
 800      * <p> The returned {@code CompletableFuture} can complete exceptionally
 801      * with:
 802      * <ul>
 803      * <li> {@link IOException}
 804      *          if an I/O error occurs during this operation
 805      * <li> {@link IllegalStateException}
 806      *          if the {@code WebSocket} closes while this operation is in progress;
 807      *          or if a Close message has been sent already;
 808      *          or if there is an outstanding send operation
 809      * </ul>
 810      *
 811      * @return a CompletableFuture with this WebSocket
 812      */
 813     CompletableFuture<WebSocket> sendClose();
 814 
 815     /**
 816      * Allows {@code n} more messages to be received by the {@link Listener
 817      * Listener}.
 818      *
 819      * <p> The actual number of received messages might be fewer if a Close
 820      * message is received, the connection closes or an error occurs.
 821      *
 822      * <p> A {@code WebSocket} that has just been created, hasn't requested
 823      * anything yet. Usually the initial request for messages is done in {@link
 824      * Listener#onOpen(java.net.http.WebSocket) Listener.onOpen}.
 825      *
 826      * @implNote This implementation does not distinguish between partial and
 827      * whole messages, because it's not known beforehand how a message will be
 828      * received.
 829      *
 830      * <p> If a server sends more messages than requested, this implementation
 831      * queues up these messages on the TCP connection and may eventually force
 832      * the sender to stop sending through TCP flow control.
 833      *
 834      * @param n
 835      *         the number of messages
 836      *
 837      * @throws IllegalArgumentException
 838      *         if {@code n < 0}
 839      */
 840     void request(long n);
 841 
 842     /**
 843      * Returns a {@linkplain Builder#subprotocols(String, String...) subprotocol}
 844      * in use.
 845      *
 846      * @return a subprotocol, or {@code null} if there is none
 847      */
 848     String getSubprotocol();
 849 
 850     /**
 851      * Tells whether the {@code WebSocket} is closed.
 852      *
 853      * <p> A {@code WebSocket} deemed closed when either the underlying socket
 854      * is closed or the closing handshake is completed.
 855      *
 856      * @return {@code true} if the {@code WebSocket} is closed,
 857      *         {@code false} otherwise
 858      */
 859     boolean isClosed();
 860 
 861     /**
 862      * Closes the {@code WebSocket} abruptly.
 863      *
 864      * <p> This method closes the underlying TCP connection. If the {@code
 865      * WebSocket} is already closed then invoking this method has no effect.
 866      *
 867      * @throws IOException
 868      *         if an I/O error occurs
 869      */
 870     void abort() throws IOException;
 871 
 872     /**
 873      * A {@code WebSocket} close status code.
 874      *
 875      * <p> Some codes <a href="https://tools.ietf.org/html/rfc6455#section-7.4">
 876      * specified</a> in the WebSocket Protocol are defined as named constants
 877      * here. Others can be {@linkplain #of(int) retrieved on demand}.
 878      *
 879      * <p> This is a
 880      * <a href="../../lang/doc-files/ValueBased.html">value-based</a> class;
 881      * use of identity-sensitive operations (including reference equality
 882      * ({@code ==}), identity hash code, or synchronization) on instances of
 883      * {@code CloseCode} may have unpredictable results and should be avoided.
 884      *
 885      * @since 9
 886      */
 887     final class CloseCode {
 888 
 889         /**
 890          * Indicates a normal close, meaning that the purpose for which the
 891          * connection was established has been fulfilled.
 892          *
 893          * <p> Numerical representation: {@code 1000}
 894          */
 895         public static final CloseCode NORMAL_CLOSURE
 896                 = new CloseCode(1000, "NORMAL_CLOSURE");
 897 
 898         /**
 899          * Indicates that an endpoint is "going away", such as a server going
 900          * down or a browser having navigated away from a page.
 901          *
 902          * <p> Numerical representation: {@code 1001}
 903          */
 904         public static final CloseCode GOING_AWAY
 905                 = new CloseCode(1001, "GOING_AWAY");
 906 
 907         /**
 908          * Indicates that an endpoint is terminating the connection due to a
 909          * protocol error.
 910          *
 911          * <p> Numerical representation: {@code 1002}
 912          */
 913         public static final CloseCode PROTOCOL_ERROR
 914                 = new CloseCode(1002, "PROTOCOL_ERROR");
 915 
 916         /**
 917          * Indicates that an endpoint is terminating the connection because it
 918          * has received a type of data it cannot accept (e.g., an endpoint that
 919          * understands only text data MAY send this if it receives a binary
 920          * message).
 921          *
 922          * <p> Numerical representation: {@code 1003}
 923          */
 924         public static final CloseCode CANNOT_ACCEPT
 925                 = new CloseCode(1003, "CANNOT_ACCEPT");
 926 
 927         /**
 928          * Indicates that an endpoint is terminating the connection because it
 929          * has received data within a message that was not consistent with the
 930          * type of the message (e.g., non-UTF-8 [RFC3629] data within a text
 931          * message).
 932          *
 933          * <p> Numerical representation: {@code 1007}
 934          */
 935         public static final CloseCode NOT_CONSISTENT
 936                 = new CloseCode(1007, "NOT_CONSISTENT");
 937 
 938         /**
 939          * Indicates that an endpoint is terminating the connection because it
 940          * has received a message that violates its policy. This is a generic
 941          * status code that can be returned when there is no other more suitable
 942          * status code (e.g., {@link #CANNOT_ACCEPT} or {@link #TOO_BIG}) or if
 943          * there is a need to hide specific details about the policy.
 944          *
 945          * <p> Numerical representation: {@code 1008}
 946          */
 947         public static final CloseCode VIOLATED_POLICY
 948                 = new CloseCode(1008, "VIOLATED_POLICY");
 949 
 950         /**
 951          * Indicates that an endpoint is terminating the connection because it
 952          * has received a message that is too big for it to process.
 953          *
 954          * <p> Numerical representation: {@code 1009}
 955          */
 956         public static final CloseCode TOO_BIG
 957                 = new CloseCode(1009, "TOO_BIG");
 958 
 959         /**
 960          * Indicates that an endpoint is terminating the connection because it
 961          * encountered an unexpected condition that prevented it from fulfilling
 962          * the request.
 963          *
 964          * <p> Numerical representation: {@code 1011}
 965          */
 966         public static final CloseCode UNEXPECTED_CONDITION
 967                 = new CloseCode(1011, "UNEXPECTED_CONDITION");
 968 
 969         private static final Map<Integer, CloseCode> cached = Map.ofEntries(
 970                 entry(NORMAL_CLOSURE),
 971                 entry(GOING_AWAY),
 972                 entry(PROTOCOL_ERROR),
 973                 entry(CANNOT_ACCEPT),
 974                 entry(NOT_CONSISTENT),
 975                 entry(VIOLATED_POLICY),
 976                 entry(TOO_BIG),
 977                 entry(UNEXPECTED_CONDITION)
 978         );
 979 
 980         /**
 981          * Returns a {@code CloseCode} from its numerical representation.
 982          *
 983          * <p> The given {@code code} should be in the range {@code 1000 <= code
 984          * <= 4999}, and should not be equal to any of the following codes:
 985          * {@code 1004}, {@code 1005}, {@code 1006} and {@code 1015}.
 986          *
 987          * @param code
 988          *         numerical representation
 989          *
 990          * @return a close code corresponding to the provided numerical value
 991          *
 992          * @throws IllegalArgumentException
 993          *         if {@code code} violates any of the requirements above
 994          */
 995         public static CloseCode of(int code) {
 996             if (code < 1000 || code > 4999) {
 997                 throw new IllegalArgumentException("Out of range: " + code);
 998             }
 999             if (code == 1004 || code == 1005 || code == 1006 || code == 1015) {
1000                 throw new IllegalArgumentException("Reserved: " + code);
1001             }
1002             CloseCode closeCode = cached.get(code);
1003             return closeCode != null ? closeCode : new CloseCode(code, "");
1004         }
1005 
1006         private final int code;
1007         private final String description;
1008 
1009         private CloseCode(int code, String description) {
1010             assert description != null;
1011             this.code = code;
1012             this.description = description;
1013         }
1014 
1015         /**
1016          * Returns a numerical representation of this close code.
1017          *
1018          * @return a numerical representation
1019          */
1020         public int getCode() {
1021             return code;
1022         }
1023 
1024         /**
1025          * Compares this close code to the specified object.
1026          *
1027          * @param o
1028          *         the object to compare this {@code CloseCode} against
1029          *
1030          * @return {@code true} iff the argument is a close code with the same
1031          * {@linkplain #getCode() numerical representation} as this one
1032          */
1033         @Override
1034         public boolean equals(Object o) {
1035             if (this == o) {
1036                 return true;
1037             }
1038             if (!(o instanceof CloseCode)) {
1039                 return false;
1040             }
1041             CloseCode that = (CloseCode) o;
1042             return code == that.code;
1043         }
1044 
1045         @Override
1046         public int hashCode() {
1047             return code;
1048         }
1049 
1050         /**
1051          * Returns a human-readable representation of this close code.
1052          *
1053          * @apiNote The representation is not designed to be parsed; the format
1054          * may change unexpectedly.
1055          *
1056          * @return a string representation
1057          */
1058         @Override
1059         public String toString() {
1060             return code + (description.isEmpty() ? "" : (": " + description));
1061         }
1062 
1063         private static Map.Entry<Integer, CloseCode> entry(CloseCode cc) {
1064             return Map.entry(cc.getCode(), cc);
1065         }
1066     }
1067 }