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