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