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